From e7817f3a20774c4a38117f350515ab7227f1b675 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Arno=20T=C3=B6ll?= Date: Sat, 9 Jun 2012 16:48:23 +0000 Subject: [PATCH] Import trafficserver_3.0.5.orig.tar.bz2 [dgit import orig trafficserver_3.0.5.orig.tar.bz2] --- .gitignore | 102 + .indent.pro | 29 + CHANGES | 1090 + INSTALL | 72 + LAYOUT | 32 + LICENSE | 427 + Makefile.am | 83 + Makefile.in | 977 + NOTICE | 26 + README | 229 + README-EC2 | 134 + README.libev | 73 + REVIEWERS | 107 + STATUS | 64 + aclocal.m4 | 998 + build/aux/config.guess | 1501 + build/aux/config.sub | 1705 ++ build/aux/depcomp | 630 + build/aux/install-sh | 520 + build/aux/ltmain.sh | 9636 ++++++ build/aux/missing | 376 + build/aux/ylwrap | 222 + build/common.m4 | 580 + build/crypto.m4 | 111 + build/libtool.m4 | 7835 +++++ build/ltoptions.m4 | 369 + build/ltsugar.m4 | 123 + build/ltversion.m4 | 23 + build/lt~obsolete.m4 | 98 + build/lzma.m4 | 100 + build/network.m4 | 114 + build/pcre.m4 | 104 + build/tcl.m4 | 3302 +++ build/xml.m4 | 111 + build/zlib.m4 | 100 + ci/README | 6 + ci/rat-excludes.txt | 108 + config.layout | 211 + configure | 24565 ++++++++++++++++ configure.ac | 1276 + contrib/install_trafficserver.sh | 401 + contrib/perl/AdminClient/Changes | 12 + contrib/perl/AdminClient/MANIFEST | 6 + contrib/perl/AdminClient/Makefile.PL | 28 + contrib/perl/AdminClient/README | 48 + .../AdminClient/lib/Apache/TS/AdminClient.pm | 765 + .../AdminClient/t/Apache-TS-AdminClient.t | 35 + .../perl/ConfigMgmt/examples/forward_proxy.pl | 41 + .../perl/ConfigMgmt/lib/Apache/TS/Config.pm | 37 + .../lib/Apache/TS/Config/Records.pm | 216 + contrib/set_trafficserver.sh | 100 + cop/Makefile.am | 37 + cop/Makefile.in | 742 + cop/TrafficCop.cc | 1950 ++ doc/Doxyfile.in | 1274 + doc/Makefile.am | 23 + doc/Makefile.in | 577 + doc/doap.rdf | 64 + doc/dot/ResponseDiag.dot | 70 + doc/dot/SimpleStateDiag.dot | 65 + doc/dot/SimpleStateDiagAPI.dot | 86 + doc/mainpage.doc | 16 + doc/man/Makefile.am | 81 + doc/man/config_alarms.1 | 52 + doc/man/config_cache.1 | 140 + doc/man/config_clock.1 | 64 + doc/man/config_dns.1 | 46 + doc/man/config_get.1 | 37 + doc/man/config_hard-restart.1 | 31 + doc/man/config_hostdb.1 | 72 + doc/man/config_http.1 | 78 + doc/man/config_icp.1 | 72 + doc/man/config_logging.1 | 160 + doc/man/config_name.1 | 36 + doc/man/config_network.1 | 75 + doc/man/config_parent.1 | 53 + doc/man/config_port-tunnels.1 | 35 + doc/man/config_remap.1 | 35 + doc/man/config_reset-stats.1 | 46 + doc/man/config_restart.1 | 33 + doc/man/config_root.1 | 34 + doc/man/config_scheduled-update.1 | 84 + doc/man/config_security.1 | 52 + doc/man/config_set.1 | 36 + doc/man/config_socks.1 | 60 + doc/man/config_ssl.1 | 43 + doc/man/config_start.1 | 32 + doc/man/config_stop.1 | 31 + doc/man/config_upgrade.1 | 52 + doc/man/config_virtual-ip.1 | 52 + doc/man/disable.1 | 33 + doc/man/enable.1 | 42 + doc/man/exit.1 | 34 + doc/man/man_page_template.txt | 67 + doc/man/show_alarms.1 | 33 + doc/man/show_cache-stats.1 | 60 + doc/man/show_cache.1 | 70 + doc/man/show_cluster.1 | 35 + doc/man/show_dns-resolver.1 | 37 + doc/man/show_dns-stats.1 | 34 + doc/man/show_hostdb-stats.1 | 35 + doc/man/show_hostdb.1 | 40 + doc/man/show_http-stats.1 | 43 + doc/man/show_http-trans-stats.1 | 55 + doc/man/show_http.1 | 45 + doc/man/show_icp-stats.1 | 46 + doc/man/show_icp.1 | 73 + doc/man/show_logging-stats.1 | 39 + doc/man/show_logging.1 | 69 + doc/man/show_network.1 | 51 + doc/man/show_parent.1 | 50 + doc/man/show_port-tunnels.1 | 37 + doc/man/show_proxy-stats.1 | 42 + doc/man/show_proxy.1 | 32 + doc/man/show_remap.1 | 36 + doc/man/show_scheduled-update.1 | 53 + doc/man/show_security.1 | 37 + doc/man/show_socks.1 | 47 + doc/man/show_ssl.1 | 33 + doc/man/show_status.1 | 33 + doc/man/show_version.1 | 33 + doc/man/show_virtual-ip.1 | 35 + doc/man/traffic_shell.1 | 127 + emacs-style | 31 + example/Makefile.am | 21 + example/Makefile.in | 774 + example/add-header/Makefile.am | 25 + example/add-header/Makefile.in | 737 + example/add-header/add-header.c | 228 + example/add-header/readme.txt | 50 + example/app-template/Makefile.am | 63 + example/app-template/Makefile.in | 824 + example/app-template/app-template.cc | 262 + example/app-template/app-template.h | 48 + example/app-template/records.config.in | 73 + example/append-transform/Makefile.am | 25 + example/append-transform/Makefile.in | 737 + example/append-transform/append-transform.c | 414 + example/append-transform/readme.txt | 89 + example/basic-auth/Makefile.am | 25 + example/basic-auth/Makefile.in | 737 + example/basic-auth/basic-auth.c | 315 + example/basic-auth/readme.txt | 58 + example/blacklist-0/Makefile.am | 25 + example/blacklist-0/Makefile.in | 737 + example/blacklist-0/blacklist-0.c | 206 + example/blacklist-1/Makefile.am | 25 + example/blacklist-1/Makefile.in | 737 + example/blacklist-1/blacklist-1.c | 371 + example/blacklist-1/blacklist.txt | 2 + example/blacklist-1/readme.txt | 17 + example/bnull-transform/Makefile.am | 25 + example/bnull-transform/Makefile.in | 737 + example/bnull-transform/bnull-transform.c | 362 + example/cache_scan/Makefile.am | 25 + example/cache_scan/Makefile.in | 737 + example/cache_scan/cache_scan.cc | 496 + example/file-1/Makefile.am | 25 + example/file-1/Makefile.in | 737 + example/file-1/file-1.c | 99 + example/file-1/readme.txt | 36 + example/gzip-transform/Makefile.am | 29 + example/gzip-transform/Makefile.in | 749 + example/gzip-transform/README.txt | 12 + example/gzip-transform/gunzip.c | 545 + example/gzip-transform/gzip.c | 631 + example/hello/Makefile.am | 25 + example/hello/Makefile.in | 737 + example/hello/hello.c | 71 + example/include_other/macro.h | 75 + example/null-transform/Makefile.am | 25 + example/null-transform/Makefile.in | 737 + example/null-transform/null-transform.c | 362 + example/null-transform/readme.txt | 112 + example/output-header/Makefile.am | 25 + example/output-header/Makefile.in | 737 + example/output-header/output-header.c | 208 + example/output-header/readme | 5 + example/prefetch/Makefile.am | 25 + example/prefetch/Makefile.in | 737 + example/prefetch/prefetch-plugin-eg1.c | 90 + example/prefetch/readme.txt | 26 + example/prefetch/test-hns-plugin.c | 253 + example/protocol/Makefile.am | 25 + example/protocol/Makefile.in | 738 + example/protocol/Protocol.c | 180 + example/protocol/Protocol.h | 47 + example/protocol/README.txt | 52 + example/protocol/TxnSM.c | 969 + example/protocol/TxnSM.h | 85 + example/protocol/test/ProtocolClientTest.java | 198 + example/protocol/test/ProtocolServerTest.java | 181 + example/protocol/test/file_gen.sh | 25 + example/query_remap/Makefile.am | 25 + example/query_remap/Makefile.in | 737 + example/query_remap/query_remap.c | 187 + example/redirect-1/Makefile.am | 25 + example/redirect-1/Makefile.in | 737 + example/redirect-1/readme.txt | 10 + example/redirect-1/redirect-1.c | 436 + example/remap/Makefile.am | 25 + example/remap/Makefile.in | 737 + example/remap/build.txt | 17 + example/remap/remap.cc | 376 + example/replace-header/Makefile.am | 25 + example/replace-header/Makefile.in | 737 + example/replace-header/replace-header.c | 137 + example/response-header-1/Makefile.am | 25 + example/response-header-1/Makefile.in | 737 + example/response-header-1/response-header-1.c | 333 + example/server-transform/Makefile.am | 25 + example/server-transform/Makefile.in | 737 + example/server-transform/server-transform.c | 691 + example/session-1/Makefile.am | 25 + example/session-1/Makefile.in | 737 + example/session-1/session-1.c | 144 + example/thread-1/Makefile.am | 25 + example/thread-1/Makefile.in | 737 + example/thread-1/readme.txt | 20 + example/thread-1/thread-1.c | 111 + example/thread-pool/Makefile.am | 25 + example/thread-pool/Makefile.in | 738 + example/thread-pool/README.txt | 133 + example/thread-pool/TESTPLAN.txt | 74 + example/thread-pool/include/Makefile.am | 25 + example/thread-pool/include/gen.c | 40 + example/thread-pool/include/gen_inc.sh | 43 + example/thread-pool/psi.c | 1077 + .../test/SDKTest/SDKtest_server.config | 15 + example/thread-pool/test/SDKTest/psi_server.c | 195 + .../thread-pool/test/SynTest/Tests/Psi/1.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/10.cfg | 51 + .../thread-pool/test/SynTest/Tests/Psi/11.cfg | 49 + .../thread-pool/test/SynTest/Tests/Psi/12.cfg | 45 + .../thread-pool/test/SynTest/Tests/Psi/13.cfg | 51 + .../thread-pool/test/SynTest/Tests/Psi/2.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/3.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/4.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/5.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/6.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/7.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/8.cfg | 50 + .../thread-pool/test/SynTest/Tests/Psi/9.cfg | 50 + .../SynTest/Tests/Psi/psi_files/tc10_file.txt | 3 + .../SynTest/Tests/Psi/psi_files/tc11_file.txt | 2 + .../SynTest/Tests/Psi/psi_files/tc12_file.txt | 3 + .../SynTest/Tests/Psi/psi_files/tc13_file.txt | 3 + .../SynTest/Tests/Psi/psi_files/tc1_file.txt | 2 + .../SynTest/Tests/Psi/psi_files/tc2_file.txt | 1 + .../SynTest/Tests/Psi/psi_files/tc3_file.txt | 2 + .../SynTest/Tests/Psi/psi_files/tc4_file.txt | 5 + .../SynTest/Tests/Psi/psi_files/tc5_file.txt | 3 + .../SynTest/Tests/Psi/psi_files/tc6_file.txt | 1 + .../SynTest/Tests/Psi/psi_files/tc7_file.txt | 3 + .../SynTest/Tests/Psi/psi_files/tc8_file.txt | 3 + .../SynTest/Tests/Psi/psi_files/tc9_file.txt | 2 + example/thread-pool/test/SynTest/system.cfg | 44 + .../thread-pool/test/SynTest/tests_psi.cfg | 61 + example/thread-pool/thread.c | 189 + example/thread-pool/thread.h | 89 + iocore/Makefile.am | 24 + iocore/Makefile.in | 772 + iocore/aio/AIO.cc | 534 + iocore/aio/I_AIO.h | 86 + iocore/aio/Inline.cc | 31 + iocore/aio/Makefile.am | 28 + iocore/aio/Makefile.in | 696 + iocore/aio/NTAIO.cc | 168 + iocore/aio/P_AIO.h | 133 + iocore/aio/sample.cfg | 17 + iocore/aio/test_AIO.i | 527 + iocore/aio/test_I_AIO.cc | 25 + iocore/aio/test_P_AIO.cc | 25 + iocore/cache/Cache.cc | 2825 ++ iocore/cache/CacheDir.cc | 1448 + iocore/cache/CacheDisk.cc | 422 + iocore/cache/CacheHosting.cc | 1224 + iocore/cache/CacheHttp.cc | 355 + iocore/cache/CacheLink.cc | 170 + iocore/cache/CachePages.cc | 629 + iocore/cache/CachePagesInternal.cc | 344 + iocore/cache/CacheRead.cc | 1127 + iocore/cache/CacheTest.cc | 418 + iocore/cache/CacheVol.cc | 509 + iocore/cache/CacheWrite.cc | 1825 ++ iocore/cache/I_Cache.h | 187 + iocore/cache/I_CacheDefs.h | 131 + iocore/cache/I_Store.h | 189 + iocore/cache/Inline.cc | 33 + iocore/cache/Makefile.am | 75 + iocore/cache/Makefile.in | 768 + iocore/cache/Notes | 17 + iocore/cache/P_Cache.h | 53 + iocore/cache/P_CacheArray.h | 186 + iocore/cache/P_CacheDir.h | 359 + iocore/cache/P_CacheDisk.h | 133 + iocore/cache/P_CacheHosting.h | 197 + iocore/cache/P_CacheHttp.h | 99 + iocore/cache/P_CacheInternal.h | 1337 + iocore/cache/P_CacheTest.h | 132 + iocore/cache/P_CacheVol.h | 533 + iocore/cache/P_RamCache.h | 44 + iocore/cache/RamCacheCLFUS.cc | 649 + iocore/cache/RamCacheLRU.cc | 197 + iocore/cache/Store.cc | 1167 + iocore/cluster/ClusterAPI.cc | 589 + iocore/cluster/ClusterCache.cc | 3215 ++ iocore/cluster/ClusterConfig.cc | 497 + iocore/cluster/ClusterHandler.cc | 3111 ++ iocore/cluster/ClusterHandlerBase.cc | 1418 + iocore/cluster/ClusterHash.cc | 177 + iocore/cluster/ClusterLib.cc | 488 + iocore/cluster/ClusterLoadMonitor.cc | 322 + iocore/cluster/ClusterMachine.cc | 271 + iocore/cluster/ClusterProcessor.cc | 825 + iocore/cluster/ClusterRPC.cc | 386 + iocore/cluster/ClusterVConnection.cc | 629 + iocore/cluster/Inline.cc | 31 + iocore/cluster/Makefile.am | 57 + iocore/cluster/Makefile.in | 743 + iocore/cluster/P_Cluster.h | 144 + iocore/cluster/P_ClusterCache.h | 1170 + iocore/cluster/P_ClusterCacheInternal.h | 836 + iocore/cluster/P_ClusterHandler.h | 666 + iocore/cluster/P_ClusterInline.h | 411 + iocore/cluster/P_ClusterInternal.h | 523 + iocore/cluster/P_ClusterLib.h | 72 + iocore/cluster/P_ClusterLoadMonitor.h | 118 + iocore/cluster/P_ClusterMachine.h | 131 + iocore/cluster/P_TimeTrace.h | 83 + iocore/cluster/test_I_Cluster.cc | 147 + iocore/cluster/test_P_Cluster.cc | 147 + iocore/dns/DNS.cc | 1585 + iocore/dns/DNSConnection.cc | 161 + iocore/dns/I_DNS.h | 44 + iocore/dns/I_DNSProcessor.h | 140 + iocore/dns/I_SplitDNS.h | 43 + iocore/dns/I_SplitDNSProcessor.h | 59 + iocore/dns/Inline.cc | 33 + iocore/dns/Makefile.am | 55 + iocore/dns/Makefile.in | 726 + iocore/dns/P_DNS.h | 47 + iocore/dns/P_DNSConnection.h | 80 + iocore/dns/P_DNSProcessor.h | 311 + iocore/dns/P_SplitDNS.h | 48 + iocore/dns/P_SplitDNSProcessor.h | 343 + iocore/dns/SRV.cc | 166 + iocore/dns/SRV.h | 157 + iocore/dns/SplitDNS.cc | 709 + iocore/dns/test_I_DNS.cc | 138 + iocore/dns/test_P_DNS.cc | 83 + iocore/eventsystem/EventSystem.cc | 47 + iocore/eventsystem/IOBuffer.cc | 271 + iocore/eventsystem/I_Action.h | 213 + iocore/eventsystem/I_Continuation.h | 200 + iocore/eventsystem/I_EThread.h | 373 + iocore/eventsystem/I_Event.h | 283 + iocore/eventsystem/I_EventProcessor.h | 315 + iocore/eventsystem/I_EventSystem.h | 61 + iocore/eventsystem/I_IOBuffer.h | 1370 + iocore/eventsystem/I_Lock.h | 828 + iocore/eventsystem/I_PriorityEventQueue.h | 126 + iocore/eventsystem/I_Processor.h | 115 + iocore/eventsystem/I_ProtectedQueue.h | 60 + iocore/eventsystem/I_ProxyAllocator.h | 102 + iocore/eventsystem/I_SocketManager.h | 136 + iocore/eventsystem/I_Tasks.h | 40 + iocore/eventsystem/I_Thread.h | 142 + iocore/eventsystem/I_VConnection.h | 413 + iocore/eventsystem/I_VIO.h | 220 + iocore/eventsystem/Inline.cc | 32 + iocore/eventsystem/Lock.cc | 112 + iocore/eventsystem/Makefile.am | 67 + iocore/eventsystem/Makefile.in | 752 + iocore/eventsystem/PQ-List.cc | 63 + iocore/eventsystem/P_EventSystem.h | 87 + iocore/eventsystem/P_Freer.h | 128 + iocore/eventsystem/P_IOBuffer.h | 1191 + iocore/eventsystem/P_ProtectedQueue.h | 96 + iocore/eventsystem/P_Thread.h | 69 + iocore/eventsystem/P_UnixEThread.h | 182 + iocore/eventsystem/P_UnixEvent.h | 58 + iocore/eventsystem/P_UnixEventProcessor.h | 155 + iocore/eventsystem/P_UnixSocketManager.h | 582 + iocore/eventsystem/P_VConnection.h | 138 + iocore/eventsystem/P_VIO.h | 139 + iocore/eventsystem/Processor.cc | 91 + iocore/eventsystem/ProtectedQueue.cc | 169 + iocore/eventsystem/SocketManager.cc | 138 + iocore/eventsystem/Tasks.cc | 36 + iocore/eventsystem/Thread.cc | 107 + iocore/eventsystem/UnixEThread.cc | 298 + iocore/eventsystem/UnixEvent.cc | 103 + iocore/eventsystem/UnixEventProcessor.cc | 122 + iocore/eventsystem/test_Buffer.cc | 160 + iocore/eventsystem/test_Event.i | 174 + iocore/eventsystem/test_I_Buffer.cc | 25 + iocore/eventsystem/test_I_Event.cc | 25 + iocore/eventsystem/test_P_Buffer.cc | 25 + iocore/eventsystem/test_P_Event.cc | 25 + iocore/hostdb/HostDB.cc | 2333 ++ iocore/hostdb/I_HostDB.h | 52 + iocore/hostdb/I_HostDBProcessor.h | 490 + iocore/hostdb/Inline.cc | 33 + iocore/hostdb/Makefile.am | 50 + iocore/hostdb/Makefile.in | 717 + iocore/hostdb/MultiCache.cc | 1503 + iocore/hostdb/P_HostDB.h | 66 + iocore/hostdb/P_HostDBProcessor.h | 398 + iocore/hostdb/P_MultiCache.h | 692 + iocore/hostdb/include/Machine.h | 146 + iocore/hostdb/test_I_HostDB.cc | 148 + iocore/hostdb/test_P_HostDB.cc | 83 + iocore/net/Connection.cc | 361 + iocore/net/I_Net.h | 101 + iocore/net/I_NetConfig.h | 64 + iocore/net/I_NetProcessor.h | 317 + iocore/net/I_NetVConnection.h | 492 + iocore/net/I_Socks.h | 84 + iocore/net/I_UDPConnection.h | 113 + iocore/net/I_UDPNet.h | 132 + iocore/net/I_UDPPacket.h | 113 + iocore/net/Inline.cc | 32 + iocore/net/Makefile.am | 97 + iocore/net/Makefile.in | 766 + iocore/net/Net.cc | 144 + iocore/net/NetConfig.cc | 105 + iocore/net/NetTest-http-server.c | 196 + iocore/net/NetTest-simple-proxy.c | 312 + iocore/net/NetVCTest.cc | 425 + iocore/net/NetVConnection.cc | 46 + iocore/net/P_CompletionUtil.h | 49 + iocore/net/P_Connection.h | 195 + iocore/net/P_InkBulkIO.h | 186 + iocore/net/P_LibBulkIO.h | 178 + iocore/net/P_Net.h | 138 + iocore/net/P_NetAccept.h | 131 + iocore/net/P_NetVCTest.h | 152 + iocore/net/P_NetVConnection.h | 103 + iocore/net/P_SSLCertLookup.h | 51 + iocore/net/P_SSLConfig.h | 198 + iocore/net/P_SSLNetAccept.h | 71 + iocore/net/P_SSLNetProcessor.h | 121 + iocore/net/P_SSLNetVConnection.h | 175 + iocore/net/P_Socks.h | 168 + iocore/net/P_UDPConnection.h | 196 + iocore/net/P_UDPIOEvent.h | 95 + iocore/net/P_UDPNet.h | 465 + iocore/net/P_UDPPacket.h | 307 + iocore/net/P_UnixCompletionUtil.h | 108 + iocore/net/P_UnixNet.h | 720 + iocore/net/P_UnixNetProcessor.h | 100 + iocore/net/P_UnixNetState.h | 61 + iocore/net/P_UnixNetVConnection.h | 354 + iocore/net/P_UnixPollDescriptor.h | 158 + iocore/net/P_UnixUDPConnection.h | 123 + iocore/net/SSLCertLookup.cc | 247 + iocore/net/SSLConfig.cc | 404 + iocore/net/SSLNet.cc | 521 + iocore/net/SSLNetVConnection.cc | 646 + iocore/net/SSLUnixNet.cc | 166 + iocore/net/Socks.cc | 699 + iocore/net/UDPIOEvent.cc | 25 + iocore/net/UnixConnection.cc | 354 + iocore/net/UnixNet.cc | 438 + iocore/net/UnixNetAccept.cc | 576 + iocore/net/UnixNetPages.cc | 247 + iocore/net/UnixNetProcessor.cc | 523 + iocore/net/UnixNetVConnection.cc | 1129 + iocore/net/UnixUDPConnection.cc | 157 + iocore/net/UnixUDPNet.cc | 1417 + iocore/net/test_I_Net.cc | 183 + iocore/net/test_I_UDPNet.cc | 214 + iocore/net/test_I_simple_proxy.cc | 294 + iocore/net/test_P_Net.cc | 112 + iocore/net/test_P_UDPNet.cc | 214 + iocore/utils/I_Machine.h | 75 + iocore/utils/I_OneWayMultiTunnel.h | 154 + iocore/utils/I_OneWayTunnel.h | 223 + iocore/utils/Machine.cc | 136 + iocore/utils/Makefile.am | 34 + iocore/utils/Makefile.in | 705 + iocore/utils/OneWayMultiTunnel.cc | 256 + iocore/utils/OneWayTunnel.cc | 384 + iocore/utils/diags.i | 121 + lib/Makefile.am | 24 + lib/Makefile.in | 774 + lib/records/I_RecAlarms.h | 58 + lib/records/I_RecCore.h | 248 + lib/records/I_RecDefs.h | 184 + lib/records/I_RecEvents.h | 39 + lib/records/I_RecLocal.h | 37 + lib/records/I_RecMutex.h | 46 + lib/records/I_RecProcess.h | 159 + lib/records/I_RecSignals.h | 56 + lib/records/Makefile.am | 82 + lib/records/Makefile.in | 980 + lib/records/P_RecCompatibility.h | 68 + lib/records/P_RecCore.h | 104 + lib/records/P_RecCore.i | 1078 + lib/records/P_RecDefs.h | 178 + lib/records/P_RecLocal.h | 29 + lib/records/P_RecMessage.h | 53 + lib/records/P_RecProcess.h | 44 + lib/records/P_RecTree.h | 93 + lib/records/P_RecUtils.h | 68 + lib/records/RecCompatibility.cc | 329 + lib/records/RecCore.cc | 1136 + lib/records/RecLocal.cc | 196 + lib/records/RecMessage.cc | 572 + lib/records/RecMutex.cc | 65 + lib/records/RecProcess.cc | 771 + lib/records/RecTree.cc | 279 + lib/records/RecUtils.cc | 266 + lib/records/test_I_RecLocal.cc | 286 + lib/records/test_I_RecProcess.cc | 25 + lib/records/test_P_RecProcess.cc | 25 + lib/records/test_RecProcess.i | 687 + lib/records/test_RecTree.cc | 81 + lib/records/test_RecordsConfig.cc | 60 + lib/records/test_RecordsConfig.h | 28 + lib/records/test_records.config | 20 + lib/ts/Allocator.cc | 43 + lib/ts/Allocator.h | 331 + lib/ts/Arena.cc | 160 + lib/ts/Arena.h | 182 + lib/ts/Bitops.cc | 63 + lib/ts/Bitops.h | 275 + lib/ts/Compatability.h | 76 + lib/ts/CompileParseRules.cc | 147 + lib/ts/DAllocator.cc | 253 + lib/ts/DAllocator.h | 102 + lib/ts/Diags.cc | 569 + lib/ts/Diags.h | 446 + lib/ts/DynArray.h | 195 + lib/ts/HostLookup.cc | 1330 + lib/ts/HostLookup.h | 128 + lib/ts/INK_MD5.h | 164 + lib/ts/I_Layout.h | 107 + lib/ts/I_Version.h | 100 + lib/ts/InkErrno.h | 72 + lib/ts/InkPool.h | 96 + lib/ts/Layout.cc | 236 + lib/ts/List.h | 497 + lib/ts/MMH.cc | 577 + lib/ts/MMH.h | 146 + lib/ts/Makefile.am | 189 + lib/ts/Makefile.in | 1201 + lib/ts/Map.h | 937 + lib/ts/MatcherUtils.cc | 587 + lib/ts/MatcherUtils.h | 99 + lib/ts/MimeTable.cc | 211 + lib/ts/MimeTable.h | 75 + lib/ts/ParseRules.cc | 178 + lib/ts/ParseRules.h | 1021 + lib/ts/Ptr.h | 417 + lib/ts/RawHashTable.cc | 33 + lib/ts/RawHashTable.h | 400 + lib/ts/Regex.cc | 146 + lib/ts/Regex.h | 67 + lib/ts/Regression.cc | 209 + lib/ts/Regression.h | 111 + lib/ts/Resource.cc | 66 + lib/ts/Resource.h | 63 + lib/ts/SimpleTokenizer.h | 293 + lib/ts/TestHttpHeader.cc | 216 + lib/ts/TextBuffer.cc | 218 + lib/ts/TextBuffer.h | 61 + lib/ts/Tokenizer.cc | 372 + lib/ts/Tokenizer.h | 163 + lib/ts/Vec.cc | 203 + lib/ts/Vec.h | 816 + lib/ts/Version.cc | 110 + lib/ts/defalloc.h | 32 + lib/ts/fastlz.c | 551 + lib/ts/fastlz.h | 100 + lib/ts/ink_aiocb.h | 63 + lib/ts/ink_align.h | 82 + lib/ts/ink_apidefs.h | 32 + lib/ts/ink_args.cc | 254 + lib/ts/ink_args.h | 77 + lib/ts/ink_assert.cc | 47 + lib/ts/ink_assert.h | 74 + lib/ts/ink_atomic.h | 167 + lib/ts/ink_auth_api.cc | 82 + lib/ts/ink_auth_api.h | 228 + lib/ts/ink_autoconf.h.in | 269 + lib/ts/ink_base64.cc | 306 + lib/ts/ink_base64.h | 49 + lib/ts/ink_bool.h | 75 + lib/ts/ink_cap.cc | 88 + lib/ts/ink_cap.h | 39 + lib/ts/ink_code.cc | 135 + lib/ts/ink_code.h | 44 + lib/ts/ink_config.h.in | 194 + lib/ts/ink_defs.cc | 107 + lib/ts/ink_defs.h | 94 + lib/ts/ink_error.cc | 258 + lib/ts/ink_error.h | 64 + lib/ts/ink_exception.h | 71 + lib/ts/ink_file.cc | 341 + lib/ts/ink_file.h | 82 + lib/ts/ink_hash_table.cc | 461 + lib/ts/ink_hash_table.h | 149 + lib/ts/ink_hrtime.cc | 223 + lib/ts/ink_hrtime.h | 331 + lib/ts/ink_inet.cc | 196 + lib/ts/ink_inet.h | 272 + lib/ts/ink_inout.h | 73 + lib/ts/ink_isolatin_table.cc | 579 + lib/ts/ink_isolatin_table.h | 51 + lib/ts/ink_killall.cc | 151 + lib/ts/ink_killall.h | 63 + lib/ts/ink_llqueue.h | 65 + lib/ts/ink_lockfile.h | 117 + lib/ts/ink_memory.cc | 283 + lib/ts/ink_memory.h | 67 + lib/ts/ink_mutex.cc | 81 + lib/ts/ink_mutex.h | 129 + lib/ts/ink_platform.h | 218 + lib/ts/ink_port.h | 96 + lib/ts/ink_queue.cc | 687 + lib/ts/ink_queue.h | 262 + lib/ts/ink_queue_utils.cc | 81 + lib/ts/ink_rand.cc | 109 + lib/ts/ink_rand.h | 88 + lib/ts/ink_res_init.cc | 653 + lib/ts/ink_res_mkquery.cc | 503 + lib/ts/ink_resolver.h | 254 + lib/ts/ink_resource.cc | 775 + lib/ts/ink_resource.h | 205 + lib/ts/ink_rwlock.cc | 167 + lib/ts/ink_rwlock.h | 55 + lib/ts/ink_sock.cc | 256 + lib/ts/ink_sock.h | 66 + lib/ts/ink_sprintf.cc | 153 + lib/ts/ink_sprintf.h | 47 + lib/ts/ink_stack_trace.cc | 70 + lib/ts/ink_stack_trace.h | 40 + lib/ts/ink_string++.cc | 195 + lib/ts/ink_string++.h | 335 + lib/ts/ink_string.cc | 532 + lib/ts/ink_string.h | 780 + lib/ts/ink_sys_control.cc | 65 + lib/ts/ink_sys_control.h | 40 + lib/ts/ink_syslog.cc | 88 + lib/ts/ink_syslog.h | 37 + lib/ts/ink_thread.cc | 40 + lib/ts/ink_thread.h | 327 + lib/ts/ink_time.cc | 831 + lib/ts/ink_time.h | 165 + lib/ts/ink_unused.h | 81 + lib/ts/libts.h | 113 + lib/ts/llqueue.cc | 295 + lib/ts/load_http_hdr.cc | 436 + lib/ts/lockfile.cc | 311 + lib/ts/mkdfa.c | 665 + lib/ts/test_List.cc | 59 + lib/ts/test_Map.cc | 112 + lib/ts/test_Vec.cc | 97 + lib/ts/test_arena.cc | 126 + lib/ts/test_atomic.cc | 237 + lib/ts/test_freelist.cc | 90 + lib/ts/test_memchr.cc | 171 + lib/ts/test_strings.cc | 378 + lib/tsconfig/BisonHeaderToC++.sed | 6 + lib/tsconfig/Errata.cc | 297 + lib/tsconfig/Errata.h | 945 + lib/tsconfig/IntrusivePtr.h | 609 + lib/tsconfig/Makefile.am | 55 + lib/tsconfig/Makefile.in | 843 + lib/tsconfig/NumericType.h | 182 + lib/tsconfig/TsBuffer.h | 200 + lib/tsconfig/TsBuilder.cc | 214 + lib/tsconfig/TsBuilder.h | 101 + lib/tsconfig/TsConfigGrammar.y | 118 + lib/tsconfig/TsConfigLexer.h | 61 + lib/tsconfig/TsConfigParseEvents.h | 67 + lib/tsconfig/TsConfigSyntax.l | 124 + lib/tsconfig/TsConfigTypes.h | 66 + lib/tsconfig/TsErrataUtil.cc | 170 + lib/tsconfig/TsErrataUtil.h | 169 + lib/tsconfig/TsValue.cc | 364 + lib/tsconfig/TsValue.h | 739 + lib/tsconfig/test-1.tsconfig | 18 + lib/tsconfig/test-tsconfig.cc | 49 + lib/wccp/Makefile.am | 39 + lib/wccp/Makefile.in | 714 + lib/wccp/Wccp.h | 512 + lib/wccp/WccpConfig.cc | 792 + lib/wccp/WccpEndPoint.cc | 1218 + lib/wccp/WccpLocal.h | 3577 +++ lib/wccp/WccpMeta.h | 203 + lib/wccp/WccpMsg.cc | 1783 ++ lib/wccp/WccpStatic.cc | 175 + lib/wccp/WccpUtil.h | 223 + lib/wccp/wccp-test-cache.cc | 196 + lib/wccp/wccp-test-router.cc | 157 + mgmt/AddConfigFilesHere.cc | 91 + mgmt/Alarms.cc | 716 + mgmt/Alarms.h | 160 + mgmt/BaseManager.cc | 171 + mgmt/BaseManager.h | 149 + mgmt/FileManager.cc | 923 + mgmt/FileManager.h | 152 + mgmt/LocalManager.cc | 1356 + mgmt/LocalManager.h | 194 + mgmt/Main.cc | 1330 + mgmt/Main.h | 63 + mgmt/Makefile.am | 112 + mgmt/Makefile.in | 1062 + mgmt/MgmtDefs.h | 108 + mgmt/MultiFile.cc | 286 + mgmt/MultiFile.h | 77 + mgmt/ProcessManager.cc | 408 + mgmt/ProcessManager.h | 120 + mgmt/RecordsConfig.cc | 1992 ++ mgmt/RecordsConfig.h | 55 + mgmt/Rollback.cc | 1133 + mgmt/Rollback.h | 217 + mgmt/api/CfgContextDefs.h | 74 + mgmt/api/CfgContextImpl.cc | 2586 ++ mgmt/api/CfgContextImpl.h | 560 + mgmt/api/CfgContextManager.cc | 623 + mgmt/api/CfgContextManager.h | 77 + mgmt/api/CfgContextUtils.cc | 2886 ++ mgmt/api/CfgContextUtils.h | 202 + mgmt/api/CoreAPI.cc | 938 + mgmt/api/CoreAPI.h | 109 + mgmt/api/CoreAPIShared.cc | 527 + mgmt/api/CoreAPIShared.h | 88 + mgmt/api/EventCallback.cc | 361 + mgmt/api/EventCallback.h | 85 + mgmt/api/EventControlMain.cc | 515 + mgmt/api/EventControlMain.h | 63 + mgmt/api/GenericParser.cc | 1084 + mgmt/api/GenericParser.h | 307 + mgmt/api/INKMgmtAPI.cc | 2769 ++ mgmt/api/INKMgmtAPIStub.cc | 808 + mgmt/api/Makefile.am | 60 + mgmt/api/Makefile.in | 896 + mgmt/api/NetworkUtilsDefs.h | 85 + mgmt/api/NetworkUtilsLocal.cc | 794 + mgmt/api/NetworkUtilsLocal.h | 81 + mgmt/api/TSControlMain.cc | 1095 + mgmt/api/TSControlMain.h | 76 + mgmt/api/include/Makefile.am | 22 + mgmt/api/include/Makefile.in | 669 + mgmt/api/include/mgmtapi.h | 1467 + mgmt/api/remote/APITestCliRemote.cc | 2490 ++ mgmt/api/remote/CoreAPIRemote.cc | 856 + mgmt/api/remote/EventRegistration.cc | 169 + mgmt/api/remote/EventRegistration.h | 52 + mgmt/api/remote/Makefile.am | 58 + mgmt/api/remote/Makefile.in | 856 + mgmt/api/remote/NetworkUtilsRemote.cc | 1802 ++ mgmt/api/remote/NetworkUtilsRemote.h | 109 + mgmt/cli/CliCreateCommands.cc | 267 + mgmt/cli/CliCreateCommands.h | 39 + mgmt/cli/CliDisplay.cc | 230 + mgmt/cli/CliDisplay.h | 91 + mgmt/cli/CliMgmtUtils.cc | 634 + mgmt/cli/CliMgmtUtils.h | 164 + mgmt/cli/ConfigCmd.cc | 5029 ++++ mgmt/cli/ConfigCmd.h | 886 + mgmt/cli/ConfigUpgradeCmd.cc | 634 + mgmt/cli/ConfigUpgradeCmd.h | 252 + mgmt/cli/ConfigUpgradeReadCmd.cc | 504 + mgmt/cli/ConfigUpgradeWriteCmd.cc | 523 + mgmt/cli/Makefile.am | 89 + mgmt/cli/Makefile.in | 857 + mgmt/cli/ShowCmd.cc | 2483 ++ mgmt/cli/ShowCmd.h | 253 + mgmt/cli/TrafficLine.cc | 198 + mgmt/cli/UtilCmds.cc | 196 + mgmt/cli/UtilCmds.h | 94 + mgmt/cli/cliAppInit.cc | 126 + mgmt/cli/cliMain.cc | 113 + mgmt/cli/cliParseArg.cc | 463 + mgmt/cli/cli_detailed_command_list.txt | 1624 + mgmt/cli/cli_feature_spec.txt | 230 + mgmt/cli/commandOptions.h | 47 + mgmt/cli/createArgument.cc | 398 + mgmt/cli/createArgument.h | 119 + mgmt/cli/createCommand.cc | 166 + mgmt/cli/createCommand.h | 59 + mgmt/cli/definitions.h | 80 + mgmt/cli/hashtable.cc | 219 + mgmt/cli/hashtable.h | 45 + mgmt/cli/processArgument.cc | 57 + mgmt/cli/script_configs.sh | 115 + mgmt/cluster/ClusterCom.cc | 2505 ++ mgmt/cluster/ClusterCom.h | 186 + mgmt/cluster/Makefile.am | 37 + mgmt/cluster/Makefile.in | 706 + mgmt/cluster/VMap.cc | 1208 + mgmt/cluster/VMap.h | 194 + mgmt/preparse/IPRange.cc | 210 + mgmt/preparse/IPRange.h | 69 + mgmt/preparse/Makefile.am | 30 + mgmt/preparse/Makefile.in | 702 + mgmt/preparse/RemapReadConfig.cc | 182 + mgmt/preparse/SocksParser.cc | 25 + mgmt/preparse/StoreReadConfig.cc | 79 + mgmt/stats/Makefile.am | 41 + mgmt/stats/Makefile.in | 712 + mgmt/stats/StatProcessor.cc | 320 + mgmt/stats/StatProcessor.h | 83 + mgmt/stats/StatType.cc | 1130 + mgmt/stats/StatType.h | 253 + mgmt/stats/StatXML.cc | 82 + mgmt/stats/StatXML.h | 47 + mgmt/stats/spec | 218 + mgmt/tools/ConfigAPI.cc | 1336 + mgmt/tools/ConfigAPI.h | 93 + mgmt/tools/Makefile.am | 37 + mgmt/tools/Makefile.in | 714 + mgmt/tools/SysAPI.cc | 2869 ++ mgmt/tools/SysAPI.h | 85 + mgmt/utils/EnvBlock.cc | 119 + mgmt/utils/EnvBlock.h | 55 + mgmt/utils/ExpandingArray.cc | 84 + mgmt/utils/ExpandingArray.h | 64 + mgmt/utils/IpLookup.cc | 451 + mgmt/utils/IpLookup.h | 86 + mgmt/utils/Makefile.am | 65 + mgmt/utils/Makefile.in | 887 + mgmt/utils/MgmtHashTable.h | 171 + mgmt/utils/MgmtSchema.cc | 339 + mgmt/utils/MgmtSchema.h | 59 + mgmt/utils/MgmtSocket.h | 199 + mgmt/utils/MgmtUtils.cc | 805 + mgmt/utils/MgmtUtils.h | 77 + mgmt/utils/WebMgmtUtils.cc | 1533 + mgmt/utils/WebMgmtUtils.h | 127 + mgmt/utils/XmlUtils.cc | 622 + mgmt/utils/XmlUtils.h | 153 + mgmt/web2/Makefile.am | 53 + mgmt/web2/Makefile.in | 732 + mgmt/web2/WebCompatibility.cc | 234 + mgmt/web2/WebCompatibility.h | 98 + mgmt/web2/WebGlobals.h | 145 + mgmt/web2/WebHttp.cc | 710 + mgmt/web2/WebHttp.h | 45 + mgmt/web2/WebHttpContext.cc | 109 + mgmt/web2/WebHttpContext.h | 69 + mgmt/web2/WebHttpMessage.cc | 604 + mgmt/web2/WebHttpMessage.h | 288 + mgmt/web2/WebHttpSession.cc | 220 + mgmt/web2/WebHttpSession.h | 46 + mgmt/web2/WebIntrMain.cc | 628 + mgmt/web2/WebIntrMain.h | 42 + mgmt/web2/WebOverview.cc | 1592 + mgmt/web2/WebOverview.h | 182 + mgmt/web2/WebUtils.cc | 132 + mgmt/web2/WebUtils.h | 53 + plugins/Makefile.am | 17 + plugins/Makefile.in | 769 + plugins/conf_remap/Makefile.am | 22 + plugins/conf_remap/Makefile.in | 734 + plugins/conf_remap/conf_remap.cc | 274 + proxy/AbstractBuffer.cc | 303 + proxy/AbstractBuffer.h | 184 + proxy/CacheControl.cc | 513 + proxy/CacheControl.h | 156 + proxy/ClassH.txt | 97 + proxy/CompletionUtil.h | 47 + proxy/ConfigParse.h | 41 + proxy/ControlBase.cc | 613 + proxy/ControlBase.h | 111 + proxy/ControlMatcher.cc | 900 + proxy/ControlMatcher.h | 301 + proxy/CoreUtils.cc | 1395 + proxy/CoreUtils.h | 266 + proxy/DebugStreamLevels.txt | 4 + proxy/DiagsConfig.cc | 426 + proxy/DiagsConfig.h | 44 + proxy/DynamicStats.h | 117 + proxy/Error.cc | 114 + proxy/Error.h | 173 + proxy/EventName.cc | 114 + proxy/EventName.h | 36 + proxy/FetchSM.cc | 215 + proxy/FetchSM.h | 112 + proxy/Freer.h | 136 + proxy/HttpTransStats.h | 26 + proxy/ICP.cc | 2528 ++ proxy/ICP.h | 1299 + proxy/ICPConfig.cc | 1507 + proxy/ICPProcessor.cc | 61 + proxy/ICPProcessor.h | 80 + proxy/ICPStats.cc | 127 + proxy/ICPevents.h | 43 + proxy/ICPlog.h | 71 + proxy/IPAllow.cc | 273 + proxy/IPAllow.h | 97 + proxy/Initialize.cc | 285 + proxy/Initialize.h | 57 + proxy/InkAPI-ensure-funcs-present.pl | 49 + proxy/InkAPI.cc | 7877 +++++ proxy/InkAPIInternal.h | 211 + proxy/InkAPITest.cc | 7642 +++++ proxy/InkAPITestTool.cc | 1019 + proxy/InkIOCoreAPI.cc | 806 + proxy/InkPool_r.h | 71 + proxy/InkXml.cc | 492 + proxy/InkXml.h | 231 + proxy/Main.cc | 2015 ++ proxy/Main.h | 144 + proxy/Makefile.am | 299 + proxy/Makefile.in | 1255 + proxy/MuxVC.cc | 3066 ++ proxy/MuxVC.h | 382 + proxy/ParentSelection.cc | 1335 + proxy/ParentSelection.h | 240 + proxy/Plugin.cc | 385 + proxy/Plugin.h | 62 + proxy/PluginDB.cc | 205 + proxy/PluginDB.h | 65 + proxy/PluginVC.cc | 1265 + proxy/PluginVC.h | 233 + proxy/Prefetch.cc | 2205 ++ proxy/Prefetch.h | 453 + proxy/ProtoSM.h | 150 + proxy/ProxyConfig.cc | 204 + proxy/ProxyConfig.h | 84 + proxy/README-stats.otl | 615 + proxy/RegressionSM.cc | 259 + proxy/RegressionSM.h | 80 + proxy/ReverseProxy.cc | 241 + proxy/ReverseProxy.h | 72 + proxy/Show.h | 141 + proxy/SimpleHttp.cc | 890 + proxy/Socks.h | 197 + proxy/SocksProxy.cc | 574 + proxy/StatPages.cc | 273 + proxy/StatPages.h | 137 + proxy/StatSystem.cc | 835 + proxy/StatSystem.h | 682 + proxy/Stuffer.cc | 744 + proxy/Stuffer.h | 253 + proxy/StufferUdpReceiver.cc | 341 + proxy/TestClock.cc | 47 + proxy/TestClusterHash.cc | 122 + proxy/TestDNS.cc | 259 + proxy/TestHook.cc | 504 + proxy/TestPreProc.cc | 190 + proxy/TestPreProc.h | 51 + proxy/TestProxy.cc | 432 + proxy/TestRegex.cc | 31 + proxy/TestSimpleProxy.cc | 161 + proxy/TimeTrace.h | 85 + proxy/Transform.cc | 1218 + proxy/Transform.h | 62 + proxy/TransformInternal.h | 179 + proxy/UDPAPIClientTest.cc | 116 + proxy/UDPAPIClientTest.h | 28 + proxy/UDPAPITest.cc | 131 + proxy/UDPAPITest.h | 28 + proxy/UglyLogStubs.cc | 176 + proxy/UnixCompletionUtil.h | 104 + proxy/Update.cc | 2676 ++ proxy/Update.h | 527 + proxy/UserNameCacheTest.h | 25 + proxy/api/ts/InkAPIHughes.h | 126 + proxy/api/ts/InkAPIPrivateIOCore.h | 248 + proxy/api/ts/Makefile.am | 28 + proxy/api/ts/Makefile.in | 677 + proxy/api/ts/TsException.h | 61 + proxy/api/ts/experimental.h | 465 + proxy/api/ts/remap.h | 133 + proxy/api/ts/ts.h.in | 2972 ++ proxy/config/Makefile.am | 57 + proxy/config/Makefile.in | 885 + proxy/config/ae_ua.config.default | 23 + proxy/config/body_factory/Makefile.am | 20 + proxy/config/body_factory/Makefile.in | 772 + .../body_factory/default/.body_factory_info | 16 + proxy/config/body_factory/default/Makefile.am | 48 + proxy/config/body_factory/default/Makefile.in | 646 + proxy/config/body_factory/default/README | 17 + .../config/body_factory/default/access#denied | 14 + .../default/access#proxy_auth_required | 14 + .../body_factory/default/access#redirect_url | 15 + .../body_factory/default/access#ssl_forbidden | 15 + .../body_factory/default/cache#not_in_cache | 16 + .../body_factory/default/cache#read_error | 14 + .../default/congestion#retryAfter | 15 + .../body_factory/default/connect#dns_failed | 17 + .../default/connect#failed_connect | 14 + .../body_factory/default/connect#hangup | 15 + proxy/config/body_factory/default/default | 14 + .../body_factory/default/interception#no_host | 17 + .../default/redirect#moved_temporarily | 14 + .../default/request#cycle_detected | 16 + .../default/request#no_content_length | 15 + .../body_factory/default/request#no_host | 17 + .../default/request#scheme_unsupported | 15 + .../body_factory/default/request#syntax_error | 14 + .../default/response#bad_response | 14 + .../body_factory/default/response#bad_version | 15 + .../body_factory/default/timeout#activity | 14 + .../body_factory/default/timeout#inactivity | 14 + .../default/transcoding#unsupported | 16 + .../default/urlrouting#no_mapping | 15 + proxy/config/cache.config.default | 45 + proxy/config/cluster.config.default | 26 + proxy/config/congestion.config.default | 56 + proxy/config/hosting.config.default | 27 + proxy/config/icp.config.default | 29 + proxy/config/ip_allow.config.default | 9 + proxy/config/log_hosts.config.default | 11 + proxy/config/logs_xml.config.default | 372 + proxy/config/mgr.cnf.default | 9 + proxy/config/parent.config.default | 52 + proxy/config/plugin.config.default | 11 + proxy/config/plugin.db.default | 9 + proxy/config/prefetch.config.default | 58 + proxy/config/public_key.der | Bin 0 -> 436 bytes proxy/config/records.config.default.in | 593 + proxy/config/remap.config.default | 125 + proxy/config/socks.config.default | 49 + proxy/config/splitdns.config.default | 58 + proxy/config/ssl_multicert.config.default | 12 + proxy/config/stats.config.dtd | 14 + proxy/config/stats.config.xml.default | 1711 ++ proxy/config/storage.config.default.in | 91 + proxy/config/throttle_error.html.example | 32 + proxy/config/update.config.default | 43 + proxy/config/vaddrs.config.default | 22 + proxy/config/volume.config.default | 30 + proxy/config/winnt_intr.config.default | 17 + proxy/congest/Congestion.cc | 793 + proxy/congest/Congestion.h | 484 + proxy/congest/CongestionDB.cc | 645 + proxy/congest/CongestionDB.h | 115 + proxy/congest/CongestionStats.cc | 52 + proxy/congest/CongestionStats.h | 51 + proxy/congest/CongestionTest.cc | 549 + proxy/congest/FeatureSpec.txt | 428 + proxy/congest/MT_hashtable.h | 404 + proxy/congest/Makefile.am | 42 + proxy/congest/Makefile.in | 713 + proxy/example_alarm_bin.sh | 71 + proxy/example_prep.sh | 32 + proxy/hdrs/HTTP.cc | 1938 ++ proxy/hdrs/HTTP.h | 1427 + proxy/hdrs/HdrHeap.cc | 1257 + proxy/hdrs/HdrHeap.h | 480 + proxy/hdrs/HdrTSOnly.cc | 199 + proxy/hdrs/HdrTest.cc | 2218 ++ proxy/hdrs/HdrTest.h | 83 + proxy/hdrs/HdrToken.cc | 743 + proxy/hdrs/HdrToken.h | 393 + proxy/hdrs/HdrUtils.cc | 181 + proxy/hdrs/HdrUtils.h | 183 + proxy/hdrs/HttpCompat.cc | 871 + proxy/hdrs/HttpCompat.h | 97 + proxy/hdrs/MIME.cc | 4084 +++ proxy/hdrs/MIME.h | 1608 + proxy/hdrs/Makefile.am | 58 + proxy/hdrs/Makefile.in | 741 + proxy/hdrs/URL.cc | 1873 ++ proxy/hdrs/URL.h | 729 + proxy/hdrs/load_http_hdr.cc | 341 + proxy/hdrs/test_header.cc | 1055 + proxy/hdrs/test_urlhash.cc | 91 + proxy/http/HttpAccept.cc | 85 + proxy/http/HttpAccept.h | 67 + proxy/http/HttpBodyFactory.cc | 1051 + proxy/http/HttpBodyFactory.h | 245 + proxy/http/HttpCacheSM.cc | 322 + proxy/http/HttpCacheSM.h | 176 + proxy/http/HttpClientSession.cc | 618 + proxy/http/HttpClientSession.h | 162 + proxy/http/HttpConfig.cc | 2027 ++ proxy/http/HttpConfig.h | 1011 + proxy/http/HttpConnectionCount.cc | 28 + proxy/http/HttpConnectionCount.h | 78 + proxy/http/HttpDebugNames.cc | 495 + proxy/http/HttpDebugNames.h | 41 + proxy/http/HttpMessageBody.cc | 130 + proxy/http/HttpMessageBody.h | 60 + proxy/http/HttpPages.cc | 493 + proxy/http/HttpPages.h | 94 + proxy/http/HttpProxyServerMain.cc | 373 + proxy/http/HttpProxyServerMain.h | 34 + proxy/http/HttpSM.cc | 6963 +++++ proxy/http/HttpSM.h | 613 + proxy/http/HttpServerSession.cc | 188 + proxy/http/HttpServerSession.h | 177 + proxy/http/HttpSessionManager.cc | 327 + proxy/http/HttpSessionManager.h | 86 + proxy/http/HttpTransact.cc | 8915 ++++++ proxy/http/HttpTransact.h | 1490 + proxy/http/HttpTransactCache.cc | 1565 + proxy/http/HttpTransactCache.h | 143 + proxy/http/HttpTransactHeaders.cc | 1380 + proxy/http/HttpTransactHeaders.h | 161 + proxy/http/HttpTunnel.cc | 1562 + proxy/http/HttpTunnel.h | 424 + proxy/http/HttpUpdateSM.cc | 236 + proxy/http/HttpUpdateSM.h | 84 + proxy/http/HttpUpdateTester.cc | 122 + proxy/http/Makefile.am | 74 + proxy/http/Makefile.in | 911 + proxy/http/README.via | 85 + proxy/http/TestHttpTransact.cc | 113 + proxy/http/TestUrl.cc | 119 + proxy/http/remap/AclFiltering.cc | 182 + proxy/http/remap/AclFiltering.h | 92 + proxy/http/remap/Makefile.am | 48 + proxy/http/remap/Makefile.in | 730 + proxy/http/remap/RemapPluginInfo.cc | 98 + proxy/http/remap/RemapPluginInfo.h | 95 + proxy/http/remap/RemapPlugins.cc | 344 + proxy/http/remap/RemapPlugins.h | 75 + proxy/http/remap/RemapProcessor.cc | 344 + proxy/http/remap/RemapProcessor.h | 72 + proxy/http/remap/StringHash.cc | 204 + proxy/http/remap/StringHash.h | 79 + proxy/http/remap/Trie.h | 243 + proxy/http/remap/UrlMapping.cc | 235 + proxy/http/remap/UrlMapping.h | 185 + proxy/http/remap/UrlMappingPathIndex.cc | 92 + proxy/http/remap/UrlMappingPathIndex.h | 89 + proxy/http/remap/UrlRewrite.cc | 2072 ++ proxy/http/remap/UrlRewrite.h | 212 + proxy/http/stats.memo | 247 + proxy/http/test_http_client.pl | 347 + proxy/http/test_proxy.pl | 326 + proxy/http/test_socket_close.cc | 646 + proxy/http/testheaders.cc | 131 + proxy/ink_icon.ico | Bin 0 -> 3774 bytes proxy/issues.txt | 252 + proxy/logcat.cc | 358 + proxy/logging/Log.cc | 1349 + proxy/logging/Log.h | 430 + proxy/logging/LogAccess.cc | 1322 + proxy/logging/LogAccess.h | 344 + proxy/logging/LogAccessHttp.cc | 1120 + proxy/logging/LogAccessHttp.h | 161 + proxy/logging/LogAccessICP.cc | 287 + proxy/logging/LogAccessICP.h | 94 + proxy/logging/LogAccessTest.cc | 401 + proxy/logging/LogAccessTest.h | 106 + proxy/logging/LogBuffer.cc | 1148 + proxy/logging/LogBuffer.h | 431 + proxy/logging/LogBufferSink.h | 44 + proxy/logging/LogCollationAccept.cc | 107 + proxy/logging/LogCollationAccept.h | 47 + proxy/logging/LogCollationBase.h | 52 + proxy/logging/LogCollationClientSM.cc | 755 + proxy/logging/LogCollationClientSM.h | 128 + proxy/logging/LogCollationHostSM.cc | 532 + proxy/logging/LogCollationHostSM.h | 117 + proxy/logging/LogConfig.cc | 2260 ++ proxy/logging/LogConfig.h | 330 + proxy/logging/LogConfigCollation.cc | 264 + proxy/logging/LogField.cc | 527 + proxy/logging/LogField.h | 204 + proxy/logging/LogFieldAliasMap.cc | 79 + proxy/logging/LogFieldAliasMap.h | 281 + proxy/logging/LogFile.cc | 971 + proxy/logging/LogFile.h | 238 + proxy/logging/LogFilter.cc | 688 + proxy/logging/LogFilter.h | 303 + proxy/logging/LogFormat.cc | 823 + proxy/logging/LogFormat.h | 145 + proxy/logging/LogFormatType.h | 52 + proxy/logging/LogHost.cc | 424 + proxy/logging/LogHost.h | 128 + proxy/logging/LogLimits.h | 42 + proxy/logging/LogObject.cc | 1296 + proxy/logging/LogObject.h | 557 + proxy/logging/LogSock.cc | 783 + proxy/logging/LogSock.h | 140 + proxy/logging/LogStandalone.cc | 281 + proxy/logging/LogUtils.cc | 768 + proxy/logging/LogUtils.h | 73 + proxy/logging/Makefile.am | 79 + proxy/logging/Makefile.in | 780 + proxy/logstats.cc | 2528 ++ proxy/mime.types | 100 + proxy/msgs/TSMessages.mc | 83 + proxy/msgs/TSMsgs.rc | 39 + proxy/regression.pl | 166 + proxy/sac.cc | 151 + proxy/signals.cc | 419 + proxy/signals.h | 53 + proxy/stats/CoupledStats.cc | 70 + proxy/stats/CoupledStats.h | 211 + proxy/stats/Makefile.am | 32 + proxy/stats/Makefile.in | 704 + proxy/stats/Stats.cc | 296 + proxy/stats/Stats.h | 207 + proxy/test_xml_parser.cc | 42 + proxy/ts_resource.h | 39 + rc/Makefile.am | 28 + rc/Makefile.in | 650 + rc/solaris.txt | 12 + rc/start_traffic_shell | 55 + rc/trafficserver.conf.in | 34 + rc/trafficserver.in | 443 + rc/trafficserver.xml.in | 101 + tools/Makefile.am | 24 + tools/Makefile.in | 639 + tools/apichecker.pl | 371 + tools/push.pl | 72 + tools/tsxs.in | 185 + 1210 files changed, 484301 insertions(+) create mode 100644 .gitignore create mode 100644 .indent.pro create mode 100644 CHANGES create mode 100644 INSTALL create mode 100644 LAYOUT create mode 100644 LICENSE create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NOTICE create mode 100644 README create mode 100644 README-EC2 create mode 100644 README.libev create mode 100644 REVIEWERS create mode 100644 STATUS create mode 100644 aclocal.m4 create mode 100755 build/aux/config.guess create mode 100755 build/aux/config.sub create mode 100755 build/aux/depcomp create mode 100755 build/aux/install-sh create mode 100755 build/aux/ltmain.sh create mode 100755 build/aux/missing create mode 100755 build/aux/ylwrap create mode 100644 build/common.m4 create mode 100644 build/crypto.m4 create mode 100644 build/libtool.m4 create mode 100644 build/ltoptions.m4 create mode 100644 build/ltsugar.m4 create mode 100644 build/ltversion.m4 create mode 100644 build/lt~obsolete.m4 create mode 100644 build/lzma.m4 create mode 100644 build/network.m4 create mode 100644 build/pcre.m4 create mode 100644 build/tcl.m4 create mode 100644 build/xml.m4 create mode 100644 build/zlib.m4 create mode 100644 ci/README create mode 100644 ci/rat-excludes.txt create mode 100644 config.layout create mode 100755 configure create mode 100644 configure.ac create mode 100644 contrib/install_trafficserver.sh create mode 100644 contrib/perl/AdminClient/Changes create mode 100644 contrib/perl/AdminClient/MANIFEST create mode 100644 contrib/perl/AdminClient/Makefile.PL create mode 100644 contrib/perl/AdminClient/README create mode 100644 contrib/perl/AdminClient/lib/Apache/TS/AdminClient.pm create mode 100644 contrib/perl/AdminClient/t/Apache-TS-AdminClient.t create mode 100755 contrib/perl/ConfigMgmt/examples/forward_proxy.pl create mode 100644 contrib/perl/ConfigMgmt/lib/Apache/TS/Config.pm create mode 100644 contrib/perl/ConfigMgmt/lib/Apache/TS/Config/Records.pm create mode 100644 contrib/set_trafficserver.sh create mode 100644 cop/Makefile.am create mode 100644 cop/Makefile.in create mode 100644 cop/TrafficCop.cc create mode 100644 doc/Doxyfile.in create mode 100644 doc/Makefile.am create mode 100644 doc/Makefile.in create mode 100644 doc/doap.rdf create mode 100644 doc/dot/ResponseDiag.dot create mode 100644 doc/dot/SimpleStateDiag.dot create mode 100644 doc/dot/SimpleStateDiagAPI.dot create mode 100644 doc/mainpage.doc create mode 100644 doc/man/Makefile.am create mode 100644 doc/man/config_alarms.1 create mode 100644 doc/man/config_cache.1 create mode 100644 doc/man/config_clock.1 create mode 100644 doc/man/config_dns.1 create mode 100644 doc/man/config_get.1 create mode 100644 doc/man/config_hard-restart.1 create mode 100644 doc/man/config_hostdb.1 create mode 100644 doc/man/config_http.1 create mode 100644 doc/man/config_icp.1 create mode 100644 doc/man/config_logging.1 create mode 100644 doc/man/config_name.1 create mode 100644 doc/man/config_network.1 create mode 100644 doc/man/config_parent.1 create mode 100644 doc/man/config_port-tunnels.1 create mode 100644 doc/man/config_remap.1 create mode 100644 doc/man/config_reset-stats.1 create mode 100644 doc/man/config_restart.1 create mode 100644 doc/man/config_root.1 create mode 100644 doc/man/config_scheduled-update.1 create mode 100644 doc/man/config_security.1 create mode 100644 doc/man/config_set.1 create mode 100644 doc/man/config_socks.1 create mode 100644 doc/man/config_ssl.1 create mode 100644 doc/man/config_start.1 create mode 100644 doc/man/config_stop.1 create mode 100644 doc/man/config_upgrade.1 create mode 100644 doc/man/config_virtual-ip.1 create mode 100644 doc/man/disable.1 create mode 100644 doc/man/enable.1 create mode 100644 doc/man/exit.1 create mode 100644 doc/man/man_page_template.txt create mode 100644 doc/man/show_alarms.1 create mode 100644 doc/man/show_cache-stats.1 create mode 100644 doc/man/show_cache.1 create mode 100644 doc/man/show_cluster.1 create mode 100644 doc/man/show_dns-resolver.1 create mode 100644 doc/man/show_dns-stats.1 create mode 100644 doc/man/show_hostdb-stats.1 create mode 100644 doc/man/show_hostdb.1 create mode 100644 doc/man/show_http-stats.1 create mode 100644 doc/man/show_http-trans-stats.1 create mode 100644 doc/man/show_http.1 create mode 100644 doc/man/show_icp-stats.1 create mode 100644 doc/man/show_icp.1 create mode 100644 doc/man/show_logging-stats.1 create mode 100644 doc/man/show_logging.1 create mode 100644 doc/man/show_network.1 create mode 100644 doc/man/show_parent.1 create mode 100644 doc/man/show_port-tunnels.1 create mode 100644 doc/man/show_proxy-stats.1 create mode 100644 doc/man/show_proxy.1 create mode 100644 doc/man/show_remap.1 create mode 100644 doc/man/show_scheduled-update.1 create mode 100644 doc/man/show_security.1 create mode 100644 doc/man/show_socks.1 create mode 100644 doc/man/show_ssl.1 create mode 100644 doc/man/show_status.1 create mode 100644 doc/man/show_version.1 create mode 100644 doc/man/show_virtual-ip.1 create mode 100644 doc/man/traffic_shell.1 create mode 100644 emacs-style create mode 100644 example/Makefile.am create mode 100644 example/Makefile.in create mode 100644 example/add-header/Makefile.am create mode 100644 example/add-header/Makefile.in create mode 100644 example/add-header/add-header.c create mode 100644 example/add-header/readme.txt create mode 100644 example/app-template/Makefile.am create mode 100644 example/app-template/Makefile.in create mode 100644 example/app-template/app-template.cc create mode 100644 example/app-template/app-template.h create mode 100644 example/app-template/records.config.in create mode 100644 example/append-transform/Makefile.am create mode 100644 example/append-transform/Makefile.in create mode 100644 example/append-transform/append-transform.c create mode 100644 example/append-transform/readme.txt create mode 100644 example/basic-auth/Makefile.am create mode 100644 example/basic-auth/Makefile.in create mode 100644 example/basic-auth/basic-auth.c create mode 100644 example/basic-auth/readme.txt create mode 100644 example/blacklist-0/Makefile.am create mode 100644 example/blacklist-0/Makefile.in create mode 100644 example/blacklist-0/blacklist-0.c create mode 100644 example/blacklist-1/Makefile.am create mode 100644 example/blacklist-1/Makefile.in create mode 100644 example/blacklist-1/blacklist-1.c create mode 100644 example/blacklist-1/blacklist.txt create mode 100644 example/blacklist-1/readme.txt create mode 100644 example/bnull-transform/Makefile.am create mode 100644 example/bnull-transform/Makefile.in create mode 100644 example/bnull-transform/bnull-transform.c create mode 100644 example/cache_scan/Makefile.am create mode 100644 example/cache_scan/Makefile.in create mode 100644 example/cache_scan/cache_scan.cc create mode 100644 example/file-1/Makefile.am create mode 100644 example/file-1/Makefile.in create mode 100644 example/file-1/file-1.c create mode 100644 example/file-1/readme.txt create mode 100644 example/gzip-transform/Makefile.am create mode 100644 example/gzip-transform/Makefile.in create mode 100644 example/gzip-transform/README.txt create mode 100644 example/gzip-transform/gunzip.c create mode 100644 example/gzip-transform/gzip.c create mode 100644 example/hello/Makefile.am create mode 100644 example/hello/Makefile.in create mode 100644 example/hello/hello.c create mode 100644 example/include_other/macro.h create mode 100644 example/null-transform/Makefile.am create mode 100644 example/null-transform/Makefile.in create mode 100644 example/null-transform/null-transform.c create mode 100644 example/null-transform/readme.txt create mode 100644 example/output-header/Makefile.am create mode 100644 example/output-header/Makefile.in create mode 100644 example/output-header/output-header.c create mode 100644 example/output-header/readme create mode 100644 example/prefetch/Makefile.am create mode 100644 example/prefetch/Makefile.in create mode 100644 example/prefetch/prefetch-plugin-eg1.c create mode 100644 example/prefetch/readme.txt create mode 100644 example/prefetch/test-hns-plugin.c create mode 100644 example/protocol/Makefile.am create mode 100644 example/protocol/Makefile.in create mode 100644 example/protocol/Protocol.c create mode 100644 example/protocol/Protocol.h create mode 100644 example/protocol/README.txt create mode 100644 example/protocol/TxnSM.c create mode 100644 example/protocol/TxnSM.h create mode 100644 example/protocol/test/ProtocolClientTest.java create mode 100644 example/protocol/test/ProtocolServerTest.java create mode 100644 example/protocol/test/file_gen.sh create mode 100644 example/query_remap/Makefile.am create mode 100644 example/query_remap/Makefile.in create mode 100644 example/query_remap/query_remap.c create mode 100644 example/redirect-1/Makefile.am create mode 100644 example/redirect-1/Makefile.in create mode 100644 example/redirect-1/readme.txt create mode 100644 example/redirect-1/redirect-1.c create mode 100644 example/remap/Makefile.am create mode 100644 example/remap/Makefile.in create mode 100644 example/remap/build.txt create mode 100644 example/remap/remap.cc create mode 100644 example/replace-header/Makefile.am create mode 100644 example/replace-header/Makefile.in create mode 100644 example/replace-header/replace-header.c create mode 100644 example/response-header-1/Makefile.am create mode 100644 example/response-header-1/Makefile.in create mode 100644 example/response-header-1/response-header-1.c create mode 100644 example/server-transform/Makefile.am create mode 100644 example/server-transform/Makefile.in create mode 100644 example/server-transform/server-transform.c create mode 100644 example/session-1/Makefile.am create mode 100644 example/session-1/Makefile.in create mode 100644 example/session-1/session-1.c create mode 100644 example/thread-1/Makefile.am create mode 100644 example/thread-1/Makefile.in create mode 100644 example/thread-1/readme.txt create mode 100644 example/thread-1/thread-1.c create mode 100644 example/thread-pool/Makefile.am create mode 100644 example/thread-pool/Makefile.in create mode 100644 example/thread-pool/README.txt create mode 100644 example/thread-pool/TESTPLAN.txt create mode 100644 example/thread-pool/include/Makefile.am create mode 100644 example/thread-pool/include/gen.c create mode 100644 example/thread-pool/include/gen_inc.sh create mode 100644 example/thread-pool/psi.c create mode 100644 example/thread-pool/test/SDKTest/SDKtest_server.config create mode 100644 example/thread-pool/test/SDKTest/psi_server.c create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/1.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/10.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/11.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/12.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/13.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/2.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/3.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/4.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/5.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/6.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/7.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/8.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/9.cfg create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc10_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc11_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc12_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc13_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc1_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc2_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc3_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc4_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc5_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc6_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc7_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc8_file.txt create mode 100644 example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc9_file.txt create mode 100644 example/thread-pool/test/SynTest/system.cfg create mode 100644 example/thread-pool/test/SynTest/tests_psi.cfg create mode 100644 example/thread-pool/thread.c create mode 100644 example/thread-pool/thread.h create mode 100644 iocore/Makefile.am create mode 100644 iocore/Makefile.in create mode 100644 iocore/aio/AIO.cc create mode 100644 iocore/aio/I_AIO.h create mode 100644 iocore/aio/Inline.cc create mode 100644 iocore/aio/Makefile.am create mode 100644 iocore/aio/Makefile.in create mode 100644 iocore/aio/NTAIO.cc create mode 100644 iocore/aio/P_AIO.h create mode 100644 iocore/aio/sample.cfg create mode 100644 iocore/aio/test_AIO.i create mode 100644 iocore/aio/test_I_AIO.cc create mode 100644 iocore/aio/test_P_AIO.cc create mode 100644 iocore/cache/Cache.cc create mode 100644 iocore/cache/CacheDir.cc create mode 100644 iocore/cache/CacheDisk.cc create mode 100644 iocore/cache/CacheHosting.cc create mode 100644 iocore/cache/CacheHttp.cc create mode 100644 iocore/cache/CacheLink.cc create mode 100644 iocore/cache/CachePages.cc create mode 100644 iocore/cache/CachePagesInternal.cc create mode 100644 iocore/cache/CacheRead.cc create mode 100644 iocore/cache/CacheTest.cc create mode 100644 iocore/cache/CacheVol.cc create mode 100644 iocore/cache/CacheWrite.cc create mode 100644 iocore/cache/I_Cache.h create mode 100644 iocore/cache/I_CacheDefs.h create mode 100644 iocore/cache/I_Store.h create mode 100644 iocore/cache/Inline.cc create mode 100644 iocore/cache/Makefile.am create mode 100644 iocore/cache/Makefile.in create mode 100644 iocore/cache/Notes create mode 100644 iocore/cache/P_Cache.h create mode 100644 iocore/cache/P_CacheArray.h create mode 100644 iocore/cache/P_CacheDir.h create mode 100644 iocore/cache/P_CacheDisk.h create mode 100644 iocore/cache/P_CacheHosting.h create mode 100644 iocore/cache/P_CacheHttp.h create mode 100644 iocore/cache/P_CacheInternal.h create mode 100644 iocore/cache/P_CacheTest.h create mode 100644 iocore/cache/P_CacheVol.h create mode 100644 iocore/cache/P_RamCache.h create mode 100644 iocore/cache/RamCacheCLFUS.cc create mode 100644 iocore/cache/RamCacheLRU.cc create mode 100644 iocore/cache/Store.cc create mode 100644 iocore/cluster/ClusterAPI.cc create mode 100644 iocore/cluster/ClusterCache.cc create mode 100644 iocore/cluster/ClusterConfig.cc create mode 100644 iocore/cluster/ClusterHandler.cc create mode 100644 iocore/cluster/ClusterHandlerBase.cc create mode 100644 iocore/cluster/ClusterHash.cc create mode 100644 iocore/cluster/ClusterLib.cc create mode 100644 iocore/cluster/ClusterLoadMonitor.cc create mode 100644 iocore/cluster/ClusterMachine.cc create mode 100644 iocore/cluster/ClusterProcessor.cc create mode 100644 iocore/cluster/ClusterRPC.cc create mode 100644 iocore/cluster/ClusterVConnection.cc create mode 100644 iocore/cluster/Inline.cc create mode 100644 iocore/cluster/Makefile.am create mode 100644 iocore/cluster/Makefile.in create mode 100644 iocore/cluster/P_Cluster.h create mode 100644 iocore/cluster/P_ClusterCache.h create mode 100644 iocore/cluster/P_ClusterCacheInternal.h create mode 100644 iocore/cluster/P_ClusterHandler.h create mode 100644 iocore/cluster/P_ClusterInline.h create mode 100644 iocore/cluster/P_ClusterInternal.h create mode 100644 iocore/cluster/P_ClusterLib.h create mode 100644 iocore/cluster/P_ClusterLoadMonitor.h create mode 100644 iocore/cluster/P_ClusterMachine.h create mode 100644 iocore/cluster/P_TimeTrace.h create mode 100644 iocore/cluster/test_I_Cluster.cc create mode 100644 iocore/cluster/test_P_Cluster.cc create mode 100644 iocore/dns/DNS.cc create mode 100644 iocore/dns/DNSConnection.cc create mode 100644 iocore/dns/I_DNS.h create mode 100644 iocore/dns/I_DNSProcessor.h create mode 100644 iocore/dns/I_SplitDNS.h create mode 100644 iocore/dns/I_SplitDNSProcessor.h create mode 100644 iocore/dns/Inline.cc create mode 100644 iocore/dns/Makefile.am create mode 100644 iocore/dns/Makefile.in create mode 100644 iocore/dns/P_DNS.h create mode 100644 iocore/dns/P_DNSConnection.h create mode 100644 iocore/dns/P_DNSProcessor.h create mode 100644 iocore/dns/P_SplitDNS.h create mode 100644 iocore/dns/P_SplitDNSProcessor.h create mode 100644 iocore/dns/SRV.cc create mode 100644 iocore/dns/SRV.h create mode 100644 iocore/dns/SplitDNS.cc create mode 100644 iocore/dns/test_I_DNS.cc create mode 100644 iocore/dns/test_P_DNS.cc create mode 100644 iocore/eventsystem/EventSystem.cc create mode 100644 iocore/eventsystem/IOBuffer.cc create mode 100644 iocore/eventsystem/I_Action.h create mode 100644 iocore/eventsystem/I_Continuation.h create mode 100644 iocore/eventsystem/I_EThread.h create mode 100644 iocore/eventsystem/I_Event.h create mode 100644 iocore/eventsystem/I_EventProcessor.h create mode 100644 iocore/eventsystem/I_EventSystem.h create mode 100644 iocore/eventsystem/I_IOBuffer.h create mode 100644 iocore/eventsystem/I_Lock.h create mode 100644 iocore/eventsystem/I_PriorityEventQueue.h create mode 100644 iocore/eventsystem/I_Processor.h create mode 100644 iocore/eventsystem/I_ProtectedQueue.h create mode 100644 iocore/eventsystem/I_ProxyAllocator.h create mode 100644 iocore/eventsystem/I_SocketManager.h create mode 100644 iocore/eventsystem/I_Tasks.h create mode 100644 iocore/eventsystem/I_Thread.h create mode 100644 iocore/eventsystem/I_VConnection.h create mode 100644 iocore/eventsystem/I_VIO.h create mode 100644 iocore/eventsystem/Inline.cc create mode 100644 iocore/eventsystem/Lock.cc create mode 100644 iocore/eventsystem/Makefile.am create mode 100644 iocore/eventsystem/Makefile.in create mode 100644 iocore/eventsystem/PQ-List.cc create mode 100644 iocore/eventsystem/P_EventSystem.h create mode 100644 iocore/eventsystem/P_Freer.h create mode 100644 iocore/eventsystem/P_IOBuffer.h create mode 100644 iocore/eventsystem/P_ProtectedQueue.h create mode 100644 iocore/eventsystem/P_Thread.h create mode 100644 iocore/eventsystem/P_UnixEThread.h create mode 100644 iocore/eventsystem/P_UnixEvent.h create mode 100644 iocore/eventsystem/P_UnixEventProcessor.h create mode 100644 iocore/eventsystem/P_UnixSocketManager.h create mode 100644 iocore/eventsystem/P_VConnection.h create mode 100644 iocore/eventsystem/P_VIO.h create mode 100644 iocore/eventsystem/Processor.cc create mode 100644 iocore/eventsystem/ProtectedQueue.cc create mode 100644 iocore/eventsystem/SocketManager.cc create mode 100644 iocore/eventsystem/Tasks.cc create mode 100644 iocore/eventsystem/Thread.cc create mode 100644 iocore/eventsystem/UnixEThread.cc create mode 100644 iocore/eventsystem/UnixEvent.cc create mode 100644 iocore/eventsystem/UnixEventProcessor.cc create mode 100644 iocore/eventsystem/test_Buffer.cc create mode 100644 iocore/eventsystem/test_Event.i create mode 100644 iocore/eventsystem/test_I_Buffer.cc create mode 100644 iocore/eventsystem/test_I_Event.cc create mode 100644 iocore/eventsystem/test_P_Buffer.cc create mode 100644 iocore/eventsystem/test_P_Event.cc create mode 100644 iocore/hostdb/HostDB.cc create mode 100644 iocore/hostdb/I_HostDB.h create mode 100644 iocore/hostdb/I_HostDBProcessor.h create mode 100644 iocore/hostdb/Inline.cc create mode 100644 iocore/hostdb/Makefile.am create mode 100644 iocore/hostdb/Makefile.in create mode 100644 iocore/hostdb/MultiCache.cc create mode 100644 iocore/hostdb/P_HostDB.h create mode 100644 iocore/hostdb/P_HostDBProcessor.h create mode 100644 iocore/hostdb/P_MultiCache.h create mode 100644 iocore/hostdb/include/Machine.h create mode 100644 iocore/hostdb/test_I_HostDB.cc create mode 100644 iocore/hostdb/test_P_HostDB.cc create mode 100644 iocore/net/Connection.cc create mode 100644 iocore/net/I_Net.h create mode 100644 iocore/net/I_NetConfig.h create mode 100644 iocore/net/I_NetProcessor.h create mode 100644 iocore/net/I_NetVConnection.h create mode 100644 iocore/net/I_Socks.h create mode 100644 iocore/net/I_UDPConnection.h create mode 100644 iocore/net/I_UDPNet.h create mode 100644 iocore/net/I_UDPPacket.h create mode 100644 iocore/net/Inline.cc create mode 100644 iocore/net/Makefile.am create mode 100644 iocore/net/Makefile.in create mode 100644 iocore/net/Net.cc create mode 100644 iocore/net/NetConfig.cc create mode 100644 iocore/net/NetTest-http-server.c create mode 100644 iocore/net/NetTest-simple-proxy.c create mode 100644 iocore/net/NetVCTest.cc create mode 100644 iocore/net/NetVConnection.cc create mode 100644 iocore/net/P_CompletionUtil.h create mode 100644 iocore/net/P_Connection.h create mode 100644 iocore/net/P_InkBulkIO.h create mode 100644 iocore/net/P_LibBulkIO.h create mode 100644 iocore/net/P_Net.h create mode 100644 iocore/net/P_NetAccept.h create mode 100644 iocore/net/P_NetVCTest.h create mode 100644 iocore/net/P_NetVConnection.h create mode 100644 iocore/net/P_SSLCertLookup.h create mode 100644 iocore/net/P_SSLConfig.h create mode 100644 iocore/net/P_SSLNetAccept.h create mode 100644 iocore/net/P_SSLNetProcessor.h create mode 100644 iocore/net/P_SSLNetVConnection.h create mode 100644 iocore/net/P_Socks.h create mode 100644 iocore/net/P_UDPConnection.h create mode 100644 iocore/net/P_UDPIOEvent.h create mode 100644 iocore/net/P_UDPNet.h create mode 100644 iocore/net/P_UDPPacket.h create mode 100644 iocore/net/P_UnixCompletionUtil.h create mode 100644 iocore/net/P_UnixNet.h create mode 100644 iocore/net/P_UnixNetProcessor.h create mode 100644 iocore/net/P_UnixNetState.h create mode 100644 iocore/net/P_UnixNetVConnection.h create mode 100644 iocore/net/P_UnixPollDescriptor.h create mode 100644 iocore/net/P_UnixUDPConnection.h create mode 100644 iocore/net/SSLCertLookup.cc create mode 100644 iocore/net/SSLConfig.cc create mode 100644 iocore/net/SSLNet.cc create mode 100644 iocore/net/SSLNetVConnection.cc create mode 100644 iocore/net/SSLUnixNet.cc create mode 100644 iocore/net/Socks.cc create mode 100644 iocore/net/UDPIOEvent.cc create mode 100644 iocore/net/UnixConnection.cc create mode 100644 iocore/net/UnixNet.cc create mode 100644 iocore/net/UnixNetAccept.cc create mode 100644 iocore/net/UnixNetPages.cc create mode 100644 iocore/net/UnixNetProcessor.cc create mode 100644 iocore/net/UnixNetVConnection.cc create mode 100644 iocore/net/UnixUDPConnection.cc create mode 100644 iocore/net/UnixUDPNet.cc create mode 100644 iocore/net/test_I_Net.cc create mode 100644 iocore/net/test_I_UDPNet.cc create mode 100644 iocore/net/test_I_simple_proxy.cc create mode 100644 iocore/net/test_P_Net.cc create mode 100644 iocore/net/test_P_UDPNet.cc create mode 100644 iocore/utils/I_Machine.h create mode 100644 iocore/utils/I_OneWayMultiTunnel.h create mode 100644 iocore/utils/I_OneWayTunnel.h create mode 100644 iocore/utils/Machine.cc create mode 100644 iocore/utils/Makefile.am create mode 100644 iocore/utils/Makefile.in create mode 100644 iocore/utils/OneWayMultiTunnel.cc create mode 100644 iocore/utils/OneWayTunnel.cc create mode 100644 iocore/utils/diags.i create mode 100644 lib/Makefile.am create mode 100644 lib/Makefile.in create mode 100644 lib/records/I_RecAlarms.h create mode 100644 lib/records/I_RecCore.h create mode 100644 lib/records/I_RecDefs.h create mode 100644 lib/records/I_RecEvents.h create mode 100644 lib/records/I_RecLocal.h create mode 100644 lib/records/I_RecMutex.h create mode 100644 lib/records/I_RecProcess.h create mode 100644 lib/records/I_RecSignals.h create mode 100644 lib/records/Makefile.am create mode 100644 lib/records/Makefile.in create mode 100644 lib/records/P_RecCompatibility.h create mode 100644 lib/records/P_RecCore.h create mode 100644 lib/records/P_RecCore.i create mode 100644 lib/records/P_RecDefs.h create mode 100644 lib/records/P_RecLocal.h create mode 100644 lib/records/P_RecMessage.h create mode 100644 lib/records/P_RecProcess.h create mode 100644 lib/records/P_RecTree.h create mode 100644 lib/records/P_RecUtils.h create mode 100644 lib/records/RecCompatibility.cc create mode 100644 lib/records/RecCore.cc create mode 100644 lib/records/RecLocal.cc create mode 100644 lib/records/RecMessage.cc create mode 100644 lib/records/RecMutex.cc create mode 100644 lib/records/RecProcess.cc create mode 100644 lib/records/RecTree.cc create mode 100644 lib/records/RecUtils.cc create mode 100644 lib/records/test_I_RecLocal.cc create mode 100644 lib/records/test_I_RecProcess.cc create mode 100644 lib/records/test_P_RecProcess.cc create mode 100644 lib/records/test_RecProcess.i create mode 100644 lib/records/test_RecTree.cc create mode 100644 lib/records/test_RecordsConfig.cc create mode 100644 lib/records/test_RecordsConfig.h create mode 100644 lib/records/test_records.config create mode 100644 lib/ts/Allocator.cc create mode 100644 lib/ts/Allocator.h create mode 100644 lib/ts/Arena.cc create mode 100644 lib/ts/Arena.h create mode 100644 lib/ts/Bitops.cc create mode 100644 lib/ts/Bitops.h create mode 100644 lib/ts/Compatability.h create mode 100644 lib/ts/CompileParseRules.cc create mode 100644 lib/ts/DAllocator.cc create mode 100644 lib/ts/DAllocator.h create mode 100644 lib/ts/Diags.cc create mode 100644 lib/ts/Diags.h create mode 100644 lib/ts/DynArray.h create mode 100644 lib/ts/HostLookup.cc create mode 100644 lib/ts/HostLookup.h create mode 100644 lib/ts/INK_MD5.h create mode 100644 lib/ts/I_Layout.h create mode 100644 lib/ts/I_Version.h create mode 100644 lib/ts/InkErrno.h create mode 100644 lib/ts/InkPool.h create mode 100644 lib/ts/Layout.cc create mode 100644 lib/ts/List.h create mode 100644 lib/ts/MMH.cc create mode 100644 lib/ts/MMH.h create mode 100644 lib/ts/Makefile.am create mode 100644 lib/ts/Makefile.in create mode 100644 lib/ts/Map.h create mode 100644 lib/ts/MatcherUtils.cc create mode 100644 lib/ts/MatcherUtils.h create mode 100644 lib/ts/MimeTable.cc create mode 100644 lib/ts/MimeTable.h create mode 100644 lib/ts/ParseRules.cc create mode 100644 lib/ts/ParseRules.h create mode 100644 lib/ts/Ptr.h create mode 100644 lib/ts/RawHashTable.cc create mode 100644 lib/ts/RawHashTable.h create mode 100644 lib/ts/Regex.cc create mode 100644 lib/ts/Regex.h create mode 100644 lib/ts/Regression.cc create mode 100644 lib/ts/Regression.h create mode 100644 lib/ts/Resource.cc create mode 100644 lib/ts/Resource.h create mode 100644 lib/ts/SimpleTokenizer.h create mode 100644 lib/ts/TestHttpHeader.cc create mode 100644 lib/ts/TextBuffer.cc create mode 100644 lib/ts/TextBuffer.h create mode 100644 lib/ts/Tokenizer.cc create mode 100644 lib/ts/Tokenizer.h create mode 100644 lib/ts/Vec.cc create mode 100644 lib/ts/Vec.h create mode 100644 lib/ts/Version.cc create mode 100644 lib/ts/defalloc.h create mode 100644 lib/ts/fastlz.c create mode 100644 lib/ts/fastlz.h create mode 100644 lib/ts/ink_aiocb.h create mode 100644 lib/ts/ink_align.h create mode 100644 lib/ts/ink_apidefs.h create mode 100644 lib/ts/ink_args.cc create mode 100644 lib/ts/ink_args.h create mode 100644 lib/ts/ink_assert.cc create mode 100644 lib/ts/ink_assert.h create mode 100644 lib/ts/ink_atomic.h create mode 100644 lib/ts/ink_auth_api.cc create mode 100644 lib/ts/ink_auth_api.h create mode 100644 lib/ts/ink_autoconf.h.in create mode 100644 lib/ts/ink_base64.cc create mode 100644 lib/ts/ink_base64.h create mode 100644 lib/ts/ink_bool.h create mode 100644 lib/ts/ink_cap.cc create mode 100644 lib/ts/ink_cap.h create mode 100644 lib/ts/ink_code.cc create mode 100644 lib/ts/ink_code.h create mode 100644 lib/ts/ink_config.h.in create mode 100644 lib/ts/ink_defs.cc create mode 100644 lib/ts/ink_defs.h create mode 100644 lib/ts/ink_error.cc create mode 100644 lib/ts/ink_error.h create mode 100644 lib/ts/ink_exception.h create mode 100644 lib/ts/ink_file.cc create mode 100644 lib/ts/ink_file.h create mode 100644 lib/ts/ink_hash_table.cc create mode 100644 lib/ts/ink_hash_table.h create mode 100644 lib/ts/ink_hrtime.cc create mode 100644 lib/ts/ink_hrtime.h create mode 100644 lib/ts/ink_inet.cc create mode 100644 lib/ts/ink_inet.h create mode 100644 lib/ts/ink_inout.h create mode 100644 lib/ts/ink_isolatin_table.cc create mode 100644 lib/ts/ink_isolatin_table.h create mode 100644 lib/ts/ink_killall.cc create mode 100644 lib/ts/ink_killall.h create mode 100644 lib/ts/ink_llqueue.h create mode 100644 lib/ts/ink_lockfile.h create mode 100644 lib/ts/ink_memory.cc create mode 100644 lib/ts/ink_memory.h create mode 100644 lib/ts/ink_mutex.cc create mode 100644 lib/ts/ink_mutex.h create mode 100644 lib/ts/ink_platform.h create mode 100644 lib/ts/ink_port.h create mode 100644 lib/ts/ink_queue.cc create mode 100644 lib/ts/ink_queue.h create mode 100644 lib/ts/ink_queue_utils.cc create mode 100644 lib/ts/ink_rand.cc create mode 100644 lib/ts/ink_rand.h create mode 100644 lib/ts/ink_res_init.cc create mode 100644 lib/ts/ink_res_mkquery.cc create mode 100644 lib/ts/ink_resolver.h create mode 100644 lib/ts/ink_resource.cc create mode 100644 lib/ts/ink_resource.h create mode 100644 lib/ts/ink_rwlock.cc create mode 100644 lib/ts/ink_rwlock.h create mode 100644 lib/ts/ink_sock.cc create mode 100644 lib/ts/ink_sock.h create mode 100644 lib/ts/ink_sprintf.cc create mode 100644 lib/ts/ink_sprintf.h create mode 100644 lib/ts/ink_stack_trace.cc create mode 100644 lib/ts/ink_stack_trace.h create mode 100644 lib/ts/ink_string++.cc create mode 100644 lib/ts/ink_string++.h create mode 100644 lib/ts/ink_string.cc create mode 100644 lib/ts/ink_string.h create mode 100644 lib/ts/ink_sys_control.cc create mode 100644 lib/ts/ink_sys_control.h create mode 100644 lib/ts/ink_syslog.cc create mode 100644 lib/ts/ink_syslog.h create mode 100644 lib/ts/ink_thread.cc create mode 100644 lib/ts/ink_thread.h create mode 100644 lib/ts/ink_time.cc create mode 100644 lib/ts/ink_time.h create mode 100644 lib/ts/ink_unused.h create mode 100644 lib/ts/libts.h create mode 100644 lib/ts/llqueue.cc create mode 100644 lib/ts/load_http_hdr.cc create mode 100644 lib/ts/lockfile.cc create mode 100644 lib/ts/mkdfa.c create mode 100644 lib/ts/test_List.cc create mode 100644 lib/ts/test_Map.cc create mode 100644 lib/ts/test_Vec.cc create mode 100644 lib/ts/test_arena.cc create mode 100644 lib/ts/test_atomic.cc create mode 100644 lib/ts/test_freelist.cc create mode 100644 lib/ts/test_memchr.cc create mode 100644 lib/ts/test_strings.cc create mode 100644 lib/tsconfig/BisonHeaderToC++.sed create mode 100644 lib/tsconfig/Errata.cc create mode 100644 lib/tsconfig/Errata.h create mode 100644 lib/tsconfig/IntrusivePtr.h create mode 100644 lib/tsconfig/Makefile.am create mode 100644 lib/tsconfig/Makefile.in create mode 100644 lib/tsconfig/NumericType.h create mode 100644 lib/tsconfig/TsBuffer.h create mode 100644 lib/tsconfig/TsBuilder.cc create mode 100644 lib/tsconfig/TsBuilder.h create mode 100644 lib/tsconfig/TsConfigGrammar.y create mode 100644 lib/tsconfig/TsConfigLexer.h create mode 100644 lib/tsconfig/TsConfigParseEvents.h create mode 100644 lib/tsconfig/TsConfigSyntax.l create mode 100644 lib/tsconfig/TsConfigTypes.h create mode 100644 lib/tsconfig/TsErrataUtil.cc create mode 100644 lib/tsconfig/TsErrataUtil.h create mode 100644 lib/tsconfig/TsValue.cc create mode 100644 lib/tsconfig/TsValue.h create mode 100644 lib/tsconfig/test-1.tsconfig create mode 100644 lib/tsconfig/test-tsconfig.cc create mode 100644 lib/wccp/Makefile.am create mode 100644 lib/wccp/Makefile.in create mode 100644 lib/wccp/Wccp.h create mode 100644 lib/wccp/WccpConfig.cc create mode 100644 lib/wccp/WccpEndPoint.cc create mode 100644 lib/wccp/WccpLocal.h create mode 100644 lib/wccp/WccpMeta.h create mode 100644 lib/wccp/WccpMsg.cc create mode 100644 lib/wccp/WccpStatic.cc create mode 100644 lib/wccp/WccpUtil.h create mode 100644 lib/wccp/wccp-test-cache.cc create mode 100644 lib/wccp/wccp-test-router.cc create mode 100644 mgmt/AddConfigFilesHere.cc create mode 100644 mgmt/Alarms.cc create mode 100644 mgmt/Alarms.h create mode 100644 mgmt/BaseManager.cc create mode 100644 mgmt/BaseManager.h create mode 100644 mgmt/FileManager.cc create mode 100644 mgmt/FileManager.h create mode 100644 mgmt/LocalManager.cc create mode 100644 mgmt/LocalManager.h create mode 100644 mgmt/Main.cc create mode 100644 mgmt/Main.h create mode 100644 mgmt/Makefile.am create mode 100644 mgmt/Makefile.in create mode 100644 mgmt/MgmtDefs.h create mode 100644 mgmt/MultiFile.cc create mode 100644 mgmt/MultiFile.h create mode 100644 mgmt/ProcessManager.cc create mode 100644 mgmt/ProcessManager.h create mode 100644 mgmt/RecordsConfig.cc create mode 100644 mgmt/RecordsConfig.h create mode 100644 mgmt/Rollback.cc create mode 100644 mgmt/Rollback.h create mode 100644 mgmt/api/CfgContextDefs.h create mode 100644 mgmt/api/CfgContextImpl.cc create mode 100644 mgmt/api/CfgContextImpl.h create mode 100644 mgmt/api/CfgContextManager.cc create mode 100644 mgmt/api/CfgContextManager.h create mode 100644 mgmt/api/CfgContextUtils.cc create mode 100644 mgmt/api/CfgContextUtils.h create mode 100644 mgmt/api/CoreAPI.cc create mode 100644 mgmt/api/CoreAPI.h create mode 100644 mgmt/api/CoreAPIShared.cc create mode 100644 mgmt/api/CoreAPIShared.h create mode 100644 mgmt/api/EventCallback.cc create mode 100644 mgmt/api/EventCallback.h create mode 100644 mgmt/api/EventControlMain.cc create mode 100644 mgmt/api/EventControlMain.h create mode 100644 mgmt/api/GenericParser.cc create mode 100644 mgmt/api/GenericParser.h create mode 100644 mgmt/api/INKMgmtAPI.cc create mode 100644 mgmt/api/INKMgmtAPIStub.cc create mode 100644 mgmt/api/Makefile.am create mode 100644 mgmt/api/Makefile.in create mode 100644 mgmt/api/NetworkUtilsDefs.h create mode 100644 mgmt/api/NetworkUtilsLocal.cc create mode 100644 mgmt/api/NetworkUtilsLocal.h create mode 100644 mgmt/api/TSControlMain.cc create mode 100644 mgmt/api/TSControlMain.h create mode 100644 mgmt/api/include/Makefile.am create mode 100644 mgmt/api/include/Makefile.in create mode 100644 mgmt/api/include/mgmtapi.h create mode 100644 mgmt/api/remote/APITestCliRemote.cc create mode 100644 mgmt/api/remote/CoreAPIRemote.cc create mode 100644 mgmt/api/remote/EventRegistration.cc create mode 100644 mgmt/api/remote/EventRegistration.h create mode 100644 mgmt/api/remote/Makefile.am create mode 100644 mgmt/api/remote/Makefile.in create mode 100644 mgmt/api/remote/NetworkUtilsRemote.cc create mode 100644 mgmt/api/remote/NetworkUtilsRemote.h create mode 100644 mgmt/cli/CliCreateCommands.cc create mode 100644 mgmt/cli/CliCreateCommands.h create mode 100644 mgmt/cli/CliDisplay.cc create mode 100644 mgmt/cli/CliDisplay.h create mode 100644 mgmt/cli/CliMgmtUtils.cc create mode 100644 mgmt/cli/CliMgmtUtils.h create mode 100644 mgmt/cli/ConfigCmd.cc create mode 100644 mgmt/cli/ConfigCmd.h create mode 100644 mgmt/cli/ConfigUpgradeCmd.cc create mode 100644 mgmt/cli/ConfigUpgradeCmd.h create mode 100644 mgmt/cli/ConfigUpgradeReadCmd.cc create mode 100644 mgmt/cli/ConfigUpgradeWriteCmd.cc create mode 100644 mgmt/cli/Makefile.am create mode 100644 mgmt/cli/Makefile.in create mode 100644 mgmt/cli/ShowCmd.cc create mode 100644 mgmt/cli/ShowCmd.h create mode 100644 mgmt/cli/TrafficLine.cc create mode 100644 mgmt/cli/UtilCmds.cc create mode 100644 mgmt/cli/UtilCmds.h create mode 100644 mgmt/cli/cliAppInit.cc create mode 100644 mgmt/cli/cliMain.cc create mode 100644 mgmt/cli/cliParseArg.cc create mode 100644 mgmt/cli/cli_detailed_command_list.txt create mode 100644 mgmt/cli/cli_feature_spec.txt create mode 100644 mgmt/cli/commandOptions.h create mode 100644 mgmt/cli/createArgument.cc create mode 100644 mgmt/cli/createArgument.h create mode 100644 mgmt/cli/createCommand.cc create mode 100644 mgmt/cli/createCommand.h create mode 100644 mgmt/cli/definitions.h create mode 100644 mgmt/cli/hashtable.cc create mode 100644 mgmt/cli/hashtable.h create mode 100644 mgmt/cli/processArgument.cc create mode 100644 mgmt/cli/script_configs.sh create mode 100644 mgmt/cluster/ClusterCom.cc create mode 100644 mgmt/cluster/ClusterCom.h create mode 100644 mgmt/cluster/Makefile.am create mode 100644 mgmt/cluster/Makefile.in create mode 100644 mgmt/cluster/VMap.cc create mode 100644 mgmt/cluster/VMap.h create mode 100644 mgmt/preparse/IPRange.cc create mode 100644 mgmt/preparse/IPRange.h create mode 100644 mgmt/preparse/Makefile.am create mode 100644 mgmt/preparse/Makefile.in create mode 100644 mgmt/preparse/RemapReadConfig.cc create mode 100644 mgmt/preparse/SocksParser.cc create mode 100644 mgmt/preparse/StoreReadConfig.cc create mode 100644 mgmt/stats/Makefile.am create mode 100644 mgmt/stats/Makefile.in create mode 100644 mgmt/stats/StatProcessor.cc create mode 100644 mgmt/stats/StatProcessor.h create mode 100644 mgmt/stats/StatType.cc create mode 100644 mgmt/stats/StatType.h create mode 100644 mgmt/stats/StatXML.cc create mode 100644 mgmt/stats/StatXML.h create mode 100644 mgmt/stats/spec create mode 100644 mgmt/tools/ConfigAPI.cc create mode 100644 mgmt/tools/ConfigAPI.h create mode 100644 mgmt/tools/Makefile.am create mode 100644 mgmt/tools/Makefile.in create mode 100644 mgmt/tools/SysAPI.cc create mode 100644 mgmt/tools/SysAPI.h create mode 100644 mgmt/utils/EnvBlock.cc create mode 100644 mgmt/utils/EnvBlock.h create mode 100644 mgmt/utils/ExpandingArray.cc create mode 100644 mgmt/utils/ExpandingArray.h create mode 100644 mgmt/utils/IpLookup.cc create mode 100644 mgmt/utils/IpLookup.h create mode 100644 mgmt/utils/Makefile.am create mode 100644 mgmt/utils/Makefile.in create mode 100644 mgmt/utils/MgmtHashTable.h create mode 100644 mgmt/utils/MgmtSchema.cc create mode 100644 mgmt/utils/MgmtSchema.h create mode 100644 mgmt/utils/MgmtSocket.h create mode 100644 mgmt/utils/MgmtUtils.cc create mode 100644 mgmt/utils/MgmtUtils.h create mode 100644 mgmt/utils/WebMgmtUtils.cc create mode 100644 mgmt/utils/WebMgmtUtils.h create mode 100644 mgmt/utils/XmlUtils.cc create mode 100644 mgmt/utils/XmlUtils.h create mode 100644 mgmt/web2/Makefile.am create mode 100644 mgmt/web2/Makefile.in create mode 100644 mgmt/web2/WebCompatibility.cc create mode 100644 mgmt/web2/WebCompatibility.h create mode 100644 mgmt/web2/WebGlobals.h create mode 100644 mgmt/web2/WebHttp.cc create mode 100644 mgmt/web2/WebHttp.h create mode 100644 mgmt/web2/WebHttpContext.cc create mode 100644 mgmt/web2/WebHttpContext.h create mode 100644 mgmt/web2/WebHttpMessage.cc create mode 100644 mgmt/web2/WebHttpMessage.h create mode 100644 mgmt/web2/WebHttpSession.cc create mode 100644 mgmt/web2/WebHttpSession.h create mode 100644 mgmt/web2/WebIntrMain.cc create mode 100644 mgmt/web2/WebIntrMain.h create mode 100644 mgmt/web2/WebOverview.cc create mode 100644 mgmt/web2/WebOverview.h create mode 100644 mgmt/web2/WebUtils.cc create mode 100644 mgmt/web2/WebUtils.h create mode 100644 plugins/Makefile.am create mode 100644 plugins/Makefile.in create mode 100644 plugins/conf_remap/Makefile.am create mode 100644 plugins/conf_remap/Makefile.in create mode 100644 plugins/conf_remap/conf_remap.cc create mode 100644 proxy/AbstractBuffer.cc create mode 100644 proxy/AbstractBuffer.h create mode 100644 proxy/CacheControl.cc create mode 100644 proxy/CacheControl.h create mode 100644 proxy/ClassH.txt create mode 100644 proxy/CompletionUtil.h create mode 100644 proxy/ConfigParse.h create mode 100644 proxy/ControlBase.cc create mode 100644 proxy/ControlBase.h create mode 100644 proxy/ControlMatcher.cc create mode 100644 proxy/ControlMatcher.h create mode 100644 proxy/CoreUtils.cc create mode 100644 proxy/CoreUtils.h create mode 100644 proxy/DebugStreamLevels.txt create mode 100644 proxy/DiagsConfig.cc create mode 100644 proxy/DiagsConfig.h create mode 100644 proxy/DynamicStats.h create mode 100644 proxy/Error.cc create mode 100644 proxy/Error.h create mode 100644 proxy/EventName.cc create mode 100644 proxy/EventName.h create mode 100644 proxy/FetchSM.cc create mode 100644 proxy/FetchSM.h create mode 100644 proxy/Freer.h create mode 100644 proxy/HttpTransStats.h create mode 100644 proxy/ICP.cc create mode 100644 proxy/ICP.h create mode 100644 proxy/ICPConfig.cc create mode 100644 proxy/ICPProcessor.cc create mode 100644 proxy/ICPProcessor.h create mode 100644 proxy/ICPStats.cc create mode 100644 proxy/ICPevents.h create mode 100644 proxy/ICPlog.h create mode 100644 proxy/IPAllow.cc create mode 100644 proxy/IPAllow.h create mode 100644 proxy/Initialize.cc create mode 100644 proxy/Initialize.h create mode 100644 proxy/InkAPI-ensure-funcs-present.pl create mode 100644 proxy/InkAPI.cc create mode 100644 proxy/InkAPIInternal.h create mode 100644 proxy/InkAPITest.cc create mode 100644 proxy/InkAPITestTool.cc create mode 100644 proxy/InkIOCoreAPI.cc create mode 100644 proxy/InkPool_r.h create mode 100644 proxy/InkXml.cc create mode 100644 proxy/InkXml.h create mode 100644 proxy/Main.cc create mode 100644 proxy/Main.h create mode 100644 proxy/Makefile.am create mode 100644 proxy/Makefile.in create mode 100644 proxy/MuxVC.cc create mode 100644 proxy/MuxVC.h create mode 100644 proxy/ParentSelection.cc create mode 100644 proxy/ParentSelection.h create mode 100644 proxy/Plugin.cc create mode 100644 proxy/Plugin.h create mode 100644 proxy/PluginDB.cc create mode 100644 proxy/PluginDB.h create mode 100644 proxy/PluginVC.cc create mode 100644 proxy/PluginVC.h create mode 100644 proxy/Prefetch.cc create mode 100644 proxy/Prefetch.h create mode 100644 proxy/ProtoSM.h create mode 100644 proxy/ProxyConfig.cc create mode 100644 proxy/ProxyConfig.h create mode 100644 proxy/README-stats.otl create mode 100644 proxy/RegressionSM.cc create mode 100644 proxy/RegressionSM.h create mode 100644 proxy/ReverseProxy.cc create mode 100644 proxy/ReverseProxy.h create mode 100644 proxy/Show.h create mode 100644 proxy/SimpleHttp.cc create mode 100644 proxy/Socks.h create mode 100644 proxy/SocksProxy.cc create mode 100644 proxy/StatPages.cc create mode 100644 proxy/StatPages.h create mode 100644 proxy/StatSystem.cc create mode 100644 proxy/StatSystem.h create mode 100644 proxy/Stuffer.cc create mode 100644 proxy/Stuffer.h create mode 100644 proxy/StufferUdpReceiver.cc create mode 100644 proxy/TestClock.cc create mode 100644 proxy/TestClusterHash.cc create mode 100644 proxy/TestDNS.cc create mode 100644 proxy/TestHook.cc create mode 100644 proxy/TestPreProc.cc create mode 100644 proxy/TestPreProc.h create mode 100644 proxy/TestProxy.cc create mode 100644 proxy/TestRegex.cc create mode 100644 proxy/TestSimpleProxy.cc create mode 100644 proxy/TimeTrace.h create mode 100644 proxy/Transform.cc create mode 100644 proxy/Transform.h create mode 100644 proxy/TransformInternal.h create mode 100644 proxy/UDPAPIClientTest.cc create mode 100644 proxy/UDPAPIClientTest.h create mode 100644 proxy/UDPAPITest.cc create mode 100644 proxy/UDPAPITest.h create mode 100644 proxy/UglyLogStubs.cc create mode 100644 proxy/UnixCompletionUtil.h create mode 100644 proxy/Update.cc create mode 100644 proxy/Update.h create mode 100644 proxy/UserNameCacheTest.h create mode 100644 proxy/api/ts/InkAPIHughes.h create mode 100644 proxy/api/ts/InkAPIPrivateIOCore.h create mode 100644 proxy/api/ts/Makefile.am create mode 100644 proxy/api/ts/Makefile.in create mode 100644 proxy/api/ts/TsException.h create mode 100644 proxy/api/ts/experimental.h create mode 100644 proxy/api/ts/remap.h create mode 100644 proxy/api/ts/ts.h.in create mode 100644 proxy/config/Makefile.am create mode 100644 proxy/config/Makefile.in create mode 100644 proxy/config/ae_ua.config.default create mode 100644 proxy/config/body_factory/Makefile.am create mode 100644 proxy/config/body_factory/Makefile.in create mode 100644 proxy/config/body_factory/default/.body_factory_info create mode 100644 proxy/config/body_factory/default/Makefile.am create mode 100644 proxy/config/body_factory/default/Makefile.in create mode 100644 proxy/config/body_factory/default/README create mode 100644 proxy/config/body_factory/default/access#denied create mode 100644 proxy/config/body_factory/default/access#proxy_auth_required create mode 100644 proxy/config/body_factory/default/access#redirect_url create mode 100644 proxy/config/body_factory/default/access#ssl_forbidden create mode 100644 proxy/config/body_factory/default/cache#not_in_cache create mode 100644 proxy/config/body_factory/default/cache#read_error create mode 100644 proxy/config/body_factory/default/congestion#retryAfter create mode 100644 proxy/config/body_factory/default/connect#dns_failed create mode 100644 proxy/config/body_factory/default/connect#failed_connect create mode 100644 proxy/config/body_factory/default/connect#hangup create mode 100644 proxy/config/body_factory/default/default create mode 100644 proxy/config/body_factory/default/interception#no_host create mode 100644 proxy/config/body_factory/default/redirect#moved_temporarily create mode 100644 proxy/config/body_factory/default/request#cycle_detected create mode 100644 proxy/config/body_factory/default/request#no_content_length create mode 100644 proxy/config/body_factory/default/request#no_host create mode 100644 proxy/config/body_factory/default/request#scheme_unsupported create mode 100644 proxy/config/body_factory/default/request#syntax_error create mode 100644 proxy/config/body_factory/default/response#bad_response create mode 100644 proxy/config/body_factory/default/response#bad_version create mode 100644 proxy/config/body_factory/default/timeout#activity create mode 100644 proxy/config/body_factory/default/timeout#inactivity create mode 100644 proxy/config/body_factory/default/transcoding#unsupported create mode 100644 proxy/config/body_factory/default/urlrouting#no_mapping create mode 100644 proxy/config/cache.config.default create mode 100644 proxy/config/cluster.config.default create mode 100644 proxy/config/congestion.config.default create mode 100644 proxy/config/hosting.config.default create mode 100644 proxy/config/icp.config.default create mode 100644 proxy/config/ip_allow.config.default create mode 100644 proxy/config/log_hosts.config.default create mode 100644 proxy/config/logs_xml.config.default create mode 100644 proxy/config/mgr.cnf.default create mode 100644 proxy/config/parent.config.default create mode 100644 proxy/config/plugin.config.default create mode 100644 proxy/config/plugin.db.default create mode 100644 proxy/config/prefetch.config.default create mode 100644 proxy/config/public_key.der create mode 100644 proxy/config/records.config.default.in create mode 100644 proxy/config/remap.config.default create mode 100644 proxy/config/socks.config.default create mode 100644 proxy/config/splitdns.config.default create mode 100644 proxy/config/ssl_multicert.config.default create mode 100644 proxy/config/stats.config.dtd create mode 100644 proxy/config/stats.config.xml.default create mode 100644 proxy/config/storage.config.default.in create mode 100644 proxy/config/throttle_error.html.example create mode 100644 proxy/config/update.config.default create mode 100644 proxy/config/vaddrs.config.default create mode 100644 proxy/config/volume.config.default create mode 100644 proxy/config/winnt_intr.config.default create mode 100644 proxy/congest/Congestion.cc create mode 100644 proxy/congest/Congestion.h create mode 100644 proxy/congest/CongestionDB.cc create mode 100644 proxy/congest/CongestionDB.h create mode 100644 proxy/congest/CongestionStats.cc create mode 100644 proxy/congest/CongestionStats.h create mode 100644 proxy/congest/CongestionTest.cc create mode 100644 proxy/congest/FeatureSpec.txt create mode 100644 proxy/congest/MT_hashtable.h create mode 100644 proxy/congest/Makefile.am create mode 100644 proxy/congest/Makefile.in create mode 100644 proxy/example_alarm_bin.sh create mode 100644 proxy/example_prep.sh create mode 100644 proxy/hdrs/HTTP.cc create mode 100644 proxy/hdrs/HTTP.h create mode 100644 proxy/hdrs/HdrHeap.cc create mode 100644 proxy/hdrs/HdrHeap.h create mode 100644 proxy/hdrs/HdrTSOnly.cc create mode 100644 proxy/hdrs/HdrTest.cc create mode 100644 proxy/hdrs/HdrTest.h create mode 100644 proxy/hdrs/HdrToken.cc create mode 100644 proxy/hdrs/HdrToken.h create mode 100644 proxy/hdrs/HdrUtils.cc create mode 100644 proxy/hdrs/HdrUtils.h create mode 100644 proxy/hdrs/HttpCompat.cc create mode 100644 proxy/hdrs/HttpCompat.h create mode 100644 proxy/hdrs/MIME.cc create mode 100644 proxy/hdrs/MIME.h create mode 100644 proxy/hdrs/Makefile.am create mode 100644 proxy/hdrs/Makefile.in create mode 100644 proxy/hdrs/URL.cc create mode 100644 proxy/hdrs/URL.h create mode 100644 proxy/hdrs/load_http_hdr.cc create mode 100644 proxy/hdrs/test_header.cc create mode 100644 proxy/hdrs/test_urlhash.cc create mode 100644 proxy/http/HttpAccept.cc create mode 100644 proxy/http/HttpAccept.h create mode 100644 proxy/http/HttpBodyFactory.cc create mode 100644 proxy/http/HttpBodyFactory.h create mode 100644 proxy/http/HttpCacheSM.cc create mode 100644 proxy/http/HttpCacheSM.h create mode 100644 proxy/http/HttpClientSession.cc create mode 100644 proxy/http/HttpClientSession.h create mode 100644 proxy/http/HttpConfig.cc create mode 100644 proxy/http/HttpConfig.h create mode 100644 proxy/http/HttpConnectionCount.cc create mode 100644 proxy/http/HttpConnectionCount.h create mode 100644 proxy/http/HttpDebugNames.cc create mode 100644 proxy/http/HttpDebugNames.h create mode 100644 proxy/http/HttpMessageBody.cc create mode 100644 proxy/http/HttpMessageBody.h create mode 100644 proxy/http/HttpPages.cc create mode 100644 proxy/http/HttpPages.h create mode 100644 proxy/http/HttpProxyServerMain.cc create mode 100644 proxy/http/HttpProxyServerMain.h create mode 100644 proxy/http/HttpSM.cc create mode 100644 proxy/http/HttpSM.h create mode 100644 proxy/http/HttpServerSession.cc create mode 100644 proxy/http/HttpServerSession.h create mode 100644 proxy/http/HttpSessionManager.cc create mode 100644 proxy/http/HttpSessionManager.h create mode 100644 proxy/http/HttpTransact.cc create mode 100644 proxy/http/HttpTransact.h create mode 100644 proxy/http/HttpTransactCache.cc create mode 100644 proxy/http/HttpTransactCache.h create mode 100644 proxy/http/HttpTransactHeaders.cc create mode 100644 proxy/http/HttpTransactHeaders.h create mode 100644 proxy/http/HttpTunnel.cc create mode 100644 proxy/http/HttpTunnel.h create mode 100644 proxy/http/HttpUpdateSM.cc create mode 100644 proxy/http/HttpUpdateSM.h create mode 100644 proxy/http/HttpUpdateTester.cc create mode 100644 proxy/http/Makefile.am create mode 100644 proxy/http/Makefile.in create mode 100644 proxy/http/README.via create mode 100644 proxy/http/TestHttpTransact.cc create mode 100644 proxy/http/TestUrl.cc create mode 100644 proxy/http/remap/AclFiltering.cc create mode 100644 proxy/http/remap/AclFiltering.h create mode 100644 proxy/http/remap/Makefile.am create mode 100644 proxy/http/remap/Makefile.in create mode 100644 proxy/http/remap/RemapPluginInfo.cc create mode 100644 proxy/http/remap/RemapPluginInfo.h create mode 100644 proxy/http/remap/RemapPlugins.cc create mode 100644 proxy/http/remap/RemapPlugins.h create mode 100644 proxy/http/remap/RemapProcessor.cc create mode 100644 proxy/http/remap/RemapProcessor.h create mode 100644 proxy/http/remap/StringHash.cc create mode 100644 proxy/http/remap/StringHash.h create mode 100644 proxy/http/remap/Trie.h create mode 100644 proxy/http/remap/UrlMapping.cc create mode 100644 proxy/http/remap/UrlMapping.h create mode 100644 proxy/http/remap/UrlMappingPathIndex.cc create mode 100644 proxy/http/remap/UrlMappingPathIndex.h create mode 100644 proxy/http/remap/UrlRewrite.cc create mode 100644 proxy/http/remap/UrlRewrite.h create mode 100644 proxy/http/stats.memo create mode 100644 proxy/http/test_http_client.pl create mode 100644 proxy/http/test_proxy.pl create mode 100644 proxy/http/test_socket_close.cc create mode 100644 proxy/http/testheaders.cc create mode 100644 proxy/ink_icon.ico create mode 100644 proxy/issues.txt create mode 100644 proxy/logcat.cc create mode 100644 proxy/logging/Log.cc create mode 100644 proxy/logging/Log.h create mode 100644 proxy/logging/LogAccess.cc create mode 100644 proxy/logging/LogAccess.h create mode 100644 proxy/logging/LogAccessHttp.cc create mode 100644 proxy/logging/LogAccessHttp.h create mode 100644 proxy/logging/LogAccessICP.cc create mode 100644 proxy/logging/LogAccessICP.h create mode 100644 proxy/logging/LogAccessTest.cc create mode 100644 proxy/logging/LogAccessTest.h create mode 100644 proxy/logging/LogBuffer.cc create mode 100644 proxy/logging/LogBuffer.h create mode 100644 proxy/logging/LogBufferSink.h create mode 100644 proxy/logging/LogCollationAccept.cc create mode 100644 proxy/logging/LogCollationAccept.h create mode 100644 proxy/logging/LogCollationBase.h create mode 100644 proxy/logging/LogCollationClientSM.cc create mode 100644 proxy/logging/LogCollationClientSM.h create mode 100644 proxy/logging/LogCollationHostSM.cc create mode 100644 proxy/logging/LogCollationHostSM.h create mode 100644 proxy/logging/LogConfig.cc create mode 100644 proxy/logging/LogConfig.h create mode 100644 proxy/logging/LogConfigCollation.cc create mode 100644 proxy/logging/LogField.cc create mode 100644 proxy/logging/LogField.h create mode 100644 proxy/logging/LogFieldAliasMap.cc create mode 100644 proxy/logging/LogFieldAliasMap.h create mode 100644 proxy/logging/LogFile.cc create mode 100644 proxy/logging/LogFile.h create mode 100644 proxy/logging/LogFilter.cc create mode 100644 proxy/logging/LogFilter.h create mode 100644 proxy/logging/LogFormat.cc create mode 100644 proxy/logging/LogFormat.h create mode 100644 proxy/logging/LogFormatType.h create mode 100644 proxy/logging/LogHost.cc create mode 100644 proxy/logging/LogHost.h create mode 100644 proxy/logging/LogLimits.h create mode 100644 proxy/logging/LogObject.cc create mode 100644 proxy/logging/LogObject.h create mode 100644 proxy/logging/LogSock.cc create mode 100644 proxy/logging/LogSock.h create mode 100644 proxy/logging/LogStandalone.cc create mode 100644 proxy/logging/LogUtils.cc create mode 100644 proxy/logging/LogUtils.h create mode 100644 proxy/logging/Makefile.am create mode 100644 proxy/logging/Makefile.in create mode 100644 proxy/logstats.cc create mode 100644 proxy/mime.types create mode 100644 proxy/msgs/TSMessages.mc create mode 100644 proxy/msgs/TSMsgs.rc create mode 100644 proxy/regression.pl create mode 100644 proxy/sac.cc create mode 100644 proxy/signals.cc create mode 100644 proxy/signals.h create mode 100644 proxy/stats/CoupledStats.cc create mode 100644 proxy/stats/CoupledStats.h create mode 100644 proxy/stats/Makefile.am create mode 100644 proxy/stats/Makefile.in create mode 100644 proxy/stats/Stats.cc create mode 100644 proxy/stats/Stats.h create mode 100644 proxy/test_xml_parser.cc create mode 100644 proxy/ts_resource.h create mode 100644 rc/Makefile.am create mode 100644 rc/Makefile.in create mode 100644 rc/solaris.txt create mode 100644 rc/start_traffic_shell create mode 100644 rc/trafficserver.conf.in create mode 100644 rc/trafficserver.in create mode 100644 rc/trafficserver.xml.in create mode 100644 tools/Makefile.am create mode 100644 tools/Makefile.in create mode 100755 tools/apichecker.pl create mode 100755 tools/push.pl create mode 100755 tools/tsxs.in diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..461c9f51 --- /dev/null +++ b/.gitignore @@ -0,0 +1,102 @@ +*.o +*.a +*.so +*.in +*~ +*.tar.gz +*.lo +*.la + +.deps + +!doc/Doxyfile.in + +/aclocal.m4 +/autom4te.cache +/build-aux +/configure +/tags + +build/aux/ +build/libtool.m4 +build/ltoptions.m4 +build/ltsugar.m4 +build/ltversion.m4 +build/lt~obsolete.m4 + +Makefile +config.log +config.status +config.nice +config.h +doc/Doxyfile +doc/html/ +doc/warn.log + +lib/ts/ink_autoconf.h +lib/ts/ink_config.h +lib/ts/stamp-h1 +lib/ts/CompileParseRules +lib/ts/ParseRulesCType +lib/ts/ParseRulesCTypeToLower +lib/ts/ParseRulesCTypeToUpper +lib/ts/mkdfa +lib/ts/test_List +lib/ts/test_arena +lib/ts/test_atomic +lib/ts/test_freelist +lib/ts/test_Map +lib/ts/test_Vec +proxy/config/records.config.default +proxy/config/storage.config.default + +mgmt/api/remote/traffic_api_cli_remote +mgmt/tools/traffic_mcast_snoop +mgmt/tools/traffic_net_config +mgmt/tools/traffic_shmem_clean +mgmt/tools/traffic_time_config +mgmt/tools/traffic_vip_config +mgmt/api/remote/api_cli_remote +mgmt/cli/traffic_line +mgmt/cli/traffic_shell +mgmt/tools/shmem_clean +mgmt/traffic_manager +proxy/traffic_logcat +proxy/traffic_logstats +proxy/traffic_sac +proxy/traffic_server + +cop/traffic_cop + +libtool +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 + +rc/trafficserver +rc/update_records +rc/trafficserver.xml +rc/trafficserver.conf + +proxy/api/include/ts +proxy/api/ts/ts.h +example/app-template/tsapp +example/app-template/records.config + +*/.libs +*/*/.libs +*/*/*/.libs + +.svn +*/.svn/ + +tsxs + +GPATH +GRTAGS +GSYMS +GTAGS +ETAGS +CTAGS diff --git a/.indent.pro b/.indent.pro new file mode 100644 index 00000000..b0c23ca8 --- /dev/null +++ b/.indent.pro @@ -0,0 +1,29 @@ +-nut +-nbad +-bap +-nbbo +-nbc +-br +-bls +-ce +-ci2 +-cli0 +-cs +-d0 +-di2 +-nfc1 +-nfca +-hnl +-i2 +-ip0 +-l120 +-lp +-npcs +-nprs +-psl +-saf +-sai +-saw +-nsc +-nsob +-nss diff --git a/CHANGES b/CHANGES new file mode 100644 index 00000000..894e18c1 --- /dev/null +++ b/CHANGES @@ -0,0 +1,1090 @@ + -*- coding: utf-8 -*- +Changes with Apache Traffic Server 3.0.5 + *) [TS-1049] TS dead locks on HTTPS POST requires. + Author: Wilson Ho + + *) [TS-1111] fix crash in RangeTransform::handle_event + + *) [TS-1109] stack dump may crash too + + *) [TS-1098] make rc script support Amazon EC2 linux AMI + + *) [TS-1185] fix build issues with clang + + *) [TS-1116] fix build issues with gcc 4.7 + + *) [TS-857] race condition UnixNetVConnection::do_io_close() + + *) [TS-1158] race condition UnixNetVConnection::mainEvent() when handling + an inactivity timeout + + *) [TS-1114] crash from access to CacheVC::write_vector without vol lock. + +Changes with Apache Traffic Server 3.0.4 + *) [TS-1154] quick_filter on HEAD does not work + Author: weijin + + *) [TS-824] Range requests that result in cache refresh give 200 status + response with full contents. Review and suggestions for improvements + by Charlie Gero. + + *) [TS-880] Major performance problem with second request on same keep-alive connection + Author: weijin + + *) [TS-1110] logstats incorrectly bucketizes all status codes greater + than 599 as 5xx + + *) [TS-1065] Traffic Cop: segment fault when TRACE_LOG_COP is enabled + Author: Conan Wang + + *) [TS-948] do not reload bad remap.config + + *) [TS-845] make proxy.config.cluster.ethernet_interface default to + loopback interface: lo on linux and lo0 on bsd derivatives + +Changes with Apache Traffic Server 3.0.3 + + *) [TS-876] forward map based on request receive port + + *) [TS-1004] Transformation plugins cause connection close when content + length is not known ahead. Author: Otto van der Schaaf. + + *) [TS-1055]: Wrong implementation of TSHttpSsnArgGet(). + Author: Yakov Kopel + + *) [TS-1074] PluginVC should schedule to the local queue instead of the + external queue. + + *) [TS-1066] TSHttpTxnServerReqHdrBytesGet in InkAPI.cc has an extra + parameter (int *bytes) from the prototype in . + Author: Alistair Stevenson + + *) [TS-874] make asf-dist work with git repo + + *) [TS-1038] SHttpTxnErrorBodySet() can leak memory. + + *) [TS-1095] ts.h.in has incorrect declaration for TSFetchURL + + *) [TS-1014] slow log can not print logs well on 32-bit system, + changed the %d to RPI64. Author: weijin. + + *) [TS-830] Better error when there are CLI permission problems, or + other problems preventing operation. Author: AdunGaos. + + *) [TS-1046] Add possibility to extend tsxs command line for -Iincludes. + + *) [TS-1047] fix lots of spelling mistakes + Author: Arno Töll + +Changes with Apache Traffic Server 3.0.2 + *) [TS-1030] Improve hashing mechanism on WKS. + + *) [TS-1011]: SSL doesn't work on Solaris. + + *) [TS-1028] Avoid triggering assert when running debug build and enabling + per-thread connection pols + + *) [TS-1021] Remove extra newline from binary logs. + + *) [TS-1013]: Allow ssl_multicert.config to support CA chains per host + + *) [TS-944]: ssl.server.cert.path & ssl.server.private_key.path do not work as expected + + *) [TS-906]: We do not honor / use the configuration option for + proxy.config.http.forward.proxy_auth_to_parent. + + *) [TS-967]: Allow for our default -O3 options to be overriden via CFLAGS/CXXFLAGS + Author: Arno Toell and igalic + + *) [TS-969] tests failing on some Debian sid and Solaris + + *) [TS-867] PluginVC crashes with TSFetchURL + + *) [TS-901] Valgrind found minor leaks and uninitialized variables + Author: William Bardwell + + *) [TS-916] TSHttpIsInternalRequest() crashes if client connection is + terminated prematurely. + Author: Manjesh Nilange + + *) [TS-882] traffic_logstats dies when printing log. + + *) [TS-883] traffic_logstats provides conflicting help output + + *) [TS-730] Allow for the SSL Cipher Suite to be configured + + *) [TS-927] don't use malloc.h, it fails on FreeBSD + Author: Radim Kolar + + *) [TS-888] fix SSL by enabling the right direction on successful setup + + *) [TS-859] ATS requesting to origin instead to the parent server + +Changes with Apache Traffic Server 3.0.1 + *) [TS-842] remove uninstall target from build system + + *) [TS-868] build fails with --as-needed. Author: Ilya Barygin. + + *) [TS-860] Built in error for host not found looks like Internet Explorer + error. Author: William Bardwell + + *) [TS-875]: TSFetchRestpGet(), TSFetchPageResptGet() and TSFetchUrl() have + incorrect asserts. Author: Manjesh Nilange + + *) [TS-834] InactivityCop::check_inactivity crash + + *) [TS-826] TSHttpTxnErrorBodySet() can leak memory. + Author: William Bardwell + + *) [TS-833] Continuation::handleEvent deadbeef fix. This fixes most of the + dns related crashes + + *) [TS-828]: Various memory leaks and uninitialized values. + Author: William Bardwell + + *) [TS-839] Build problems when specifying lmza location. + + *) [TS-840] Regression checks fail (again) due to faulty assert use. + Author: Arno Toell. + + *) [TS-847] Bad timeout when using CONNECT method. + + +Changes with Apache Traffic Server 3.0.0 + *) [TS-827] TSMimeHdrFieldValueStringInsert() can use freed memory to + edit headers. Author: William Bardwell. + + *) [TS-825] negative caching caches responses that should never be + cached: Author: William Bardwell. + + *) [TS-820] Restore log buffer size to previous defaults. + + *) [TS-818] Assertion/abort when starting TS with SOCKS proxy enabled. + Author: Yakov Markovitch + + *) [TS-810] Typo in switch statement + slight improvement. + + *) [TS-809] ts.h broken when compiling C plugins. + + *) [TS-798] We add broken remap rules when we encounter parse errors of + remap.config. + + +Changes with Apache Traffic Server 2.1.9 + *) [TS-805] HostDB wastes a lot of storage for round-robin entries, + and the calculations of size are off. + + *) [TS-806] TS_ADDTO removes duplicates, so avoid this by using the + -R option to libtool + + *) [TS-793] Improve print statements for ink_freelist debugging. + + *) [TS-679] The external API was changed to make it IPv6 compliant + (although it doesn't actually work with IPv6). Old API functions + were deprecated but not removed. + + *) [TS-797] Wrong delete used in stats processor. + + *) [TS-769] Fixed infinite loop when getting a 505 response from the + origin and the connection is keep-alive. Now downgrading keep-alive + all the time along with the protocol. + + *) [TS-788] Cleaned up the request and response cacheable apis. + + *) [TS-792] Add a config option (disabled by default) to support + mlock() and mlockall(). + + *) [TS-783] Port ATS to IA64. Author: Arno Toell. + + *) [TS-778] Compile Fails on Solaris 10 (gcc). Author: Igor Brezac. + + *) [TS-404] Add a new API, TSOSIpSet() which allows you to bypass the + origin server DNS lookup. + + *) [TS-791] Remove ShmemClean.cc, it's no longer needed. + + *) [TS-786] Add a perl module to edit a records.config configuration + file. + + *) [TS-779] Set thread name for various event types. + + *) [TS-784] Don not use class allocator for remap processing when no + remap threads are enabled. + + *) [TS-782] Remap processor creates a remap thread even when asked not + to. + + *) [TS-781] Cleanup of unusual configs, and better defaults making + records.config leaner, and a little more useful. + + *) [TS-780] Retune the number of SSL threads. + + *) [TS-775] Disable cluster autodiscovery via multicast when + clustering is disabled. This should hopefully fix run-time errors + with Ubuntu 11.x. + + *) [TS-776] memchr in glibc has evolved, and is faster than our + version, replaced. + + *) [TS-774] Add a new configure option, --enable-static-libts, which + avoids the dynamic linking hassles involved with the dynamic nature + of libts. This is for devs only. + + *) [TS-773] Traffic server has a hard limit of 512 gigabytes per RAW + disk partition. This fix required changing the disk structure which + will result in a total disk cache clear (wipe) after upgrading. + + *) [TS-772] Make proxy.config.http.doc_in_cache_skip_dns overridable. + + *) [TS-770] proxy.config.http.doc_in_cache_skip_dns is not being read + from records.config. Author: Yakov Markovitch + + *) [TS-738] 'make check` fails on x86. + + *) [TS-771] Remove remaining v1 log buffer code. + + *) [TS-562] Make --with-openssl path be honored with an -rpath to + libtool. This also fixes the same problem with other libraries, + e.g. pcre, zlib etc. + + *) [TS-765] Make the backdoor port (8084 by default) only listen on + 127.0.0.1 . + + *) [TS-762] Range values like -10 are processed. Author: William + Bardwell. + + *) [TS-761] Fixed bug where 3 (or more) remap plugins in a chain + couldn't be loaded. + + *) [TS-763] When creating multiple SSL accept threads, we use the + wrong instantiator. + + *) [TS-757] Change TSNetAccept() API to take an option for enabling + (and number of) accept threads. + + *) [TS-759] Makefile in proxy/config handles $DESTDIR incorrectly. + Author: Arno Toell + +Changes with Apache Traffic Server 2.1.8 + *) [TS-750] TS does not fail-over if one origin server for a 2 address + hostname. Author: William Bardwell. + + *) [TS-752] If you cancel a scan really quickly you can get a NULL + dereference. Also other important performance and correctness fixes + for the cache scanning code. Author: William Bardwell and jplevyak. + + *) [TS-749] Connection hangs if origin server goes down in the middle of + a response. Author: William Bardwell. + + *) [TS-753] TS-753 Some more cleanup in InkAPI, move a few experimental + APIs to ts.h + + *) [TS-751] Experimental TSHttpTxnCacheLookupStatusSet(HIT_STALE) calls + cause a crash. Author: William Bardwell + + *) [TS-748] Client side transparency doesn't work on trunk. + + *) [TS-702] FATAL: MIME.cc:1250: failed assert `j < block_count`. + Author: Yakov Markovitch + + *) [TS-746] Allow to remove URL fields with "NULL" (or 0) values. + + *) [TS-744] Configurations to control SSL session reuse and cache + size. Authors: qianshi and Leif + + *) [TS-716] Bug where NetVC could be double free'd. + Fix for DNS crash: bad memory management of HostEnt structures. It is + not clear that this fixes the bug entirely. Some of the stack traces + are consistent with this bug, but some are not. + + *) [TS-743] Support separate configs for keep-alive enabled for _in + and _out connections. + + *) [TS-741] traffic_manager handles sockets incorrectly. + + *) [TS-742] assert triggered wrongly (in debug builds). + + *) [TS-740] Traffic Server fails to build on kfreebsd. + Author: Arno Toell. + + *) [TS-737] Small hackish fix for rc/trafficserver.in so rc/trafficserver + will work with FreeBSD. Author: G Todd. + + *) [TS-735] Disable ccache by default, use with --enable-ccache. + + *) [TS-734] Remove unused fields in net stats pages. + + *) [TS-212] Startup service support for Solaris. Author: Igor Brezac. + + *) [TS-629] fix some non-portable char == unsigned char assumptions. + + *) [TS-621] Update records.config.default.in with changed / removed + configs. + + *) [TS-641] Remove a bunch of Web UI related configs and code. + + *) [TS-719] libtsutil.so is not self-contained. + Author: Igor Brezac. + + *) [TS-729] Fix bugs with Via Headers handling. (Note: This is + unlikely to have caused the crash the bug report) + Author Leif Hedstrom + + *) [TS-721] Incorrect http hit ratio in stats. + This also removes a number of obsoleted stats and also disables + stats aggregation in WebOverview.cc, one more nail to WebUI's + grave. Author: Leif Hedstrom + + *) [TS-728] Remove the --enable-webui option, since it doesn't + produce a running webui anyway. Also remove html2 + + *) [TS-685] Rename partition.config because it doesn't have + anything todo with disks. Also rename all code related to it + so as not to confuse anybody. + + *) [TS-714] Fix traffic_shell hanging on every command + + *) [TS-562] Fix TCL linking to honor custom library dirs. + Author: Eric Connell. + + *) [TS-624] make install should not overwrite etc/trafficserver/. + Author: Eric Connell. + + *) [TS-465] Allow for existing Server: string to not be overwritten. + This adds a new semantic for the value "2" to this option. + + *) [TS-633] Fix reverse mapping with different schemes. + Author: Andreas Hartke. + + *) [TS-715] Fixes and cleanup for Perl client. Author: Billy Vierra. + + *) TS-550 Remove an unused / unsupported debug tool. Also update the + remap code to use our standard linked list (Queue in this case). + + *) [TS-704] Link traffic_server dynamically to make distros happy, + since --disable-static will work. + + *) [TS-545] Clean out more cruft from MIXT legacy. + + *) [TS-713] Honor the offset within do_io_pread. + + *) [TS-712] Fix compile problems with clang / llvm + + *) [TS-545] parent.config (and perhaps other configs) have an unused + concept of "tags" for MIXT media. Cleanup remaining MIXT junk. + +Changes with Apache Traffic Server 2.1.7 + *) [TS-711] Don't schedule remap.config reloads on a network threads. + We now schedule this task on an ET_TASK thread, which avoids blocking + a net-thread for several seconds (when reloading very large remaps). + + *) [TS-710] Do not dlopen / reload a remap plugin .so more than once. + + *) [TS-588] Change Remap plugin APIs to use URL TSMLoc, and normal + ts/ts.h APIs for getting and setting components. + + *) [TS-708] TsConfig doesn't handle backslashes correctly. + + *) [TS-209] add support for raw disk on Solaris: credits: Igor Brezac + for both the code and testing! + + *) [TS-705] Fixes for compiling with gcc v4.6. + + *) [TS-706] hardware sector size's over 8K current report an Error + but are passed through resulting in lots of disk waste. + + *) [TS-707] The random number generator from 1-23-2011 is using the + same seed for all threads = collisions in the cache + + *) [TS-700] Need additional controls in cache.config. + + *) [TS-696] make check fails on libtsutil due to missing libresolv + and librt. Author: Eric Connell. + + *) [TS-691] LogFilter not working for "int" types. + Author: Eric Connell. + + *) [TS-692] Add an experimental API to modify the outgoing IP address. + + *) TS-676: logic in Store::clear and Store::read_config is wrong. + Author: mohan_zl. + + *) [TS-680] Change many typedef void* types to anonymous structs. + + *) [TS-690] Schedule some callbacks on the ET_TASK threads + + *) TS-689 Restore TSMgmtUpdateRegister() to the SDK APIs. + + *) [TS-550] Remove MgmtPlugin.{cc,h}. + + *) [TS-657] Proper validation of RWW settings on startup. + + *) [TS-688] Remove the "tag" modifier from parent.config. + + *) [TS-682] Segfault when partition.config is used. + + *) [TS-687] Build failures on FreeBSD8 + + *) [TS-684] config.layout for gentoo linux, may also be used on Fedora + + *) [TS-675] Make redirect and reverse maps work again. + + +Changes with Apache Traffic Server 2.1.6 + + *) [TS-678] Add a config option for try-lock retry delay. + + This adds a configuration option + + proxy.config.cache.mutex_retry_delay INT 2 + + 2ms seems to be fairly optimal, with little detrimental effect on CPU + usage. We'll fine tune this further in the next release. + + *) [TS-674] Fixes for cache.config and the "modifiers" to work. + + *) [TS-641] Remove inktomi*.css and some files only referenced by it. + Removing mgmt/html2/charting. Remove the now empty mgmt/html2/tune. + + *) [TS-590] Cleanup all SDK APIs to be more consistent. This changes a + large number of APIs, so please check updated docs and signatures in + ts/ts.h. A new tools, tools/apichecker.pl, can be used to help + identifying areas in existing plugins that might need changes. + + *) [TS-673] Make the default configurations more conservative + for when content is cacheable. + + *) [TS-672] Remove unused/unreferenced Win32 header files and + code paths + + *) [TS-671] Detect install group based on install user. + + *) [TS-644] Fix clustered cache pages crash. + + *) [TS-651] Clear all stats when we ask to clear the local stats. + + *) [TS-489] Remove the "connection collapsing" feature, it was poorly + implemented, and caused major problem if enabled. We should redo this + for v3.1 in a way that fits with the HttpSM [author: mohan_zl]. + + *) [TS-668] Add support for URL stats to traffic_logstats. + + *) [TS-665] Remove HTTP_ASSERT from the code base, use standard asserts. + + *) [TS-663, TS-664] Fixes to WCCP with mask assignments, and trunk build + problems. + + *) [TS-662] Make per partition stats for bytes_used work. + + *) [TS-661] Delay the copy of per transaction configs until a plugin + actually tries to modify a setting. We also add these settings to the + list of configurations that is overridable: + + proxy.config.http.cache.max_open_read_retries + proxy.config.http.cache.open_read_retry_time + + *) [TS-660] Cache scan can not be canceled. + + *) [TS-505, TS-506] Changed the defaults to deal with read contention on + the cache, this dramatically improves the performance on cache misses. + + *) [TS-655] Reorganize some code to reduce binary foot prints. + + *) [TS-653] Bogus logcat conversion of squid timestamps. + + *) [TS-643] Unable to purge objects on other servers in full cluster mode. + + *) New 64-bit random generator. + + *) [TS-639] Rename the management APIs from INK* to TS*. + + *) [TS-650] Remove the dead v2 stats code. + + *) [TS-649] Dynamic libraries for mgmt APIs. + + This makes libts -> libtsutil, and we now support making .so's for + libtsutil.so and libtsmgmt.so. All binaries are changed to use this, + except traffic_server which continues to use the libtsutil.a library + (for performance on e.g. 32-bit platforms). + + This also renames the public API include file to be + + #include + + + *) [TS-647] Move Layout out of iocore and into lib/ts. + + *) [TS-638] Rename various directories: + proxy/mgmt -> mgmt/ + proxy/mgmt/cop -> cop/ + + All "cli" APIs are now also migrated into mgmt/cli, unified into one + single cli. + + *) [TS-641] Cleanup of Web2/HTML2. + + *) [TS-636, TS-637] Remove various unused source files. + + *) [TS-631] Rename proxy/http2 -> proxy/http and proxy/mgmt2 to proxy/mgmt. + + *) [TS-582] Add an example to records.config for how to bind a specific IP. + + *) [TS-491] Cluster port was activated even with clustering disabled. This fix also + adds monitoring support for the "cli" unix domain socket. + + *) [TS-593] Cleanup of inktomi.com. + + *) [TS-324] Cleaning up some old TCL files and dependencies. + + *) Remove traces of FTP references [TS-324] by purging the now useless TCL + bindings to it. + + *) [TS-513] Fix configure issues for sqlite3. This fix eliminates all of + SimpleDBM, sqlite3 and bdb dependencies. It also fixes the "make + distclean" problem, and clean things up a bit. + + *) [TS-491] Add the CLI interface to Traffic Cop, and make it possible to + run traffic_manager without listening on the cluster port. + + *) [TS-583] Build fails if --disable-webui is added. + + *) [TS-618] Removing traces of CCAS/CCASFLAGS. + + *) [TS-627] Fixes for "make check" to succeed (author: Arno Toell). + + *) [TS-632] Fixes for bad cast and cleanup for Intel CC. + + +Changes with Apache Traffic Server 2.1.5 + + *) More 64-bit issues has been identified in the SDK and HTTP core, and + fixed [TS-620]. + + *) Code cleanup of old transparency code and options [TS-613]. + + *) We now require a compiler (or libc) that provides atomic + operations. This includes gcc 4.1.2 or later, Intel CC, clang (recent + versions) as well as Sun's Solaris compilers and libc [TS-618]. + + *) Support normal default path for remap plugins [TS-616]. + + *) Change default settings for MSIE User-Agent sniffing [TS-615]. + + *) Remove remnants from InktoSwitch. This removes the following + configurations [TS-614]: + + proxy.config.http.inktoswitch_enabled + proxy.config.http.router_ip + proxy.config.http.router_port + + *) Modify TSContSchedule to take a thread type, and add + TSContScheduleEvery [TS-589]. + + *) Added support to allow some select (~50 or so) records.config + configurations to be overridable per transaction. This is done via new SDK + APIs, as well as a remap plugin provided with the core [TS-599]. The new + APIs available are + + TSHttpTxnConfigIntSet() + TSHttpTxnConfigIntGet() + TSHttpTxnConfigFloatSet() + TSHttpTxnConfigFloatGet() + TSHttpTxnConfigStringSet() + TSHttpTxnConfigStringGet() + TSHttpTxnConfigFind() + + *) Eliminate dedicated default DNS for SplitDNS [TS-597]. Author: Zhao + Yongming. + + *) Eliminate proxy.config.net.max_poll_delay configs [TS-605]. + + *) Old traffic_net configurations are eliminated [TS-601]. + + *) Multiple preads: this patch is only active if you call do_io_pread on + the cache. This includes a regression test for do_io_pread which is at + least a smoke test of the new code. [TS-61] + + *) Migrate from home-grown regular expression classes to pcre [TS-604] + + *) Reduce number of calls to regex matcher for standard requests with + well-known-strings (WKS). [TS-603] + + *) Parse Range: requests a bit better. Prior, a request like like Range: + bytes=100-200 would return 0-200. Additionally, Range: bytes=100- would + not parse properly. [TS-596] + + *) Remove old, unused configuration code (duplicated) [TS-576]. + + *) Bump the SDK version numbers properly [TS-595]. + + *) Migrate from our own int64 (et.al) to int64_t / stdint types. This also + changes the SDK, so ts/ts.h users should now use int64_t etc. [TS-594]. + + *)./configure will now tell us more about its defaults. + + *) Add better tests for eventfd, making sure sys/eventfd.h exists + [TS-515]. + + *) Stub / base implementation for the Task thread pool [TS-589]. + + *) Cleanup of traffic_logstats, and also add support for JSON + output. Several new options and query args added to select output format + and data [TS-587]. + + *) Add back support for using the default DNSHandler from DNS.cc This + helps with SplitDNS [TS-580]. + + *) Fixes for DNS to properly schedule and initialize [TS-570]. + + *) Fix make check so it actually compiles [TS-586]. + + *) Remove RAF pieces [TS-584]. + + *) Replace the SDKAllocator with a ClassAllocator [TS-577]. + + This reduces the amount of memory allocation for plugins, but requires + that plugins now religiously release the handles that they are expected + to release (i.e. no automatic gc is done for lazy developers). + + + *) Fixes for getting the altinfo regression check to succeeds [TS-171]. + + *) Fixes for some transform, and other, mismatches of int vs int64 in the + new APIs and underlying cache [TS-456]. + + *) Eliminate misguided string copies in the SDK [TS-579]. + + *) Fix build of ts.h and tsxs when the .in files changes [TS-574]. + + *) Move libinktomi++ and librecords to lib/ts and lib/records [TS-571]. + + *) Add SDK API calls to directly get the elements of the running TS + version [TS-568]. + + *) Added WCCP support. + + *) Bring IPv6 functionality back to trunk, for incoming (client) + connections [TS-18]. Original author: Tsunayoshi Egawa. + + *) Segfault with HTTPS, fixed by correctly initializing SSLNetVConnection + being added to freelist [TS-559]. + + *) The old logs.config custom log format is no longer supported. Only the + XML custom logs are now supported. This eliminates the config + + proxy.config.log.xml_logs_config + + as well, since it's the only option for custom logs [TS-556]. + + *) All log configurations (and stats) are renamed from log2.* to + log.*. This is to avoid confusion, since Apache Traffic Server never had + the old (obsolete) log system. There's now only one log system, log + [TS-555]. + + *) Many fixes and improvements on the Stats pages subsystem. This now + properly supports (if configured) various internal URLs, like + http://{net}, http://{hostdb} etc. [TS-554]. + + *) The NewCacheVC is removed [TS-551]. + + *) Support for the Alpha processor is eliminated [TS-552]. + + *) A number of unecessary memory allocations are removed, improving + performance under heavy load. [TS-550, TS-549] + + *) All streaming media (MIXT) configurations are now properly removed from + code and default configs [TS-544]. + + *) URL scheme was case sensitive in the cache key [TS-474]. + + *) Fixes for broken API signatures, additions / modifications to the + following API: + + TSReturnCode TSHttpTxnArgSet(TSHttpTxn txnp, int arg_idx, void *arg); + TSReturnCode TSHttpTxnArgGet(TSHttpTxn txnp, int arg_idx, void **argp); + TSReturnCode TSHttpSsnArgSet(TSHttpSsn ssnp, int arg_idx, void *arg); + TSReturnCode TSHttpSsnArgGet(TSHttpSsn ssnp, int arg_idx, void **argp); + + TSReturnCode TSHttpArgIndexReserve(const char* name, const char* + description, int* arg_idx); TSReturnCode TSHttpArgIndexNameLookup(const + char* name, int* arg_idx, const char** description); TSReturnCode + TSHttpArgIndexLookup(int arg_idx, const char** name, const char** + description); + + TSReturnCode TSHttpSsnTransactionCount(TSHttpSsn ssnp, int* count); + + This was all combine into [TS-504], but also see [TS-503]. + + *) Many fixes for broken regression tests! + + *) RNI is now completely cleaned out [TS-536]. + + *) Fixes for SplitDNS (co-author: mohan_zl) [TS-435]. + + *) HTTPS to origin servers, with Chunked responses, would hang [TS-540]. + + *) Mismatched APIs using "unsigned char*" [TS-458]. + + *) Rename / modify TSSetCacheUrl() API, the new prototype is + + TSReturnCode TSCacheUrlSet(TSHttpTxn txnp, const char *url, int + length); + + If length == -1, then the API will calculate it using strlen() [TS-520]. + + *) All public APIs, structs and defines are now prefixed with "TS" instead + of the old "INK". There are two exceptions, for the deprecated INKStats* + and INKCoupledStats* APIs [TS-521]. + + *) The hooks around "remap" has been organized, and a new hook as been + added (for post-remap). New / renamed hooks are + + TS_HTTP_PRE_REMAP_HOOK TS_HTTP_POST_REMAP_HOOK + + In addition, a new API was added, to allow a plugin to skip the remap + phase completely: + + TSReturnCode TSSkipRemappingSet(TSHttpTxn txnp, int flag); + + These fixes went in with [TS-529] and [TS-530]. + + *) INKHttpTxnSetHttpRetStatus not honored when an API transaction is + reenabled with INK_EVENT_HTTP_ERROR [TS-535]. + + *) Various defines for version identification has been moved to the public + ts/ts.h include file, e.g. + + #define TS_VERSION_STRING "2.1.6-unstable" + #define TS_VERSION_NUMBER 2001006 + #define TS_VERSION_MAJOR 2 + #define TS_VERSION_MINOR 1 + #define TS_VERSION_MICRO 6 + + The intended use is for plugins to be able to verify available APIs at + compile time (vs the existing runtime checks) [TS-534]. + + *) Traffic Server should now build on ARM processors. Commit message is + appropriately describing the situation with this CPU: + + This is a sad day of defeat. Not my defeat, but more a collective human + defeat. + + Question: "Chips fabricated today don't have 64bit atomic primitives?" + Answer: "Be sad." + + The ARM box we're working on (armv5tejl) doesn't support any 64bit + primitives. + + This means we need a method of using a global (yes, giant lock of death) + to protect modifications of arbitrary 64bit integers in process space. + We could make this less contentious by allocating pagesize/8 mutexs and + then protecting an int64 based on its page offset. Instead, I think we + should mobilize to burn these architectures to the ground and use public + embarrassment to fix future instruction sets. If another platform has + this issue, we'll want to change the define to: + + TS_ARCHITECTURE_LACKS_64BIT_INSTRUCTIONS and turn on the global death + lock based on that. + + This does not change performance on any other platform -- it's compile + time capital punishment. [TS-533] and [TS-135]. + + *) Very old APIs, that have been deprecated since long before the Apache + Open Source project, are removed. Also, only three public include files + are now available: + + ts/ts.h ts/experimental.h ts/remap.h + + Various other cleanup related to the APIs was also done [TS-522]. + + +Changes with Apache Traffic Server 2.1.4 + + *) Fixes to clustering, that caused an assert to trigger after the stats + changes [TS-519]. + + *) Make the checks when to honor the Content-Length: header less strict, + against origins without Keep-Alive [TS-500]. + + *) Eliminate old ssl_ports feature, it's completely replaced with the + connect_ports configuration [TS-517]. + + *) New script available to help build plugins, tsxs [TS-512]. + + *) Simple, brute force (and efficient) status code stats counters + [TS-509]. + + *) Generalize RecDumpRecordsHt to use RecDumpRecords which is a + callback/map pattern [TS-508]. + + *) Fix plugin APIs to be compatible with the 64-bit changes in the + core. This is an incompatible change with previous releases [TS-14]. + + *) Fixes for stats around origin connection counters, used when allowing + for origin connections to be reused between clients [TS-501]. + + *) Experimental supoprt for a dedicated DNS thread. This can be enabled + with the records.config option + + CONFIG proxy.config.dns.dedicated_thread INT 1 + + This feature is possibly useful for very busy forward or transparent + proxies [TS-307]. + + *) Accept threads can leak some amount of memory. This patch also supports + multiple accept threads (very experimental!) [TS-496]. + + *) HttpSM has an assertion that checks the client URL against the cache + URL, which breaks INKSetCacheUrl [TS-495]. + + *) Return value from pcre_exec tested incorrectly [TS-493]. + + *) Improved loop detection using the Via header [TS-490]. + + *) Fixes for Solaris build (yay, it builds!). + + *) Remove filter.config remnants [TS-486]. + + *) Cleanup in InkAPI [TS-485]. + + *) Move PKGSYSUSER to ink_config.h.in [TS-482]. + + *) Unresponsive server can stall ATS [TS-480]. + + *) UrlRewrite cleanup [TS-434]. + + *) Build TS with clang (author: Igor Galic) [TS-427]. + + *) Better support and handling of DNS round-robin options (author: Zhao + Yongming) [TS-313]. + + *) Make it possible to "write" Content-Length headers > 2GB [TS-471]. + + *) Better support for Age: headers, and avoiding overflows [TS-470]. + + *) Added a configure option to size the API stats "slots". The new option + is --with-max-api-stats= [TS-454]. + + *) In Cache.cc, make snprintf() around Debug statements conditional for + performance [TS-459]. + + *) Cleanup / optimize Via: string generation [TS-460]. Also make the + default for Via: on responses to be disabled (it can leak info). + + +Changes with Apache Traffic Server 2.1.3 + + *) Removed the remnants of NCA from the source [TS-455]. + + *) New plugin APIs for stats, and making the "v2" (incomplete) stats + experimental (no longer built by default) [TS-390]. See + https://cwiki.apache.org/confluence/display/TS/NewStatsAPI for more + details. + + *) Cleanup in duplicated configs, and obsoleted configs [TS-447] and + [TS-451]. + + *) Remove some remnants of SNMP [TS-401]. + + *) Cleanup of MIX and LDAP/NTLM remnants [TS-443]. + + *) Make the target fragment size configurable for the disk cache. This + adds a new option, proxy.config.cache.target_fragment_size [TS-445]. + This should dramatically improve large file disk performance. + + *) Improve build include dependencies [TS-442]. + + *) Cleanup / fixes for remap plugin chaining [TS-224]. + + *) Support the rc/trafficserver script for FreeBSD [TS-211]. + + *) traffic_shell shows wrong RAM cache size > 2GB [TS-439]. + + *) Better warnings / errors when bad NIC is configured [TS-327]. + + *) Add support for hardware sector sizes 512 - 8192 bytes (e.g. 4096, the + new standard). Autodetected for raw devices on Linux (no support for + other OSes yet), and added a new configuration + + CONFIG proxy.config.cache.force_sector_size INT 4096 + + This change invalidates the entire cache as well, since it's no longer + compatible [TS-43]. + + *) Added APIs to override the cacheablity of the response [TS-395]. + + *) Add OSX support to 'trafficserver' script (author: Dan Mercer) + [TS-210]. + + *) Fix for (very) large buffers fed to the cache [TS-413]. + + *) Forward transparency is available on Linux kernels with TPROXY + [TS-291]. + + *) Fix defaults / max for DNS retries [TS-424]. + + *) Improvements for Perl admin module (author: Adam Faris) [TS-418]. + + *) Problems with specifying separate config files for SSL certificates and + keys [TS-405]. + + *) Logging: Default settings for diagnostic logging [TS-55]. + + *) Fixes to Debian layout (author: Igor Galić) [TS-415]. + + *) Remove DNS proxy support [TS-422]. + + *) rc/trafficserver start/stop quits with bogus status on success (author: + Igor Galić) [TS-429]. + + *) Increase default max in-flight DNS queries [TS-423]. + + *) Update so the pristine URL will work for reverse and forward proxy. + Also, clearing the url on transaction close (author: Wendy Huang) + [TS-410]. + + *) TS fails to use user ID with user name > 8 characters (author: Yakov + Markovitch) [TS-420]. + + *) Duplication of RAM cache hits and miss statistics (reading 2x) (author: + John Plevyak) [TS-453]. + + +Changes with Apache Traffic Server 2.1.2 + + *) Improvements in resilience against DNS poisoning and forging of + response packets [TS-425] and [CVE-2010-2952]. + + *) Segmentation fault in INKError when error output is made both in error + log and as debug messages (author: Yakov Markovitch) [TS-419]. + + *) Debian layout for config.layout (author: Igor Galic) [TS-415]. + + *) Eliminate extraneous stats thread [TS-411]. + + *) CACHE_FRAG_TYPE is now not a power of 2 [TS-76]. + + *) Remove unnecessary stats update [TS-390]. + + *) Get basic features to compile with Intel CC [TS-400]. + + *) More 64 bit issues, this time in the PluginVC code [TS-380]. + + *) Add configure option to enable detailed logging [TS-392]. + + *) Make sure to honor user settings for "dirs" (author: Theo Schlossnagle) + [TS-399]. + + *) Errors on failing to bind / listen on a specified port [TS-247]. + + *) Exempt quick filter for 127.0.0.1 [TS-397]. + + *) Cleanup after "layout changes" (author: Zhao Yongming) [TS-389]. + + *) Fix remaining (non-API) INK64 etc. [TS-365]. + + *) Segfault when using show:network [TS-109]. + + *) Update all examples to use non-deprecated APIs [TS-266]. + + *) Do some cleanup on Connection::fast_connect and + Connection::bind_connect (author: Alan M. Carrol) [TS-320]. + + *) Remove LLONG config option [Ts-364]. + + *) Cleanup some proxy/mgmt2/tools [TS-16]. + + *) Cleanup a little more of webui [TS-91]. + + *) TCL missing [TS-326]. + + *) logstats does not work with layout changes (author: Zhao Yongming) + [TS-385]. + + *) Convert bogus IOCORE_MachineFatal and IOCORE_ProcessFatal to Warning + and MachineFatal respectively based on review of the code and related + uses [TS-144]. + + *) INKIOBufferReaderCopy, INKIOBufferWrite should take void * instead of + char * [TS-67]. + + *) Adds APIs for aio disk read and writes using the internal aio support + in iocore (author: Wendy Huang) [TS-387]. + + *) Solaris 10 (x86) 64-bit patch (author: Igor Brezac) [TS-388]. + + *) Fix for 64-bit conversion [TS-385]. + + *) Creating transaction specific 'to URL' in case of regex remap match + [TS-384]. + + *) Backing out m_capacity_host changes [TS-383] + + *) Solaris 10 port work. + + +Changes with Apache Traffic Server 2.1.1 + + *) Allow SI decimal multipliers for numeric configuration parameters + [TS-361]. + + *) Standardize configure options by allowing to specify the location for + any third-party library, and split library detection code into separate + .m4 files [TS-345]. + + *) Reorganization of the path layout system. Add --enable-layout=LAYOUT + configure option that can select layout from config.layout file + [TS-280]. + + *) HTTP state machine is now 64-bit "clean", allowing for caching and + proxying documents larger than 2GB [TS-34]. + + *) Fix for truncated Content-Type on TS-generated responses [TS-290]. + + *) Performance improvements on cache for larger(ish) objects. + + +Changes with Apache Traffic Server 2.1.0 + + *) Support for many more platforms, including FreeBSD, MacOSX and Solaris. + + *) Code cleanup to get the ATS software into a distributable shape. This + means that certain things are missing, or not functional (intentionally). + + *) Support for larger Cache Partitions up to .5 PB (Petabytes), reducing + seeks/write. + + *) Reduced Cache miss latency (sub millesecond). + + *) RAM Cache pluggability, new algorithm (CLFUS) and optional compression. + + *) Support for TCL v8.6 and later [TS-246]. + + *) The cache is now 64-bit "clean". + + +Changes with Apache Traffic Server 2.0.1 + + *) Port of CVE-2010-2952 for 2.0.x [TS-425]. + + *) Backport part of TS-322 that deals with indexing arrays with char + (author: Marcus Ruckert) [TS-334]. + + *) Backport TS-336 to 2.0.x. Problems with make install DESTDIR=... + + +Changes with Apache Traffic Server 2.0.0 + + *) Change SDK versioning schemes to 2.0 [TS-249). + + *) Minor additions to the SDK (see the docs for details). + + *) Support regexe_map rules in remap.config [TS-80] + + +Changes with Apache Traffic Server 2.0.0-alpha + + *) Code cleanup to get the ATS software into a distributable shape. This + means that certain things are missing, or not functional (intentionally). + + *) Ports available for most Linux distros, including 64-bit. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..48d9bd0f --- /dev/null +++ b/INSTALL @@ -0,0 +1,72 @@ +APACHE TRAFFIC SERVER INSTALLATION + + Quick Start - Unix + ----------------- + + For complete installation documentation, see the on-line documentation at + + http://trafficserver.apache.org/docs.html + + Configure & Build: + Source (SVN) + $ autoreconf -i # generate the configure script and Makefile.in files + + On Linux, OSX and FreeBSD: + $ ./configure [--prefix=PREFIX] + $ make + + On OpenSolaris: + $ ./configure [--prefix=PREFIX] CC=/usr/bin/gcc-4.3.2 CXX=/usr/bin/g++-4.3.2 + $ make + + Next set the cluster interface in 'records.config' + On Linux: e.g + CONFIG proxy.config.cluster.ethernet_interface STRING eth0 + On OSX: e.g + CONFIG proxy.config.cluster.ethernet_interface STRING en0 + on FreeBSD: e.g. + CONFIG proxy.config.cluster.ethernet_interface STRING em0 + On OpenSolaris e.g. + CONFIG proxy.config.cluster.ethernet_interface STRING e1000g0 + + To install: + $ sudo make install + + To start Traffic Server process stack (TC, TM, TS): + On Linux: + $ sudo PREFIX/bin/trafficserver start + + On FreeBSD, OSX and OpenSolaris: + $ sudo PREFIX/bin/traffic_cop + + NOTES: * Replace PREFIX with the filesystem path under which + Traffic Server should be installed. Default PREFIX + is "/usr/local" (without the quotes). + + * If you want to build using different layout see the config.layout + file for possible alternatives. You can create your own layout and + enable it with ./configure --enable-layout=ID, where ID is the + layout name you have created. + + * The easiest way to find all of the configuration flags + for Traffic Server is to run ./configure --help. + + * To build the examples in example directory use + $ make examples + To installl the examples inside current layout libexecdir + use the + $ sudo make install-examples + + Postscript + ---------- + + The Apache Traffic Server group cannot field user's installation questions. + There are many valuable forums to help you get started. Please refer your + questions to the appropriate forum, such as the Users Mailing List at + + http://cwiki.apache.org/confluence/display/TS/Traffic+Server + + Thanks for using the Apache Traffic Server, version 2.1. + + The Apache Software Foundation + http://www.apache.org/ diff --git a/LAYOUT b/LAYOUT new file mode 100644 index 00000000..cf59cb36 --- /dev/null +++ b/LAYOUT @@ -0,0 +1,32 @@ +The Traffic Server 2.1 Default LAYOUT +-------------------------------- + +` ........................... Top-Level Traffic Server Directory +| +| +|-- bin ..................... Binaries +|-- etc ..................... Configuration files +| `-- trafficserver +| |-- body_factory +| | `-- default +| |-- internal +| `-- snapshots +|-- include +| `-- ts +|-- lib +| `-- trafficserver +|-- libexec +| `-- trafficserver +|-- share +| `-- trafficserver +| |-- configure +| | `-- helper +| |-- images +| |-- include +| |-- monitor +| `-- mrtg +`-- var + |-- log + | `-- trafficserver ... Log files + `-- trafficserver ....... Runtime data + diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b2e6b61e --- /dev/null +++ b/LICENSE @@ -0,0 +1,427 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +~~~ + +Copyright (C) 2009 Yahoo! Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +~~~ + +Mersenne Twister License + + Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +~~~ + +TK 8.3 License + +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., and other parties. The following +terms apply to all files associated with the software unless explicitly +disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +~~~ + +BIND license + +Copyright (c) 1985, 1989, 1993 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + + + +Portions Copyright (c) 1993 by Digital Equipment Corporation. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies, and that +the name of Digital Equipment Corporation not be used in advertising or +publicity pertaining to distribution of the document or software without +specific, written prior permission. + +THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + + + +Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") +Portions Copyright (c) 1996-1999 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +~~~ + +Copyright (c) 1994-2011 John Bradley Plevyak, All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +~~~ + +Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) +Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) +Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +For the strlcat, strlcpy in inktomi++/ink_string.cc: + +Copyright (c) 1998 Todd C. Miller + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..da966f5a --- /dev/null +++ b/Makefile.am @@ -0,0 +1,83 @@ +# +# Top-level Makefile.am for Traffic Server. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Local Macros +# http://www.gnu.org/software/automake/manual/automake.html#Local-Macros +ACLOCAL_AMFLAGS = -I build + +# TODO: There's still some weirdness in the dependencies between proxy +# and mgmt, hence we have to build proxy/hdrs first. + +# proxy/api/ts has to be built first, since so much of libraries and "core +# depends on the generates ts/ts.h include file. +if STANDALONE_IOCORE +SUBDIRS = proxy/api/ts iocore lib proxy/hdrs mgmt proxy cop plugins tools +else +SUBDIRS = proxy/api/ts iocore lib proxy/hdrs mgmt proxy cop rc doc plugins tools +endif + +DIST_BUILD_USER=`id -nu` +DIST_BUILD_USER_GROUP=`id -ng` +DISTCHECK_CONFIGURE_FLAGS=--with-user=${DIST_BUILD_USER} --with-group=${DIST_BUILD_USER_GROUP} + +EXTRA_DIST=CHANGES INSTALL STATUS NOTICE LAYOUT LICENSE example contrib README.libev README-EC2 REVIEWERS + +installcheck-local: + $(DESTDIR)$(bindir)/traffic_server -R 1 + +doxygen: + $(MAKE) -C doc doxygen + +asf-distdir: + @$(am__remove_distdir) + test -d .git && git clone . $(distdir) || svn export . $(distdir) + cd $(distdir) && autoreconf -i + rm -rf $(distdir)/test $(distdir)/autom4te.cache $(distdir)/.git + +asf-dist: asf-distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + @$(am__remove_distdir) + +asf-dist-sign: asf-dist + md5sum -b $(distdir).tar.bz2 >$(distdir).tar.bz2.md5 + sha1sum -b $(distdir).tar.bz2 >$(distdir).tar.bz2.sha1 + gpg --armor --output $(distdir).tar.bz2.asc --detach-sig $(distdir).tar.bz2 + +examples: all + @(cd example; $(MAKE)) + +install-examples: examples + @(cd example; $(MAKE) install pkglibdir=$(pkglibexecdir)) + +help: + @echo 'all default target for building the package' && \ + echo 'check run the test suite, if any' && \ + echo 'clean remove whatever make created' && \ + echo 'distclean remove whatever configure created' && \ + echo 'dist DEPRECATED: recreate source package' && \ + echo 'examples make examples' && \ + echo 'asf-dist recreate source package' && \ + echo 'asf-dist-sign recreate source package, with checksums and signature' && \ + echo 'distcheck verify dist by performing VPATH build and then distclean' && \ + echo 'doxygen generate doxygen docs in doc/html dir' && \ + echo 'help display this list of make targets' && \ + echo 'install install by copying the built files to system-wide dirs' && \ + echo 'install-strip same as install but then strips debugging symbols' && \ + echo 'install-examples install examples by copying the built files to system-wide dirs' + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..7fd8730e --- /dev/null +++ b/Makefile.in @@ -0,0 +1,977 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Top-level Makefile.am for Traffic Server. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/configure INSTALL \ + build/aux/config.guess build/aux/config.sub build/aux/depcomp \ + build/aux/install-sh build/aux/ltmain.sh build/aux/missing \ + build/aux/ylwrap +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = proxy/api/ts iocore lib proxy/hdrs mgmt proxy cop rc \ + doc plugins tools +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ + +# Local Macros +# http://www.gnu.org/software/automake/manual/automake.html#Local-Macros +ACLOCAL_AMFLAGS = -I build +@STANDALONE_IOCORE_FALSE@SUBDIRS = proxy/api/ts iocore lib proxy/hdrs mgmt proxy cop rc doc plugins tools + +# TODO: There's still some weirdness in the dependencies between proxy +# and mgmt, hence we have to build proxy/hdrs first. + +# proxy/api/ts has to be built first, since so much of libraries and "core +# depends on the generates ts/ts.h include file. +@STANDALONE_IOCORE_TRUE@SUBDIRS = proxy/api/ts iocore lib proxy/hdrs mgmt proxy cop plugins tools +DIST_BUILD_USER = `id -nu` +DIST_BUILD_USER_GROUP = `id -ng` +DISTCHECK_CONFIGURE_FLAGS = --with-user=${DIST_BUILD_USER} --with-group=${DIST_BUILD_USER_GROUP} +EXTRA_DIST = CHANGES INSTALL STATUS NOTICE LAYOUT LICENSE example contrib README.libev README-EC2 REVIEWERS +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: installcheck-local + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-generic distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installcheck-local installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-recursive uninstall uninstall-am + + +installcheck-local: + $(DESTDIR)$(bindir)/traffic_server -R 1 + +doxygen: + $(MAKE) -C doc doxygen + +asf-distdir: + @$(am__remove_distdir) + test -d .git && git clone . $(distdir) || svn export . $(distdir) + cd $(distdir) && autoreconf -i + rm -rf $(distdir)/test $(distdir)/autom4te.cache $(distdir)/.git + +asf-dist: asf-distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + @$(am__remove_distdir) + +asf-dist-sign: asf-dist + md5sum -b $(distdir).tar.bz2 >$(distdir).tar.bz2.md5 + sha1sum -b $(distdir).tar.bz2 >$(distdir).tar.bz2.sha1 + gpg --armor --output $(distdir).tar.bz2.asc --detach-sig $(distdir).tar.bz2 + +examples: all + @(cd example; $(MAKE)) + +install-examples: examples + @(cd example; $(MAKE) install pkglibdir=$(pkglibexecdir)) + +help: + @echo 'all default target for building the package' && \ + echo 'check run the test suite, if any' && \ + echo 'clean remove whatever make created' && \ + echo 'distclean remove whatever configure created' && \ + echo 'dist DEPRECATED: recreate source package' && \ + echo 'examples make examples' && \ + echo 'asf-dist recreate source package' && \ + echo 'asf-dist-sign recreate source package, with checksums and signature' && \ + echo 'distcheck verify dist by performing VPATH build and then distclean' && \ + echo 'doxygen generate doxygen docs in doc/html dir' && \ + echo 'help display this list of make targets' && \ + echo 'install install by copying the built files to system-wide dirs' && \ + echo 'install-strip same as install but then strips debugging symbols' && \ + echo 'install-examples install examples by copying the built files to system-wide dirs' + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..0d61ac13 --- /dev/null +++ b/NOTICE @@ -0,0 +1,26 @@ +Apache Traffic Server +Copyright 2010 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). +Pavlov Media (http://pavlovmedia.com) +Network Geographics (http://network-geographics.com) +~~~ + +Codebase originally donated by Yahoo: + +Copyright (C) 2009 Yahoo! Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +~~~ + +lib/wccp developed by Network Geographics on behalf of Pavlov Media. +Copyright (C) 2010 Pavlov Media, Inc. + +lib/tsconfig +Copyright (C) 2010 Network Geographics, Inc. diff --git a/README b/README new file mode 100644 index 00000000..f211f694 --- /dev/null +++ b/README @@ -0,0 +1,229 @@ +Apache Traffic Server + +Traffic Server is a high-performance building block for cloud services. +It's more than just a caching proxy server; it also has support for +plugins to build large scale web applications. + +1. DIRECTORY STRUCTURE + + traffic/ ............... top src dir + |-- cop ................ traffic_cop application + |-- doc/ ............... generated documentation + |-- example/ ........... example plugins + |-- install/ ........... installation programs and scripts + |-- iocore/ ............ IO core + |-- lib/ ............... + |-- ts/ ............ Base / core library + |-- tsconfig/....... New config parser and library (experimental) + |-- records/ ....... library for config files + |-- m4/ ................ custom macros for configure.ac + |-- mgmt/ .............. Management server and tools (including traffic_manager) + |-- cli ............ Command line utilities and API + |-- proxy/ ............. HTTP proxy logic + |-- test/ .............. functional tests + |-- .indent.pro ........ indent profile for coding style + |-- emacs-style ........ emacs style definition + |-- README ............. intro, links, build info + |-- README-EC2 ......... info on EC2 support + |-- README.libev ....... instructions to build with 'libev' + |-- REVIEWERS .......... (incomplete) list of areas with committer interest + |-- LICENSE ............ full license text + |-- NOTICE ............. copyright notices + |-- configure.ac ....... autoconf configuration + `-- Makefile.am ........ top level automake configuration + + +2. REQUIREMENTS + This section outlines different OS distributions + + Fedora 11,12, 13, 14, 15: + autoconf + automake + libtool + gcc-c++ + glibc-devel + openssl-devel + tcl-devel + expat-devel + pcre + libcap-devel + + Fedora 8 EC2 (Kernel: 2.6.21.7-2.ec2.v1.2.fc8xen): + FC8 on EC2 requires unique configure declarations, please see that section + below. + + NOTE: Alternately you may use the install scripts in 'contrib' which + automate this or use the pre-built public Fedora Core 8 EC2 AMI + with ATS installed. Both of which are HIGHLY RECOMMENDED. + See 'README-EC2' for further details. + + Install these packages: + autoconf + automake + libtool + gcc-c++ + glibc-devel + openssl-devel + tcl-devel + expat-devel + db4-devel + pcre + + Ubuntu 8.* ,9.*, 10.*, 11.*: + autoconf + automake + libtool + g++ + libssl-dev + tcl-dev + expat + libexpat-dev + libpcre3-dev + libcap-dev + + Ubuntu EC2 9.10: + NOTE: Alternately you may use the install scripts in 'contrib' which + automate this or use the pre-built public Ubuntu EC2 AMI with + ATS installed. Both of which are HIGHLY RECOMMENDED. + See 'README-EC2' for further details. + + Install these packages: + autoconf + automake + libtool + g++ + libssl-dev + tcl-dev + expat + libexpat-dev + libpcre3-dev + + FreeBSD 7.2,8.0: + GCC 4.2.1 compiler suite + autoconf + automake + libtool + tcl + expat + openssl + pcre + + OpenSolaris osol0906: + GCC 4.3.2 compiler suite (dev collection) + autoconf + automake + libtool + tcl + expat + openssl + pcre + + OSX 10.5: + GCC 4.2.4 compiler suite (ports collection) + autoconf + automake + libtool + tcl + expat + openssl + pcre + + +3. Building from distribution + +You can download the latest source code from the official Apache Traffic +Server site: + + http://trafficserver.apache.org/downloads.html + +(or via the URL shortener: http://s.apache.org/uG). Once downloaded, +follow the instructions: + + tar xf trafficserver-2.1.8-unstable.tar.bz2 + cd trafficserver-2.1.8-unstable + ./configure # configure the build environment to create Makfiles + make # execute the compile + +This will build with a destination prefix of /usr/local. You can finish +the installation with + + sudo make install + + +4. BUILDING FROM SVN REPO + + mkdir -p ~/dev # make yourself a development dir + cd ~/dev # enter your development dir + svn checkout ... # get the source code from ASF Subversion repo + cd traffic # enter the checkout dir + autoreconf -i # generate the configure script and Makefile.in files + ./configure # configure the build environment to create Makfiles + make # execute the compile + +4b. Instructions for building on EC2 + NOTE: Alternately you may use the scripts under 'contrib' which will + automate the install for trafficserver under EC2 which is + HIGHLY RECOMMENDED. See 'README-EC2' for further details. + + # As root do the following when using Ubuntu + mkdir -p /mnt #EC2 Storage Mount, where storage is located + cd /mnt + svn checkout ... # get the source code from ASF Subversion repo + cd traffic # enter the checkout dir + autoreconf -i --force # generate the configure script and Makefile.in files + ./configure + make + + # As root do the following when using Fedora Core 8 kernel + mkdir -p /mnt #EC2 Storage Mount, where storage is located + cd /mnt + svn checkout ... # get the source code from ASF Subversion repo + cd traffic # enter the checkout dir + autoreconf -i --force # generate the configure script and Makefile.in files + ./configure --disable-eventfd + make + + +5. INSTALLATION + + DEFAULT DIR CONTENTS + /usr/local/var/log/trafficserver log files created at runtime + /usr/local/var/trafficserver runtime files + /usr/local/etc/trafficserver configuration files + /usr/local/bin executable binaries + /usr/local/libexec/trafficserver plugins + + +6. CRYPTO NOTICE + + This distribution includes cryptographic software. The country in + which you currently reside may have restrictions on the import, + possession, use, and/or re-export to another country, of + encryption software. BEFORE using any encryption software, please + check your country's laws, regulations and policies concerning the + import, possession, or use, and re-export of encryption software, to + see if this is permitted. See for more + information. + + The U.S. Government Department of Commerce, Bureau of Industry and + Security (BIS), has classified this software as Export Commodity + Control Number (ECCN) 5D002.C.1, which includes information security + software using or performing cryptographic functions with asymmetric + algorithms. The form and manner of this Apache Software Foundation + distribution makes it eligible for export under the License Exception + ENC Technology Software Unrestricted (TSU) exception (see the BIS + Export Administration Regulations, Section 740.13) for both object + code and source code. + + The following provides more details on the included cryptographic + software: + + The functionality of OpenSSL is + utilized in parts of the software. + + +7. ADDITIONAL INFO + + Web page: http://trafficserver.apache.org/ + Wiki: http://cwiki.apache.org/confluence/display/TS/ + User mailing list: users@trafficserver.apache.org diff --git a/README-EC2 b/README-EC2 new file mode 100644 index 00000000..6f746abe --- /dev/null +++ b/README-EC2 @@ -0,0 +1,134 @@ +Apache TrafficServer AMIs for EC2 +Author: Jason Giedymin + +--TOC-- +1.0 Ubuntu Based Images +1.1 Ubuntu AMI Details +1.2 What is installed? + +2.0 Fedora Based Images +2.1 Fedora AMI Details +2.2 What is installed? + +3.0 The ATS Installation +3.1 Additional Update Functionality +3.2 User customized settings +3.3 Script Breakout + +4.0 FAQ +4.1 I use EC2 and I'm still confused!? +4.2 What is EC2? +4.3 I don't use EC2 or have an AWS account, can I still use these scripts on + my Virtual Machine or dedicated Ubuntu/Fedora Linux Box? +4.4 How do I contact you for help? +4.5 Will these AMIs be updated in the future? + +------- + +1.0 Ubuntu Based Images + This is the prefered image as Ubuntu is kept up to date by Canonical. + +1.1 Ubuntu AMI Details + Name: Amuxbit-Karmic-ApacheTrafficServer-AMI + x86_64 AMI: ami-ada24cc4, kernel: aki-fd15f694, Ramdisk: ari-7b739e12 + i386 AMI: ami-5ba34d32, kernel: aki-5f15f636, Ramdisk: ari-d5709dbc + +1.2 What is installed? + All packages other than Apache TrafficServer are from the ec2 ubuntu + package repositories. All software installed should be open source. + * Official Canonical Ubuntu Karmic 9.10 EC2 AMI + * Dist Upgraded as of 4/1/2010 + * Apache TrafficServer - Trunk (can be updated at any time) + * openjdk-6-jre (for ec2 tools) + * ruby (for ec2 tools) + * libopenssl-ruby (for ec2 tools) + * Apache2 (httpd, used for testing) + +2.0 Fedora Based Images + +2.1 Fedora AMI Details + Name: Amuxbit-Fedora8-ApacheTrafficServer-AMI + x86_64 AMI: ami-c3a04eaa, kernel: aki-a3d737ca, Ramdisk: ari-7cb95a15 + i386 AMI: ami-53a04e3a, kernel: aki-6eaa4907, Ramdisk: ari-42b95a2b + +2.2 What is installed? + All packages other than Apache TrafficServer are from the ec2 fedora + package repositories. All software installed should be open source. + * Official Fedora Core 8 EC2 AMI + * Dist Upgraded as of 4/1/2010 + * Apache TrafficServer - Trunk (can be updated at any time) + * java-1.7.0-icedtea (openjdk for ec2 tools) + * openssl-devel (for ec2 tools) + * ruby (for ec2 tools) + * httpd (Apache web server, used for testing) + +3.0 The ATS Installation + Apache Traffic Server is installed in: '/ats'. + The installation script used to install ATS is contained within the contrib + directory, part of the ATS source distribution. The script is included + within the '/ats' folder for actual use. + +3.1 Additional Update Functionality + The EC2 images provided contain additional scripts to maintain freshness + of the install scripts. At one time the scripts provided 'auto-heal' + functionality but that has beeen removed. Running /ats/install_update.sh + will keep the ATS installation up to date. + +3.2 User customized settings + Any customized settings will be lost if the update/install scripts are run. + Upon executing the install/update scripts you may copy your files back into + the config directory. Users should periodically backup your config files, + and keep abrest of any config changes as new versions of ATS are released. + The latter reason being why I did not auto-copy configs. While I've tried + to lessen as much pain for any Sys Admins, ultimately you must take charge + of these critical settings as updates will and do happen frequently to the + ATS source. + + An example script which alters settings can be found in + '/ats/contrib/set_trafficserver.sh' + This has been used on the AMIs already provided. + +3.3 Script Breakout + + ats + |-- contrib + | -- install_trafficserver.sh : installs ATS. Try not to run this directly. + | -- set_trafficserver.sh : sample config/testing/benchmark base script. + You may want to learn from/use this script. + ` -- update_scripts.sh : used to update install_trafficserver.sh, + and set_trafficserver.sh from trunk. + |-- install_update.sh : the 'easy button' script to re-install ATS. + Executes update_scripts.sh, then install_trafficserver.sh. + This is what you want to run. + `-- readme : extra information. + +4.0 FAQ + +4.1 I use EC2 and I'm still confused!? + With your EC2 account, refer to one of the AMIs listed in this doc + (Ubuntu/Fedora). Image architectures provided are i386, and x86_64. + 64bit is offered for those who need to spin up a big high powered instances. + Once running (and it may take a while) you will find yourself with a Linux + distribution with Apache Traffic Server already installed. If you'd like + to re-install ATS against trunk, run '/ats/install_update.sh'. Note that + you will have to backup and/or optimize your configuration (see 3.2). + To further setup ATS see the TrafficServer wiki @ + + http://cwiki.apache.org/confluence/display/TS/ + +4.2 What is EC2? + See http://aws.amazon.com/ + +4.3 I don't use EC2 or have an AWS account, can I still use these scripts on + my Virtual Machine or dedicated Ubuntu/Fedora Linux Box? + Absolutely! The /contrib scripts are actually meant for Ubuntu/Linux + Installs first, EC2 second. You can find them on the ATS SVN/Git + repository under '/contrib'. + +4.4 How do I contact you for help? + For mailing lists, and IRC information, visit our web page at + + http://trafficserver.apache.org/ + +4.5 Will these AMIs be updated in the future? + Absolutely! diff --git a/README.libev b/README.libev new file mode 100644 index 00000000..2b220b35 --- /dev/null +++ b/README.libev @@ -0,0 +1,73 @@ +To compile TrafficServer with libev + +1. Get the libev source by either: + a. Pull the libev source into the root of the TS source + cvs -z3 -d :pserver:anonymous@cvs.schmorp.de/schmorpforge co libev + + OR + + b. Download libev tar ball e.g. libev-3.8.tar.gz and extract into + toplevel TS source directory. Next symlink the extracted directory + to 'libev' e.g. 'ln -s libev-3.8 libev'. + +2. Apply the patch at the end of this file (after CUT HERE) to the libev source + +3. In the libev directory + a. autoreconf -i + b. ./configure CFLAGS="$CFLAGS -Dinline_size= -DEV_MINPRI=0 -DEV_MAXPRI=0" + c. install normally + +4. Configure trafffic server with '--enable-libev'. + + +------------------------ CUT HERE ---------------- +Index: ev.c +=================================================================== +RCS file: /schmorpforge/libev/ev.c,v +retrieving revision 1.320 +diff -u -r1.320 ev.c +--- ev.c 4 Dec 2009 20:25:06 -0000 1.320 ++++ ev.c 25 Feb 2010 17:24:18 -0000 +@@ -467,7 +467,9 @@ + + #define expect_false(expr) expect ((expr) != 0, 0) + #define expect_true(expr) expect ((expr) != 0, 1) ++#ifndef inline_size + #define inline_size static inline ++#endif + + #if EV_MINIMAL + # define inline_speed static noinline +Index: ev_poll.c +=================================================================== +RCS file: /schmorpforge/libev/ev_poll.c,v +retrieving revision 1.31 +diff -u -r1.31 ev_poll.c +--- ev_poll.c 19 Jul 2009 04:11:27 -0000 1.31 ++++ ev_poll.c 25 Feb 2010 17:24:18 -0000 +@@ -104,12 +104,12 @@ + else if (errno != EINTR) + ev_syserr ("(libev) poll"); + } +- else +- for (p = polls; res; ++p) ++ else { ++ int i = 0; ++ for (i = 0; i < pollcnt; i++) { ++ p = &polls[i]; + if (expect_false (p->revents)) /* this expect is debatable */ + { +- --res; +- + if (expect_false (p->revents & POLLNVAL)) + fd_kill (EV_A_ p->fd); + else +@@ -120,6 +120,8 @@ + | (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0) + ); + } ++ } ++ } + } + + int inline_size diff --git a/REVIEWERS b/REVIEWERS new file mode 100644 index 00000000..173f46bb --- /dev/null +++ b/REVIEWERS @@ -0,0 +1,107 @@ +These are Committers who have expressed general interest in the listed parts +of the Traffic Server code to the extent that they will review or at least read +over changes in those parts and should review major changes. + +All changes should have a jira ticket: + https://issues.apache.org/jira/browse/TS + +Big changes should be discussed on one or more of: + mailing list: dev@trafficserver.apache.org + IRC: #traffic-server irc.freenode.net + +Major or controversial changes should be have wiki page and may require a vote: + http://cwiki.apache.org/confluence/display/TS/Traffic+Server + +Committers: add modules as needed and any qualifications after your e-mail address +==================================================================================== + +all/general interest + jplevyak@apache.org + bcall@apache.org + mturk@apache.org + zwoop@apache.org + jim@apache.org + ericb@apache.org +lib/ts + jplevyak@apache.org + zwoop@apache.org + bcall@apache.org + georgep@apache.org + ericb@apache.org +lib/records + bcall@apache.org + georgep@apache.org + zwoop@apache.org +Event System/Buffering/VIO/VConnection + jplevyak@apache.org + bcall@apache.org + georgep@apache.org +Network I/O + jplevyak@apache.org - not including SSL or UDP except where it intersects the other code + bcall@apache.org + georgep@apache.org + jim@apache.org + zwoop@apache.org +Raw Cache and AIO + jplevyak@apache.org + bcall@apache.org + georgep@apache.org +HTTP Caching + bcall@apache.org + jim@apache.org + zwoop@apache.org +Block-Cache +Clustering + jplevyak@apache.org + georgep@apache.org + jim@apache.org +DNS/HostDB + jplevyak@apache.org + zwoop@apache.org + bcall@apache.org + georgep@apache.org + ericb@apache.org +FastIO +Docs + dianes@apache.org +Examples/Plugins + zwoop@apache.org + bcall@apache.org + ericb@apache.org +HDRs + bcall@apache.org + zwoop@apache.org +HTTP + bcall@apache.org + zwoop@apache.org + jim@apache.org + ericb@apache.org +Remap + zwoop@apache.org + bcall@apache.org + jim@apache.org + ericb@apache.org +API + zwoop@apache.org + bcall@apache.org + georgep@apache.org + ericb@apache.org +Config + zwoop@apache.org + bcall@apache.org + georgep@apache.org +Congest +Logging + georgep@apache.org +MGMT + georgep@apache.org +Stats + bcall@apache.org + georgep@apache.org + zwoop@apache.org +Build System + zwoop@apache.org + bcall@apache.org + georgep@apache.org + mturk@apache.org + jim@apache.org diff --git a/STATUS b/STATUS new file mode 100644 index 00000000..178fde21 --- /dev/null +++ b/STATUS @@ -0,0 +1,64 @@ +Traffic Server 3.0 STATUS: -*-text-*- +Last modified at [$Date$] + +The current version of this file can be found at: + + * http://git-wip-us.apache.org/repos/asf?p=trafficserver.git;a=blob;f=STATUS;hb=3.0.x + + +Release history: + [NOTE that x.{odd}.z versions are strictly Alpha/Beta releases, + while x.{even}.z versions are Stable/GA releases.] + + 3.0.6 : Released on xxx, 2012 + 3.0.5 : Released on May 11, 2012 + 3.0.4 : Released on March 21, 2012 + 3.0.3 : Released on Februrary 13, 2012 + 3.0.2 : Released on December 07th, 2011 + 3.0.1 : Released on July 18th, 2011 + 3.0.0 : Released on June 13th, 2011 + 2.0.1 : Released on August 31, 2010 + 2.0.0 : Released on April 28, 2010 + + +Contributors looking for a mission: + + * Just do an egrep on "TODO" or "XXX" in the source. + + * Review the bug database at: https://issues.apache.org/jira/browse/TS + + - Download, test and review patches attached to open bugs + + * Open bugs in the bug database. + + +CURRENT RELEASE NOTES: + + +RELEASE SHOWSTOPPERS: + +A list of all bugs open for the next v3.0.6 release can be found at + + http://s.apache.org/ts-3.0.6 + +PATCHES ACCEPTED TO BACKPORT FROM TRUNK: + +PATCHES PROPOSED TO BACKPORT FROM TRUNK: + [ New proposals should be added at the end of the list ] + + +STALLED ISSUES + + *) key->volume hash table is not consistent when a disk is marked as bad or removed due to failure + Trunk patch: https://git-wip-us.apache.org/repos/asf?p=trafficserver.git;a=commit;h=b2109cdaf55234621d6c3b2fcb4f15774f0939ab + Jira: https://issues.apache.org/jira/browse/TS-949 + +1: zym + -0: zwoop (I think this breaks compatibility with existing 3.0.x + caches, and I'm not positive it's a good idea to do so). + +RELEASE PROCESS + +The Traffic Server release process is documented at + + https://cwiki.apache.org/confluence/display/TS/ReleaseProcess + https://cwiki.apache.org/confluence/display/TS/3.0.x-Series diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 00000000..d42e555e --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,998 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, +[m4_warning([this file was generated for autoconf 2.68. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Figure out how to run the assembler. -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_PROG_AS +# ---------- +AC_DEFUN([AM_PROG_AS], +[# By default we simply use the C compiler to build assembly code. +AC_REQUIRE([AC_PROG_CC]) +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS +AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)]) +AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)]) +_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([build/common.m4]) +m4_include([build/crypto.m4]) +m4_include([build/libtool.m4]) +m4_include([build/ltoptions.m4]) +m4_include([build/ltsugar.m4]) +m4_include([build/ltversion.m4]) +m4_include([build/lt~obsolete.m4]) +m4_include([build/lzma.m4]) +m4_include([build/network.m4]) +m4_include([build/pcre.m4]) +m4_include([build/tcl.m4]) +m4_include([build/xml.m4]) +m4_include([build/zlib.m4]) diff --git a/build/aux/config.guess b/build/aux/config.guess new file mode 100755 index 00000000..dc84c68e --- /dev/null +++ b/build/aux/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/aux/config.sub b/build/aux/config.sub new file mode 100755 index 00000000..2a55a507 --- /dev/null +++ b/build/aux/config.sub @@ -0,0 +1,1705 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build/aux/depcomp b/build/aux/depcomp new file mode 100755 index 00000000..df8eea7e --- /dev/null +++ b/build/aux/depcomp @@ -0,0 +1,630 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free +# Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u="sed s,\\\\\\\\,/,g" + depmode=msvisualcpp +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/build/aux/install-sh b/build/aux/install-sh new file mode 100755 index 00000000..6781b987 --- /dev/null +++ b/build/aux/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/build/aux/ltmain.sh b/build/aux/ltmain.sh new file mode 100755 index 00000000..78cf0175 --- /dev/null +++ b/build/aux/ltmain.sh @@ -0,0 +1,9636 @@ + +# libtool (GNU libtool) 2.4 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.4 +TIMESTAMP="" +package_revision=1.3293 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ fputs ("/' -e 's/$/\\n", f);/' + + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/build/aux/missing b/build/aux/missing new file mode 100755 index 00000000..28055d2a --- /dev/null +++ b/build/aux/missing @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/build/aux/ylwrap b/build/aux/ylwrap new file mode 100755 index 00000000..84d56340 --- /dev/null +++ b/build/aux/ylwrap @@ -0,0 +1,222 @@ +#! /bin/sh +# ylwrap - wrapper for lex/yacc invocations. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, +# 2007, 2009 Free Software Foundation, Inc. +# +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case "$1" in + '') + echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 + exit 1 + ;; + --basedir) + basedir=$2 + shift 2 + ;; + -h|--h*) + cat <<\EOF +Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... + +Wrapper for lex/yacc invocations, renaming files as desired. + + INPUT is the input file + OUTPUT is one file PROG generates + DESIRED is the file we actually want instead of OUTPUT + PROGRAM is program to run + ARGS are passed to PROG + +Any number of OUTPUT,DESIRED pairs may be used. + +Report bugs to . +EOF + exit $? + ;; + -v|--v*) + echo "ylwrap $scriptversion" + exit $? + ;; +esac + + +# The input. +input="$1" +shift +case "$input" in + [\\/]* | ?:[\\/]*) + # Absolute path; do nothing. + ;; + *) + # Relative path. Make it absolute. + input="`pwd`/$input" + ;; +esac + +pairlist= +while test "$#" -ne 0; do + if test "$1" = "--"; then + shift + break + fi + pairlist="$pairlist $1" + shift +done + +# The program to run. +prog="$1" +shift +# Make any relative path in $prog absolute. +case "$prog" in + [\\/]* | ?:[\\/]*) ;; + *[\\/]*) prog="`pwd`/$prog" ;; +esac + +# FIXME: add hostname here for parallel makes that run commands on +# other machines. But that might take us over the 14-char limit. +dirname=ylwrap$$ +trap "cd '`pwd`'; rm -rf $dirname > /dev/null 2>&1" 1 2 3 15 +mkdir $dirname || exit 1 + +cd $dirname + +case $# in + 0) "$prog" "$input" ;; + *) "$prog" "$@" "$input" ;; +esac +ret=$? + +if test $ret -eq 0; then + set X $pairlist + shift + first=yes + # Since DOS filename conventions don't allow two dots, + # the DOS version of Bison writes out y_tab.c instead of y.tab.c + # and y_tab.h instead of y.tab.h. Test to see if this is the case. + y_tab_nodot="no" + if test -f y_tab.c || test -f y_tab.h; then + y_tab_nodot="yes" + fi + + # The directory holding the input. + input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` + # Quote $INPUT_DIR so we can use it in a regexp. + # FIXME: really we should care about more than `.' and `\'. + input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` + + while test "$#" -ne 0; do + from="$1" + # Handle y_tab.c and y_tab.h output by DOS + if test $y_tab_nodot = "yes"; then + if test $from = "y.tab.c"; then + from="y_tab.c" + else + if test $from = "y.tab.h"; then + from="y_tab.h" + fi + fi + fi + if test -f "$from"; then + # If $2 is an absolute path name, then just use that, + # otherwise prepend `../'. + case "$2" in + [\\/]* | ?:[\\/]*) target="$2";; + *) target="../$2";; + esac + + # We do not want to overwrite a header file if it hasn't + # changed. This avoid useless recompilations. However the + # parser itself (the first file) should always be updated, + # because it is the destination of the .y.c rule in the + # Makefile. Divert the output of all other files to a temporary + # file so we can compare them to existing versions. + if test $first = no; then + realtarget="$target" + target="tmp-`echo $target | sed s/.*[\\/]//g`" + fi + # Edit out `#line' or `#' directives. + # + # We don't want the resulting debug information to point at + # an absolute srcdir; it is better for it to just mention the + # .y file with no path. + # + # We want to use the real output file name, not yy.lex.c for + # instance. + # + # We want the include guards to be adjusted too. + FROM=`echo "$from" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + TARGET=`echo "$2" | sed \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ + -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` + + sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ + -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? + + # Check whether header files must be updated. + if test $first = no; then + if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then + echo "$2" is unchanged + rm -f "$target" + else + echo updating "$2" + mv -f "$target" "$realtarget" + fi + fi + else + # A missing file is only an error for the first file. This + # is a blatant hack to let us support using "yacc -d". If -d + # is not specified, we don't want an error when the header + # file is "missing". + if test $first = yes; then + ret=1 + fi + fi + shift + shift + first=no + done +else + ret=$? +fi + +# Remove the directory. +cd .. +rm -rf $dirname + +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/build/common.m4 b/build/common.m4 new file mode 100644 index 00000000..a0f2cd84 --- /dev/null +++ b/build/common.m4 @@ -0,0 +1,580 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl common.m4: Trafficserver's general-purpose autoconf macros +dnl + +dnl +dnl TS_CONFIG_NICE(filename) +dnl +dnl Saves a snapshot of the configure command-line for later reuse +dnl +AC_DEFUN([TS_CONFIG_NICE], [ + rm -f $1 + cat >$1<> $1 + fi + if test -n "$CXX"; then + echo "CXX=\"$CXX\"; export CXX" >> $1 + fi + if test -n "$CFLAGS"; then + echo "CFLAGS=\"$CFLAGS\"; export CFLAGS" >> $1 + fi + if test -n "$CXXFLAGS"; then + echo "CXXFLAGS=\"$CXXFLAGS\"; export CXXFLAGS" >> $1 + fi + if test -n "$CPPFLAGS"; then + echo "CPPFLAGS=\"$CPPFLAGS\"; export CPPFLAGS" >> $1 + fi + if test -n "$LDFLAGS"; then + echo "LDFLAGS=\"$LDFLAGS\"; export LDFLAGS" >> $1 + fi + if test -n "$LTFLAGS"; then + echo "LTFLAGS=\"$LTFLAGS\"; export LTFLAGS" >> $1 + fi + if test -n "$LIBS"; then + echo "LIBS=\"$LIBS\"; export LIBS" >> $1 + fi + if test -n "$INCLUDES"; then + echo "INCLUDES=\"$INCLUDES\"; export INCLUDES" >> $1 + fi + if test -n "$NOTEST_CFLAGS"; then + echo "NOTEST_CFLAGS=\"$NOTEST_CFLAGS\"; export NOTEST_CFLAGS" >> $1 + fi + if test -n "$NOTEST_CXXFLAGS"; then + echo "NOTEST_CXXFLAGS=\"$NOTEST_CXXFLAGS\"; export NOTEST_CXXFLAGS" >> $1 + fi + if test -n "$NOTEST_CPPFLAGS"; then + echo "NOTEST_CPPFLAGS=\"$NOTEST_CPPFLAGS\"; export NOTEST_CPPFLAGS" >> $1 + fi + if test -n "$NOTEST_LDFLAGS"; then + echo "NOTEST_LDFLAGS=\"$NOTEST_LDFLAGS\"; export NOTEST_LDFLAGS" >> $1 + fi + if test -n "$NOTEST_LIBS"; then + echo "NOTEST_LIBS=\"$NOTEST_LIBS\"; export NOTEST_LIBS" >> $1 + fi + + # Retrieve command-line arguments. + eval "set x $[0] $ac_configure_args" + shift + + for arg + do + TS_EXPAND_VAR(arg, $arg) + echo "\"[$]arg\" \\" >> $1 + done + echo '"[$]@"' >> $1 + chmod +x $1 +])dnl + +dnl +dnl TS_SETIFNULL(variable, value) +dnl +dnl Set variable iff it's currently null +dnl +AC_DEFUN([TS_SETIFNULL], [ + if test -z "$$1"; then + test "x$verbose" = "xyes" && echo " setting $1 to \"$2\"" + $1="$2" + fi +])dnl + +dnl +dnl TS_SETVAR(variable, value) +dnl +dnl Set variable no matter what +dnl +AC_DEFUN([TS_SETVAR], [ + test "x$verbose" = "xyes" && echo " forcing $1 to \"$2\"" + $1="$2" +])dnl + +dnl +dnl TS_ADDTO(variable, value) +dnl +dnl Add value to variable +dnl +AC_DEFUN([TS_ADDTO], [ + if test "x$$1" = "x"; then + test "x$verbose" = "xyes" && echo " setting $1 to \"$2\"" + $1="$2" + else + ats_addto_bugger="$2" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $$1; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to $1" + $1="$$1 $i" + fi + done + fi +])dnl + +dnl +dnl TS_REMOVEFROM(variable, value) +dnl +dnl Remove a value from a variable +dnl +AC_DEFUN([TS_REMOVEFROM], [ + if test "x$$1" = "x$2"; then + test "x$verbose" = "xyes" && echo " nulling $1" + $1="" + else + ats_new_bugger="" + ats_removed=0 + for i in $$1; do + if test "x$i" != "x$2"; then + ats_new_bugger="$ats_new_bugger $i" + else + ats_removed=1 + fi + done + if test $ats_removed = "1"; then + test "x$verbose" = "xyes" && echo " removed \"$2\" from $1" + $1=$ats_new_bugger + fi + fi +]) dnl + +dnl +dnl TS_TRY_COMPILE_NO_WARNING(INCLUDES, FUNCTION-BODY, +dnl [ACTIONS-IF-NO-WARNINGS], [ACTIONS-IF-WARNINGS]) +dnl +dnl Tries a compile test with warnings activated so that the result +dnl is false if the code doesn't compile cleanly. For compilers +dnl where it is not known how to activate a "fail-on-error" mode, +dnl it is undefined which of the sets of actions will be run. +dnl +AC_DEFUN([TS_TRY_COMPILE_NO_WARNING], +[ats_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $CFLAGS_WARN" + if test "$ac_cv_prog_gcc" = "yes"; then + CFLAGS="$CFLAGS -Werror" + fi + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ + [#include "confdefs.h" + ] + [[$1]] + [int main(int argc, const char *const *argv) {] + [[$2]] + [ return 0; }]])], + [$3], [$4]) + CFLAGS=$ats_save_CFLAGS +]) + + +dnl Iteratively interpolate the contents of the second argument +dnl until interpolation offers no new result. Then assign the +dnl final result to $1. +dnl +dnl Example: +dnl +dnl foo=1 +dnl bar='${foo}/2' +dnl baz='${bar}/3' +dnl TS_EXPAND_VAR(fraz, $baz) +dnl $fraz is now "1/2/3" +dnl +AC_DEFUN([TS_EXPAND_VAR], [ +ats_last= +ats_cur="$2" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +$1="${ats_cur}" +]) + + +dnl +dnl Removes the value of $3 from the string in $2, strips of any leading +dnl slashes, and returns the value in $1. +dnl +dnl Example: +dnl orig_path="${prefix}/bar" +dnl TS_PATH_RELATIVE(final_path, $orig_path, $prefix) +dnl $final_path now contains "bar" +AC_DEFUN([TS_PATH_RELATIVE], [ +ats_stripped=`echo $2 | sed -e "s#^$3##"` +# check if the stripping was successful +if test "x$2" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + $1="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + $1="$2" +fi +]) + + +dnl TS_SUBST(VARIABLE) +dnl Makes VARIABLE available in generated files +dnl (do not use @variable@ in Makefiles, but $(variable)) +AC_DEFUN([TS_SUBST], [ + TS_VAR_SUBST="$TS_VAR_SUBST $1" + AC_SUBST($1) +]) + +dnl +dnl TS_SUBST_LAYOUT_PATH +dnl Export (via TS_SUBST) the various path-related variables that +dnl trafficserver will use while generating scripts and +dnl the default config file. +AC_DEFUN([TS_SUBST_LAYOUT_PATH], [ + TS_EXPAND_VAR(exp_$1, [$]$1) + TS_PATH_RELATIVE(rel_$1, [$]exp_$1, ${prefix}) + TS_SUBST(exp_$1) + TS_SUBST(rel_$1) + TS_SUBST($1) +]) + +dnl TS_HELP_STRING(LHS, RHS) +dnl Autoconf 2.50 can not handle substr correctly. It does have +dnl AC_HELP_STRING, so let's try to call it if we can. +dnl Note: this define must be on one line so that it can be properly returned +dnl as the help string. When using this macro with a multi-line RHS, ensure +dnl that you surround the macro invocation with []s +AC_DEFUN([TS_HELP_STRING], [ifelse(regexp(AC_ACVERSION, 2\.1), -1, AC_HELP_STRING([$1],[$2]),[ ][$1] substr([ ],len($1))[$2])]) + +dnl +dnl TS_LAYOUT(configlayout, layoutname [, extravars]) +dnl +AC_DEFUN([TS_LAYOUT], [ + if test ! -f $srcdir/config.layout; then + echo "** Error: Layout file $srcdir/config.layout not found" + echo "** Error: Cannot use undefined layout '$LAYOUT'" + exit 1 + fi + # Catch layout names including a slash which will otherwise + # confuse the heck out of the sed script. + case $2 in + */*) + echo "** Error: $2 is not a valid layout name" + exit 1 ;; + esac + pldconf=./config.pld + changequote({,}) + sed -e "1s/[ ]*<[lL]ayout[ ]*$2[ ]*>[ ]*//;1t" \ + -e "1,/[ ]*<[lL]ayout[ ]*$2[ ]*>[ ]*/d" \ + -e '/[ ]*<\/Layout>[ ]*/,$d' \ + -e "s/^[ ]*//g" \ + -e "s/:[ ]*/=\'/g" \ + -e "s/[ ]*$/'/g" \ + $1 > $pldconf + layout_name=$2 + if test ! -s $pldconf; then + echo "** Error: unable to find layout $layout_name" + exit 1 + fi + . $pldconf + rm $pldconf + for var in prefix exec_prefix bindir sbindir libexecdir mandir infodir \ + sysconfdir datadir includedir localstatedir runtimedir \ + logdir libdir installbuilddir libsuffix $3; do + eval "val=\"\$$var\"" + case $val in + *+) + val=`echo $val | sed -e 's;\+$;;'` + eval "$var=\"\$val\"" + autosuffix=yes + ;; + *) + autosuffix=no + ;; + esac + val=`echo $val | sed -e 's:\(.\)/*$:\1:'` + val=`echo $val | sed -e 's:[\$]\([a-z_]*\):${\1}:g'` + if test "$autosuffix" = "yes"; then + if echo $val | grep -i '/trafficserver$' >/dev/null; then + addtarget=no + else + addtarget=yes + fi + if test "$addtarget" = "yes"; then + val="$val/trafficserver" + fi + fi + eval "$var='$val'" + done + for var in bindir sbindir libexecdir mandir infodir sysconfdir \ + datadir localstatedir runtimedir logdir libdir $3; do + eval "val=\"\$$var\"" + case $val in + *+) + val=`echo $val | sed -e 's;\+$;;'` + eval "$var=\"\$val\"" + autosuffix=yes + ;; + *) + autosuffix=no + ;; + esac + org_val= + exp_val="$val" + while test "x${exp_val}" != "x${org_val}"; + do + org_val="${exp_val}" + exp_val="`eval \"echo ${exp_val}\"`" + done + if echo $exp_val | grep -i '/trafficserver$' >/dev/null; then + addtarget=no + else + addtarget=yes + fi + if test "$addsuffix" = "yes" -a "$addtarget" = "yes"; then + val="$val/trafficserver" + fi + var="pkg${var}" + eval "$var='$val'" + done + changequote([,]) +])dnl + +dnl +dnl TS_ENABLE_LAYOUT(default layout name [, extra vars]) +dnl +AC_DEFUN([TS_ENABLE_LAYOUT], [ +AC_ARG_ENABLE(layout, + [TS_HELP_STRING([--enable-layout=LAYOUT],[Enable LAYOUT specified inside config.layout file (defaults to TrafficServer)])],[ + LAYOUT=$enableval +]) + +if test -z "$LAYOUT"; then + LAYOUT="$1" +fi +TS_LAYOUT($srcdir/config.layout, $LAYOUT, $2) + +AC_MSG_CHECKING(for chosen layout) +AC_MSG_RESULT($layout_name) +]) + + +dnl +dnl TS_PARSE_ARGUMENTS +dnl a reimplementation of autoconf's argument parser, +dnl used here to allow us to co-exist layouts and argument based +dnl set ups. +AC_DEFUN([TS_PARSE_ARGUMENTS], [ +ac_prev= +# Retrieve the command-line arguments. The eval is needed because +# the arguments are quoted to preserve accuracy. +eval "set x $ac_configure_args" +shift +for ac_option +do +# If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[[^=]]*=\(.*\)'` + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" + pkgbindir="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" + pkgdatadir="$ac_optarg" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" + pkglibdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" + pkglibexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" + pkglocalstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -runtimedir | --runtimedir | --runtimedi | --runtimed | --runtime | --runtim \ + | --runti | --runt | --run | --ru | --r) + ac_prev=runtimedir ;; + -runtimedir=* | --runtimedir=* | --runtimedi=* | --runtimed=* | --runtime=* \ + | --runtim=* | --runti=* | --runt=* | --run=* | --ru=* | --r=*) + ac_prev=runtimedir ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" + pkgsbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" + pkgsysconfdir="$ac_optarg" ;; + + esac +done + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [[\\/$]]* | ?:[[\\/]]* | NONE | '' ) ;; + *) AC_MSG_ERROR([expected an absolute path for --$ac_var: $ac_val]);; + esac +done + +])dnl + +dnl TS_FLAG_HEADERS(HEADER-FILE ... ) +dnl +AC_DEFUN([TS_FLAG_HEADERS], [ +AC_CHECK_HEADERS([$1], [$2], [$3], [$4]) +for tsc_i in $1 +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done +]) + +dnl TS_FLAG_FUNCS(FUNC ... ) +dnl +AC_DEFUN([TS_FLAG_FUNCS], [ +AC_CHECK_FUNCS($1) +for tsc_j in $1 +do + tsc_3="has_$tsc_j" + if eval "test \"`echo '$ac_cv_func_'$tsc_j`\" = yes"; then + eval "$tsc_3=1" + else + eval "$tsc_3=0" + fi +done +]) + +dnl +dnl Support macro for AC_ARG_ENABLE +dnl Arguments: +dnl 1: Variable prefix +dnl 2: Variable stem +dnl The prefix is prepended with separating underscore to the stem +dnl to create the boolean variable to be set. The stem is also used +dnl to create the name of the AC_ARG_ENABLE variable and therefore +dnl must be the same as passed to AC_ARG_ENABLE. The prefix should +dnl be one of "use", "has", or "is", as is appropriate for the +dnl argument type. The target variable will be set to '1' if the +dnl enable argument is 'yes', and '0' otherwise. +dnl +dnl For instance, if the prefix is "has" and stem is "bob", +dnl then AC_ARG_ENABLE will set $enable_bob and this macro will set +dnl $has_bob based on the value in $enable_bob. See the examples +dnl in configure.ac. +dnl +dnl Note: As with AC_ARG_ENABLE, non-alphanumeric characters are +dnl transformed to underscores. +dnl +AC_DEFUN([TS_ARG_ENABLE_VAR],[ + tsl_prefix="AS_TR_SH($1)" + tsl_stem="AS_TR_SH($2)" + eval "tsl_enable=\$enable_${tsl_stem}" + AS_IF([test "x$tsl_enable" = "xyes"], + [eval "${tsl_prefix}_${tsl_stem}=1"], + [eval "${tsl_prefix}_${tsl_stem}=0"] + ) +]) + diff --git a/build/crypto.m4 b/build/crypto.m4 new file mode 100644 index 00000000..6d5e4057 --- /dev/null +++ b/build/crypto.m4 @@ -0,0 +1,111 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl crypto.m4 Trafficserver's Crypto autoconf macros +dnl + +dnl +dnl TS_CHECK_CRYPTO: look for crypto libraries and headers +dnl +AC_DEFUN([TS_CHECK_CRYPTO], [ + enable_crypto=no + AC_CHECK_LIB([crypt],[crypt],[AC_SUBST([LIBCRYPT],["-lcrypt"])]) + + TS_CHECK_CRYPTO_OPENSSL + dnl add checks for other varieties of ssl here +]) +dnl + +AC_DEFUN([TS_CHECK_CRYPTO_OPENSSL], [ +enable_openssl=no +AC_ARG_WITH(openssl, [AC_HELP_STRING([--with-openssl=DIR],[use a specific OpenSSL library])], +[ + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + openssl_base_dir="$withval" + if test "$withval" != "no"; then + enable_openssl=yes + case "$withval" in + *":"*) + openssl_include="`echo $withval |sed -e 's/:.*$//'`" + openssl_ldflags="`echo $withval |sed -e 's/^.*://'`" + AC_MSG_CHECKING(checking for OpenSSL includes in $openssl_include libs in $openssl_ldflags ) + ;; + *) + openssl_include="$withval/include" + openssl_ldflags="$withval/lib" + AC_MSG_CHECKING(checking for OpenSSL includes in $withval) + ;; + esac + fi + fi +]) + +if test "x$openssl_base_dir" = "x"; then + AC_MSG_CHECKING([for OpenSSL location]) + AC_CACHE_VAL(ats_cv_openssl_dir,[ + for dir in /usr/local/ssl /usr/pkg /usr/sfw /usr/local /usr; do + if test -d $dir && test -f $dir/include/openssl/x509.h; then + ats_cv_openssl_dir=$dir + break + fi + done + ]) + openssl_base_dir=$ats_cv_openssl_dir + if test "x$openssl_base_dir" = "x"; then + enable_openssl=no + AC_MSG_RESULT([not found]) + else + enable_openssl=yes + openssl_include="$openssl_base_dir/include" + openssl_ldflags="$openssl_base_dir/lib" + AC_MSG_RESULT([${openssl_base_dir}]) + fi +else + if test -d $openssl_include/openssl && test -d $openssl_ldflags && test -f $openssl_include/openssl/x509.h; then + AC_MSG_RESULT([ok]) + else + AC_MSG_RESULT([not found]) + fi +fi + +if test "$enable_openssl" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + openssl_have_headers=0 + openssl_have_libs=0 + if test "$openssl_base_dir" != "/usr"; then + TS_ADDTO(CPPFLAGS, [-I${openssl_include}]) + TS_ADDTO(LDFLAGS, [-L${openssl_ldflags}]) + TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R${openssl_ldflags}]) + fi + AC_CHECK_LIB(crypto, BN_init, AC_CHECK_LIB(ssl, SSL_accept, [openssl_have_libs=1],,-lcrypto)) + if test "$openssl_have_libs" != "0"; then + AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1]) + fi + if test "$openssl_have_headers" != "0"; then + AC_CHECK_DECLS([EVP_PKEY_CTX_new], [], [], + [#include ]) + enable_crypto=yes + AC_SUBST([LIBSSL],["-lssl -lcrypto"]) + else + enable_openssl=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi + +]) diff --git a/build/libtool.m4 b/build/libtool.m4 new file mode 100644 index 00000000..88de383a --- /dev/null +++ b/build/libtool.m4 @@ -0,0 +1,7835 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010 Free Software Foundation, +# Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010 Free Software Foundation, +# Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/build/ltoptions.m4 b/build/ltoptions.m4 new file mode 100644 index 00000000..17cfd51c --- /dev/null +++ b/build/ltoptions.m4 @@ -0,0 +1,369 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/build/ltsugar.m4 b/build/ltsugar.m4 new file mode 100644 index 00000000..9000a057 --- /dev/null +++ b/build/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/build/ltversion.m4 b/build/ltversion.m4 new file mode 100644 index 00000000..9c7b5d41 --- /dev/null +++ b/build/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3293 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4]) +m4_define([LT_PACKAGE_REVISION], [1.3293]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4' +macro_revision='1.3293' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/build/lt~obsolete.m4 b/build/lt~obsolete.m4 new file mode 100644 index 00000000..c573da90 --- /dev/null +++ b/build/lt~obsolete.m4 @@ -0,0 +1,98 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/build/lzma.m4 b/build/lzma.m4 new file mode 100644 index 00000000..482ec14e --- /dev/null +++ b/build/lzma.m4 @@ -0,0 +1,100 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl lzma.m4: Trafficserver's lzma autoconf macros +dnl + +dnl +dnl TS_CHECK_LZMA: look for lzma libraries and headers +dnl +AC_DEFUN([TS_CHECK_LZMA], [ +enable_lzma=no +AC_ARG_WITH(lzma, [AC_HELP_STRING([--with-lzma=DIR],[use a specific lzma library])], +[ + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + lzma_base_dir="$withval" + if test "$withval" != "no"; then + enable_lzma=yes + case "$withval" in + *":"*) + lzma_include="`echo $withval |sed -e 's/:.*$//'`" + lzma_ldflags="`echo $withval |sed -e 's/^.*://'`" + AC_MSG_CHECKING(checking for lzma includes in $lzma_include libs in $lzma_ldflags ) + ;; + *) + lzma_include="$withval/include" + lzma_ldflags="$withval/lib" + AC_MSG_CHECKING(checking for lzma includes in $withval) + ;; + esac + fi + fi +]) + +if test "x$lzma_base_dir" = "x"; then + AC_MSG_CHECKING([for lzma location]) + AC_CACHE_VAL(ats_cv_lzma_dir,[ + for dir in /usr/local /usr ; do + if test -d $dir && test -f $dir/include/lzma.h; then + ats_cv_lzma_dir=$dir + break + fi + done + ]) + lzma_base_dir=$ats_cv_lzma_dir + if test "x$lzma_base_dir" = "x"; then + enable_lzma=no + AC_MSG_RESULT([not found]) + else + enable_lzma=yes + lzma_include="$lzma_base_dir/include" + lzma_ldflags="$lzma_base_dir/lib" + AC_MSG_RESULT([$lzma_base_dir]) + fi +else + if test -d $lzma_include && test -d $lzma_ldflags && test -f $lzma_include/lzma.h; then + AC_MSG_RESULT([ok]) + else + AC_MSG_RESULT([not found]) + fi +fi + +lzmah=0 +if test "$enable_lzma" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + lzma_have_headers=0 + lzma_have_libs=0 + if test "$lzma_base_dir" != "/usr"; then + TS_ADDTO(CPPFLAGS, [-I${lzma_include}]) + TS_ADDTO(LDFLAGS, [-L${lzma_ldflags}]) + TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R${lzma_ldflags}]) + fi + AC_CHECK_LIB(lzma, lzma_code, [lzma_have_libs=1]) + if test "$lzma_have_libs" != "0"; then + TS_FLAG_HEADERS(lzma.h, [lzma_have_headers=1]) + fi + if test "$lzma_have_headers" != "0"; then + TS_ADDTO(LIBS, [-llzma]) + else + enable_lzma=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi +AC_SUBST(lzmah) +]) diff --git a/build/network.m4 b/build/network.m4 new file mode 100644 index 00000000..70f1a352 --- /dev/null +++ b/build/network.m4 @@ -0,0 +1,114 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl ----------------------------------------------------------------- +dnl network.m4: Trafficserver's autoconf macros for testing network support +dnl + +dnl +dnl Checks the definition of gethostbyname_r and gethostbyaddr_r +dnl which are different for glibc, solaris and assorted other operating +dnl systems +dnl +dnl Note that this test is executed too early to see if we have all of +dnl the headers. +AC_DEFUN([TS_CHECK_GETHOSTBYNAME_R_STYLE], [ + +dnl Try and compile a glibc2 gethostbyname_r piece of code, and set the +dnl style of the routines to glibc2 on success +AC_CACHE_CHECK([style of gethostbyname_r routine], ac_cv_gethostbyname_r_style, +TS_TRY_COMPILE_NO_WARNING([ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +],[ +int tmp = gethostbyname_r((const char *) 0, (struct hostent *) 0, + (char *) 0, 0, (struct hostent **) 0, &tmp); +/* use tmp to suppress the warning */ +tmp=0; +], ac_cv_gethostbyname_r_style=glibc2, ac_cv_gethostbyname_r_style=none)) + +if test "$ac_cv_gethostbyname_r_style" = "glibc2"; then + gethostbyname_r_glibc2=1 + AC_DEFINE(GETHOSTBYNAME_R_GLIBC2, 1, [Define if gethostbyname_r has the glibc style]) +else + gethostbyname_r_glibc2=0 +fi + +AC_CACHE_CHECK([3rd argument to the gethostbyname_r routines], ac_cv_gethostbyname_r_arg, +TS_TRY_COMPILE_NO_WARNING([ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +],[ +int tmp = gethostbyname_r((const char *) 0, (struct hostent *) 0, + (struct hostent_data *) 0); +/* use tmp to suppress the warning */ +tmp=0; +], ac_cv_gethostbyname_r_arg=hostent_data, ac_cv_gethostbyname_r_arg=char)) + +if test "$ac_cv_gethostbyname_r_arg" = "hostent_data"; then + gethostbyname_r_hostent_data=1 + AC_DEFINE(GETHOSTBYNAME_R_HOSTENT_DATA, 1, [Define if gethostbyname_r has the hostent_data for the third argument]) +else + gethostbyname_r_hostent_data=0 +fi +AC_SUBST(gethostbyname_r_glibc2) +AC_SUBST(gethostbyname_r_hostent_data) +]) + +dnl +dnl TS_CHECK_LOOPBACK_IFACE: try to figure out default loopback interface +dnl +AC_DEFUN([TS_CHECK_LOOPBACK_IFACE], [ +default_loopback_iface="" +AC_MSG_CHECKING([for loopback network interface]) +case $host_os in + linux*) + default_loopback_iface=lo + ;; +darwin* | freebsd* | solaris*) + default_loopback_iface=lo0 + ;; +esac +AC_MSG_RESULT([$default_loopback_iface]) +AC_SUBST([default_loopback_iface]) +]) +dnl diff --git a/build/pcre.m4 b/build/pcre.m4 new file mode 100644 index 00000000..a90b115d --- /dev/null +++ b/build/pcre.m4 @@ -0,0 +1,104 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl pcre.m4: Trafficserver's pcre autoconf macros +dnl + +dnl +dnl TS_CHECK_PCRE: look for pcre libraries and headers +dnl +AC_DEFUN([TS_CHECK_PCRE], [ +enable_pcre=no +AC_ARG_WITH(pcre, [AC_HELP_STRING([--with-pcre=DIR],[use a specific pcre library])], +[ + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + pcre_base_dir="$withval" + if test "$withval" != "no"; then + enable_pcre=yes + case "$withval" in + *":"*) + pcre_include="`echo $withval |sed -e 's/:.*$//'`" + pcre_ldflags="`echo $withval |sed -e 's/^.*://'`" + AC_MSG_CHECKING(checking for pcre includes in $pcre_include libs in $pcre_ldflags ) + ;; + *) + pcre_include="$withval/include" + pcre_ldflags="$withval/lib" + AC_MSG_CHECKING(checking for pcre includes in $withval) + ;; + esac + fi + fi +]) + +if test "x$pcre_base_dir" = "x"; then + AC_MSG_CHECKING([for pcre location]) + AC_CACHE_VAL(ats_cv_pcre_dir,[ + for dir in /usr/local /usr ; do + if test -d $dir && ( test -f $dir/include/pcre.h || test -f $dir/include/pcre/pcre.h ); then + ats_cv_pcre_dir=$dir + break + fi + done + ]) + pcre_base_dir=$ats_cv_pcre_dir + if test "x$pcre_base_dir" = "x"; then + enable_pcre=no + AC_MSG_RESULT([not found]) + else + enable_pcre=yes + pcre_include="$pcre_base_dir/include" + pcre_ldflags="$pcre_base_dir/lib" + AC_MSG_RESULT([$pcre_base_dir]) + fi +else + if test -d $pcre_include && test -d $pcre_ldflags && ( test -f $pcre_include/pcre.h || test -f $pcre_include/pcre/pcre.h ); then + AC_MSG_RESULT([ok]) + else + AC_MSG_RESULT([not found]) + fi +fi + +pcreh=0 +pcre_pcreh=0 +if test "$enable_pcre" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + pcre_have_headers=0 + pcre_have_libs=0 + if test "$pcre_base_dir" != "/usr"; then + TS_ADDTO(CPPFLAGS, [-I${pcre_include}]) + TS_ADDTO(LDFLAGS, [-L${pcre_ldflags}]) + TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R${pcre_ldflags}]) + fi + AC_CHECK_LIB(pcre, pcre_exec, [pcre_have_libs=1]) + if test "$pcre_have_libs" != "0"; then + TS_FLAG_HEADERS(pcre.h, [pcre_have_headers=1]) + TS_FLAG_HEADERS(pcre/pcre.h, [pcre_have_headers=1]) + fi + if test "$pcre_have_headers" != "0"; then + AC_DEFINE(HAVE_LIBPCRE,1,[Compiling with pcre support]) + AC_SUBST(LIBPCRE, [-lpcre]) + else + enable_pcre=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi +AC_SUBST(pcreh) +AC_SUBST(pcre_pcreh) +]) diff --git a/build/tcl.m4 b/build/tcl.m4 new file mode 100644 index 00000000..7ab726bb --- /dev/null +++ b/build/tcl.m4 @@ -0,0 +1,3302 @@ +#------------------------------------------------------------------------ +# SC_PATH_TCLCONFIG -- +# +# Locate the tclConfig.sh file and perform a sanity check on +# the Tcl compile flags +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tcl=... +# +# Defines the following vars: +# TCL_BIN_DIR Full path to the directory containing +# the tclConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([SC_PATH_TCLCONFIG], [ + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + AC_ARG_WITH(tcl, + AC_HELP_STRING([--with-tcl], + [directory containing tcl configuration (tclConfig.sh)]), + with_tclconfig="${withval}") + AC_MSG_CHECKING([for Tcl configuration]) + AC_CACHE_VAL(ac_cv_c_tclconfig,[ + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tcl.framework/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -dr ${exec_prefix}/lib/tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${exec_prefix}/lib/tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${exec_prefix}/lib/tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -dr ${prefix}/lib/tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${prefix}/lib/tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${prefix}/lib/tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -dr /usr/lib64/tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/lib64/tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr /usr/lib64/tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -dr /usr/contrib/lib/tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/contrib/lib/tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr /usr/contrib/lib/tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -dr /usr/lib/tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr /usr/lib/tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr /usr/lib/tcl[[8-9]].[[0-9]]* 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + AC_MSG_ERROR([Can't find Tcl configuration, install the TCL dev package]) + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# SC_PATH_TKCONFIG -- +# +# Locate the tkConfig.sh file +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --with-tk=... +# +# Defines the following vars: +# TK_BIN_DIR Full path to the directory containing +# the tkConfig.sh file +#------------------------------------------------------------------------ + +AC_DEFUN([SC_PATH_TKCONFIG], [ + # + # Ok, lets find the tk configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tk + # + + if test x"${no_tk}" = x ; then + # we reset no_tk in case something fails here + no_tk=true + AC_ARG_WITH(tk, + AC_HELP_STRING([--with-tk], + [directory containing tk configuration (tkConfig.sh)]), + with_tkconfig="${withval}") + AC_MSG_CHECKING([for Tk configuration]) + AC_CACHE_VAL(ac_cv_c_tkconfig,[ + + # First check to see if --with-tkconfig was specified. + if test x"${with_tkconfig}" != x ; then + case "${with_tkconfig}" in + */tkConfig.sh ) + if test -f "${with_tkconfig}"; then + AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) + with_tkconfig="`echo "${with_tkconfig}" | sed 's!/tkConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tkconfig}/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd "${with_tkconfig}"; pwd)`" + else + AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) + fi + fi + + # then check for a private Tk library + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ../tk \ + `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../tk \ + `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ + ../../../tk \ + `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tk.framework/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + ; do + if test -f "$i/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tkconfig}" = x ; then + for i in \ + ${srcdir}/../tk \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ + `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do + if test -f "$i/unix/tkConfig.sh" ; then + ac_cv_c_tkconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + ]) + + if test x"${ac_cv_c_tkconfig}" = x ; then + TK_BIN_DIR="# no Tk configs found" + AC_MSG_WARN([Can't find Tk configuration definitions]) + exit 0 + else + no_tk= + TK_BIN_DIR="${ac_cv_c_tkconfig}" + AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh]) + fi + fi +]) + +#------------------------------------------------------------------------ +# SC_LOAD_TCLCONFIG -- +# +# Load the tclConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TCL_BIN_DIR +# +# Results: +# +# Subst the following vars: +# TCL_BIN_DIR +# TCL_SRC_DIR +# TCL_LIB_FILE +# +#------------------------------------------------------------------------ + +AC_DEFUN([SC_LOAD_TCLCONFIG], [ + AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) + + if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TCL_BIN_DIR}/tclConfig.sh" + else + AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tcl.framework installed in an arbitary location. + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then + for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ + "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then + TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" + break + fi + done + fi + if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then + TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" + TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + AC_SUBST(TCL_VERSION) + AC_SUBST(TCL_PATCH_LEVEL) + AC_SUBST(TCL_BIN_DIR) + AC_SUBST(TCL_SRC_DIR) + + AC_SUBST(TCL_LIB_FILE) + AC_SUBST(TCL_LIB_FLAG) + AC_SUBST(TCL_LIB_SPEC) + + AC_SUBST(TCL_STUB_LIB_FILE) + AC_SUBST(TCL_STUB_LIB_FLAG) + AC_SUBST(TCL_STUB_LIB_SPEC) +]) + +#------------------------------------------------------------------------ +# SC_LOAD_TKCONFIG -- +# +# Load the tkConfig.sh file +# +# Arguments: +# +# Requires the following vars to be set: +# TK_BIN_DIR +# +# Results: +# +# Sets the following vars that should be in tkConfig.sh: +# TK_BIN_DIR +#------------------------------------------------------------------------ + +AC_DEFUN([SC_LOAD_TKCONFIG], [ + AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) + + if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then + AC_MSG_RESULT([loading]) + . "${TK_BIN_DIR}/tkConfig.sh" + else + AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" + eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" + + # If the TK_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TK_LIB_SPEC will be set to the value + # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC + # instead of TK_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TK_BIN_DIR}/Makefile" ; then + TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}" + TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}" + TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tk was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tk.framework installed in an arbitary location. + case ${TK_DEFS} in + *TK_FRAMEWORK*) + if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then + for i in "`cd "${TK_BIN_DIR}"; pwd`" \ + "`cd "${TK_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then + TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}" + break + fi + done + fi + if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then + TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" + TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TK_DBGX substitution + eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" + eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" + eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" + eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" + + AC_SUBST(TK_VERSION) + AC_SUBST(TK_BIN_DIR) + AC_SUBST(TK_SRC_DIR) + + AC_SUBST(TK_LIB_FILE) + AC_SUBST(TK_LIB_FLAG) + AC_SUBST(TK_LIB_SPEC) + + AC_SUBST(TK_STUB_LIB_FILE) + AC_SUBST(TK_STUB_LIB_FLAG) + AC_SUBST(TK_STUB_LIB_SPEC) +]) + +#------------------------------------------------------------------------ +# SC_PROG_TCLSH +# Locate a tclsh shell installed on the system path. This macro +# will only find a Tcl shell that already exists on the system. +# It will not find a Tcl shell in the Tcl build directory or +# a Tcl shell that has been installed from the Tcl build directory. +# If a Tcl shell can't be located on the PATH, then TCLSH_PROG will +# be set to "". Extensions should take care not to create Makefile +# rules that are run by default and depend on TCLSH_PROG. An +# extension can't assume that an executable Tcl shell exists at +# build time. +# +# Arguments +# none +# +# Results +# Subst's the following values: +# TCLSH_PROG +#------------------------------------------------------------------------ + +AC_DEFUN([SC_PROG_TCLSH], [ + AC_MSG_CHECKING([for tclsh]) + AC_CACHE_VAL(ac_cv_path_tclsh, [ + search_path=`echo ${PATH} | sed -e 's/:/ /g'` + for dir in $search_path ; do + for j in `ls -r $dir/tclsh[[8-9]]* 2> /dev/null` \ + `ls -r $dir/tclsh* 2> /dev/null` ; do + if test x"$ac_cv_path_tclsh" = x ; then + if test -f "$j" ; then + ac_cv_path_tclsh=$j + break + fi + fi + done + done + ]) + + if test -f "$ac_cv_path_tclsh" ; then + TCLSH_PROG="$ac_cv_path_tclsh" + AC_MSG_RESULT([$TCLSH_PROG]) + else + # It is not an error if an installed version of Tcl can't be located. + TCLSH_PROG="" + AC_MSG_RESULT([No tclsh found on PATH]) + fi + AC_SUBST(TCLSH_PROG) +]) + +#------------------------------------------------------------------------ +# SC_BUILD_TCLSH +# Determine the fully qualified path name of the tclsh executable +# in the Tcl build directory. This macro will correctly determine +# the name of the tclsh executable even if tclsh has not yet +# been built in the build directory. The build tclsh must be used +# when running tests from an extension build directory. It is not +# correct to use the TCLSH_PROG in cases like this. +# +# Arguments +# none +# +# Results +# Subst's the following values: +# BUILD_TCLSH +#------------------------------------------------------------------------ + +AC_DEFUN([SC_BUILD_TCLSH], [ + AC_MSG_CHECKING([for tclsh in Tcl build directory]) + BUILD_TCLSH="${TCL_BIN_DIR}"/tclsh + AC_MSG_RESULT([$BUILD_TCLSH]) + AC_SUBST(BUILD_TCLSH) +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_SHARED -- +# +# Allows the building of shared libraries +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-shared=yes|no +# +# Defines the following vars: +# STATIC_BUILD Used for building import/export libraries +# on Windows. +# +# Sets the following vars: +# SHARED_BUILD Value of 1 or 0 +#------------------------------------------------------------------------ + +AC_DEFUN([SC_ENABLE_SHARED], [ + AC_MSG_CHECKING([how to build libraries]) + AC_ARG_ENABLE(shared, + AC_HELP_STRING([--enable-shared], + [build and link with shared libraries (default: on)]), + [tcl_ok=$enableval], [tcl_ok=yes]) + + if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + tcl_ok=$enableval + else + tcl_ok=yes + fi + + if test "$tcl_ok" = "yes" ; then + AC_MSG_RESULT([shared]) + SHARED_BUILD=1 + else + AC_MSG_RESULT([static]) + SHARED_BUILD=0 + AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) + fi +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_FRAMEWORK -- +# +# Allows the building of shared libraries into frameworks +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-framework=yes|no +# +# Sets the following vars: +# FRAMEWORK_BUILD Value of 1 or 0 +#------------------------------------------------------------------------ + +AC_DEFUN([SC_ENABLE_FRAMEWORK], [ + if test "`uname -s`" = "Darwin" ; then + AC_MSG_CHECKING([how to package libraries]) + AC_ARG_ENABLE(framework, + AC_HELP_STRING([--enable-framework], + [package shared libraries in MacOSX frameworks (default: off)]), + [enable_framework=$enableval], [enable_framework=no]) + if test $enable_framework = yes; then + if test $SHARED_BUILD = 0; then + AC_MSG_WARN([Frameworks can only be built if --enable-shared is yes]) + enable_framework=no + fi + if test $tcl_corefoundation = no; then + AC_MSG_WARN([Frameworks can only be used when CoreFoundation is available]) + enable_framework=no + fi + fi + if test $enable_framework = yes; then + AC_MSG_RESULT([framework]) + FRAMEWORK_BUILD=1 + else + if test $SHARED_BUILD = 1; then + AC_MSG_RESULT([shared library]) + else + AC_MSG_RESULT([static library]) + fi + FRAMEWORK_BUILD=0 + fi + fi +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_THREADS -- +# +# Specify if thread support should be enabled +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-threads +# +# Sets the following vars: +# THREADS_LIBS Thread library(s) +# +# Defines the following vars: +# TCL_THREADS +# _REENTRANT +# _THREAD_SAFE +# +#------------------------------------------------------------------------ + +AC_DEFUN([SC_ENABLE_THREADS], [ + AC_ARG_ENABLE(threads, + AC_HELP_STRING([--enable-threads], + [build with threads (default: off)]), + [tcl_ok=$enableval], [tcl_ok=no]) + + if test "${TCL_THREADS}" = 1; then + tcl_threaded_core=1; + fi + + if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then + TCL_THREADS=1 + # USE_THREAD_ALLOC tells us to try the special thread-based + # allocator that significantly reduces lock contention + AC_DEFINE(USE_THREAD_ALLOC, 1, + [Do we want to use the threaded memory allocator?]) + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + if test "`uname -s`" = "SunOS" ; then + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + fi + AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) + AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) + if test "$tcl_ok" = "no"; then + # Check a little harder for __pthread_mutex_init in the same + # library, as some systems hide it there until pthread.h is + # defined. We could alternatively do an AC_TRY_COMPILE with + # pthread.h, but that will work with libpthread really doesn't + # exist, like AIX 4.2. [Bug: 4359] + AC_CHECK_LIB(pthread, __pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + fi + + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthread" + else + AC_CHECK_LIB(pthreads, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -lpthreads" + else + AC_CHECK_LIB(c, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "no"; then + AC_CHECK_LIB(c_r, pthread_mutex_init, + tcl_ok=yes, tcl_ok=no) + if test "$tcl_ok" = "yes"; then + # The space is needed + THREADS_LIBS=" -pthread" + else + TCL_THREADS=0 + AC_MSG_WARN([Don't know how to find pthread lib on your system - you must disable thread support or edit the LIBS in the Makefile...]) + fi + fi + fi + fi + + # Does the pthread-implementation provide + # 'pthread_attr_setstacksize' ? + + ac_saved_libs=$LIBS + LIBS="$LIBS $THREADS_LIBS" + AC_CHECK_FUNCS(pthread_attr_setstacksize) + AC_CHECK_FUNC(pthread_attr_get_np,tcl_ok=yes,tcl_ok=no) + if test $tcl_ok = yes ; then + AC_DEFINE(HAVE_PTHREAD_ATTR_GET_NP, 1, + [Do we want a BSD-like thread-attribute interface?]) + AC_CACHE_CHECK([for pthread_attr_get_np declaration], + tcl_cv_grep_pthread_attr_get_np, [ + AC_EGREP_HEADER(pthread_attr_get_np, pthread.h, + tcl_cv_grep_pthread_attr_get_np=present, + tcl_cv_grep_pthread_attr_get_np=missing)]) + if test $tcl_cv_grep_pthread_attr_get_np = missing ; then + AC_DEFINE(ATTRGETNP_NOT_DECLARED, 1, + [Is pthread_attr_get_np() declared in ?]) + fi + else + AC_CHECK_FUNC(pthread_getattr_np,tcl_ok=yes,tcl_ok=no) + if test $tcl_ok = yes ; then + AC_DEFINE(HAVE_PTHREAD_GETATTR_NP, 1, + [Do we want a Linux-like thread-attribute interface?]) + AC_CACHE_CHECK([for pthread_getattr_np declaration], + tcl_cv_grep_pthread_getattr_np, [ + AC_EGREP_HEADER(pthread_getattr_np, pthread.h, + tcl_cv_grep_pthread_getattr_np=present, + tcl_cv_grep_pthread_getattr_np=missing)]) + if test $tcl_cv_grep_pthread_getattr_np = missing ; then + AC_DEFINE(GETATTRNP_NOT_DECLARED, 1, + [Is pthread_getattr_np declared in ?]) + fi + fi + fi + if test $tcl_ok = no; then + # Darwin thread stacksize API + AC_CHECK_FUNCS(pthread_get_stacksize_np) + fi + LIBS=$ac_saved_libs + else + TCL_THREADS=0 + fi + # Do checking message here to not mess up interleaved configure output + AC_MSG_CHECKING([for building with threads]) + if test "${TCL_THREADS}" = 1; then + AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) + if test "${tcl_threaded_core}" = 1; then + AC_MSG_RESULT([yes (threaded core)]) + else + AC_MSG_RESULT([yes]) + fi + else + AC_MSG_RESULT([no (default)]) + fi + + AC_SUBST(TCL_THREADS) +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_SYMBOLS -- +# +# Specify if debugging symbols should be used. +# Memory (TCL_MEM_DEBUG) and compile (TCL_COMPILE_DEBUG) debugging +# can also be enabled. +# +# Arguments: +# none +# +# Requires the following vars to be set in the Makefile: +# CFLAGS_DEBUG +# CFLAGS_OPTIMIZE +# LDFLAGS_DEBUG +# LDFLAGS_OPTIMIZE +# +# Results: +# +# Adds the following arguments to configure: +# --enable-symbols +# +# Defines the following vars: +# CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true +# Sets to $(CFLAGS_OPTIMIZE) if false +# LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true +# Sets to $(LDFLAGS_OPTIMIZE) if false +# DBGX Formerly used as debug library extension; +# always blank now. +# +#------------------------------------------------------------------------ + +AC_DEFUN([SC_ENABLE_SYMBOLS], [ + AC_MSG_CHECKING([for build with symbols]) + AC_ARG_ENABLE(symbols, + AC_HELP_STRING([--enable-symbols], + [build with debugging symbols (default: off)]), + [tcl_ok=$enableval], [tcl_ok=no]) +# FIXME: Currently, LDFLAGS_DEFAULT is not used, it should work like CFLAGS_DEFAULT. + DBGX="" + if test "$tcl_ok" = "no"; then + CFLAGS_DEFAULT='$(CFLAGS_OPTIMIZE)' + LDFLAGS_DEFAULT='$(LDFLAGS_OPTIMIZE)' + AC_MSG_RESULT([no]) + AC_DEFINE(TCL_CFG_OPTIMIZED, 1, [Is this an optimized build?]) + else + CFLAGS_DEFAULT='$(CFLAGS_DEBUG)' + LDFLAGS_DEFAULT='$(LDFLAGS_DEBUG)' + if test "$tcl_ok" = "yes"; then + AC_MSG_RESULT([yes (standard debugging)]) + fi + fi + AC_SUBST(CFLAGS_DEFAULT) + AC_SUBST(LDFLAGS_DEFAULT) + ### FIXME: Surely TCL_CFG_DEBUG should be set to whether we're debugging? + AC_DEFINE(TCL_CFG_DEBUG, 1, [Is debugging enabled?]) + + if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) + fi + + ifelse($1,bccdebug,dnl Only enable 'compile' for the Tcl core itself + if test "$tcl_ok" = "compile" -o "$tcl_ok" = "all"; then + AC_DEFINE(TCL_COMPILE_DEBUG, 1, [Is bytecode debugging enabled?]) + AC_DEFINE(TCL_COMPILE_STATS, 1, [Are bytecode statistics enabled?]) + fi) + + if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then + if test "$tcl_ok" = "all"; then + AC_MSG_RESULT([enabled symbols mem ]ifelse($1,bccdebug,[compile ])[debugging]) + else + AC_MSG_RESULT([enabled $tcl_ok debugging]) + fi + fi +]) + +#------------------------------------------------------------------------ +# SC_ENABLE_LANGINFO -- +# +# Allows use of modern nl_langinfo check for better l10n. +# This is only relevant for Unix. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-langinfo=yes|no (default is yes) +# +# Defines the following vars: +# HAVE_LANGINFO Triggers use of nl_langinfo if defined. +# +#------------------------------------------------------------------------ + +AC_DEFUN([SC_ENABLE_LANGINFO], [ + AC_ARG_ENABLE(langinfo, + AC_HELP_STRING([--enable-langinfo], + [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), + [langinfo_ok=$enableval], [langinfo_ok=yes]) + + HAVE_LANGINFO=0 + if test "$langinfo_ok" = "yes"; then + AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) + fi + AC_MSG_CHECKING([whether to use nl_langinfo]) + if test "$langinfo_ok" = "yes"; then + AC_CACHE_VAL(tcl_cv_langinfo_h, [ + AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], + [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) + AC_MSG_RESULT([$tcl_cv_langinfo_h]) + if test $tcl_cv_langinfo_h = yes; then + AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) + fi + else + AC_MSG_RESULT([$langinfo_ok]) + fi +]) + +#-------------------------------------------------------------------- +# SC_CONFIG_MANPAGES +# +# Decide whether to use symlinks for linking the manpages, +# whether to compress the manpages after installation, and +# whether to add a package name suffix to the installed +# manpages to avoidfile name clashes. +# If compression is enabled also find out what file name suffix +# the given compression program is using. +# +# Arguments: +# none +# +# Results: +# +# Adds the following arguments to configure: +# --enable-man-symlinks +# --enable-man-compression=PROG +# --enable-man-suffix[=STRING] +# +# Defines the following variable: +# +# MAN_FLAGS - The apropriate flags for installManPage +# according to the user's selection. +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_CONFIG_MANPAGES], [ + AC_MSG_CHECKING([whether to use symlinks for manpages]) + AC_ARG_ENABLE(man-symlinks, + AC_HELP_STRING([--enable-man-symlinks], + [use symlinks for the manpages (default: off)]), + test "$enableval" != "no" && MAN_FLAGS="$MAN_FLAGS --symlinks", + enableval="no") + AC_MSG_RESULT([$enableval]) + + AC_MSG_CHECKING([whether to compress the manpages]) + AC_ARG_ENABLE(man-compression, + AC_HELP_STRING([--enable-man-compression=PROG], + [compress the manpages with PROG (default: off)]), + [case $enableval in + yes) AC_MSG_ERROR([missing argument to --enable-man-compression]);; + no) ;; + *) MAN_FLAGS="$MAN_FLAGS --compress $enableval";; + esac], + enableval="no") + AC_MSG_RESULT([$enableval]) + if test "$enableval" != "no"; then + AC_MSG_CHECKING([for compressed file suffix]) + touch TeST + $enableval TeST + Z=`ls TeST* | sed 's/^....//'` + rm -f TeST* + MAN_FLAGS="$MAN_FLAGS --extension $Z" + AC_MSG_RESULT([$Z]) + fi + + AC_MSG_CHECKING([whether to add a package name suffix for the manpages]) + AC_ARG_ENABLE(man-suffix, + AC_HELP_STRING([--enable-man-suffix=STRING], + [use STRING as a suffix to manpage file names (default: no, AC_PACKAGE_NAME if enabled without specifying STRING)]), + [case $enableval in + yes) enableval="AC_PACKAGE_NAME" MAN_FLAGS="$MAN_FLAGS --suffix $enableval";; + no) ;; + *) MAN_FLAGS="$MAN_FLAGS --suffix $enableval";; + esac], + enableval="no") + AC_MSG_RESULT([$enableval]) + + AC_SUBST(MAN_FLAGS) +]) + +#-------------------------------------------------------------------- +# SC_CONFIG_SYSTEM +# +# Determine what the system is (some things cannot be easily checked +# on a feature-driven basis, alas). This can usually be done via the +# "uname" command, but there are a few systems, like Next, where +# this doesn't work. +# +# Arguments: +# none +# +# Results: +# Defines the following var: +# +# system - System/platform/version identification code. +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_CONFIG_SYSTEM], [ + AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ + if test -f /usr/lib/NextStep/software_version; then + tcl_cv_sys_version=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` + else + tcl_cv_sys_version=`uname -s`-`uname -r` + if test "$?" -ne 0 ; then + AC_MSG_WARN([can't find uname command]) + tcl_cv_sys_version=unknown + else + # Special check for weird MP-RAS system (uname returns weird + # results, and the version is kept in special file). + + if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then + tcl_cv_sys_version=MP-RAS-`awk '{print $[3]}' /etc/.relid` + fi + if test "`uname -s`" = "AIX" ; then + tcl_cv_sys_version=AIX-`uname -v`.`uname -r` + fi + fi + fi + ]) + system=$tcl_cv_sys_version +]) + +#-------------------------------------------------------------------- +# SC_CONFIG_CFLAGS +# +# Try to determine the proper flags to pass to the compiler +# for building shared libraries and other such nonsense. +# +# Arguments: +# none +# +# Results: +# +# Defines and substitutes the following vars: +# +# DL_OBJS - Name of the object file that implements dynamic +# loading for Tcl on this system. +# DL_LIBS - Library file(s) to include in tclsh and other base +# applications in order for the "load" command to work. +# LDFLAGS - Flags to pass to the compiler when linking object +# files into an executable application binary such +# as tclsh. +# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. Could +# be the same as CC_SEARCH_FLAGS if ${CC} is used to link. +# CC_SEARCH_FLAGS-Flags to pass to ${CC}, such as "-Wl,-rpath,/usr/local/tcl/lib", +# that tell the run-time dynamic linker where to look +# for shared libraries such as libtcl.so. Depends on +# the variable LIB_RUNTIME_DIR in the Makefile. +# MAKE_LIB - Command to execute to build the a library; +# differs when building shared or static. +# MAKE_STUB_LIB - +# Command to execute to build a stub library. +# INSTALL_LIB - Command to execute to install a library; +# differs when building shared or static. +# INSTALL_STUB_LIB - +# Command to execute to install a stub library. +# STLIB_LD - Base command to use for combining object files +# into a static library. +# SHLIB_CFLAGS - Flags to pass to cc when compiling the components +# of a shared library (may request position-independent +# code, among other things). +# SHLIB_LD - Base command to use for combining object files +# into a shared library. +# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when +# creating shared libraries. This symbol typically +# goes at the end of the "ld" commands that build +# shared libraries. The value of the symbol is +# "${LIBS}" if all of the dependent libraries should +# be specified when creating a shared library. If +# dependent libraries should not be specified (as on +# SunOS 4.x, where they cause the link to fail, or in +# general if Tcl and Tk aren't themselves shared +# libraries), then this symbol has an empty string +# as its value. +# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable +# extensions. An empty string means we don't know how +# to use shared libraries on this platform. +# TCL_SHLIB_LD_EXTRAS - Additional element which are added to SHLIB_LD_LIBS +# TK_SHLIB_LD_EXTRAS for the build of Tcl and Tk, but not recorded in the +# tclConfig.sh, since they are only used for the build +# of Tcl and Tk. +# Examples: MacOS X records the library version and +# compatibility version in the shared library. But +# of course the Tcl version of this is only used for Tcl. +# LIB_SUFFIX - Specifies everything that comes after the "libfoo" +# in a static or shared library name, using the $VERSION variable +# to put the version in the right place. This is used +# by platforms that need non-standard library names. +# Examples: ${VERSION}.so.1.1 on NetBSD, since it needs +# to have a version after the .so, and ${VERSION}.a +# on AIX, since a shared library needs to have +# a .a extension whereas shared objects for loadable +# extensions have a .so extension. Defaults to +# ${VERSION}${SHLIB_SUFFIX}. +# TCL_NEEDS_EXP_FILE - +# 1 means that an export file is needed to link to a +# shared library. +# TCL_EXP_FILE - The name of the installed export / import file which +# should be used to link to the Tcl shared library. +# Empty if Tcl is unshared. +# TCL_BUILD_EXP_FILE - +# The name of the built export / import file which +# should be used to link to the Tcl shared library. +# Empty if Tcl is unshared. +# TCL_LIBS - +# Libs to use when linking Tcl shell or some other +# shell that includes Tcl libs. +# CFLAGS_DEBUG - +# Flags used when running the compiler in debug mode +# CFLAGS_OPTIMIZE - +# Flags used when running the compiler in optimize mode +# CFLAGS - Additional CFLAGS added as necessary (usually 64-bit) +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_CONFIG_CFLAGS], [ + + # Step 0.a: Enable 64 bit support? + + AC_MSG_CHECKING([if 64bit support is requested]) + AC_ARG_ENABLE(64bit, + AC_HELP_STRING([--enable-64bit], + [enable 64bit support (default: off)]), + [do64bit=$enableval], [do64bit=no]) + AC_MSG_RESULT([$do64bit]) + + # Step 0.b: Enable Solaris 64 bit VIS support? + + AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) + AC_ARG_ENABLE(64bit-vis, + AC_HELP_STRING([--enable-64bit-vis], + [enable 64bit Sparc VIS support (default: off)]), + [do64bitVIS=$enableval], [do64bitVIS=no]) + AC_MSG_RESULT([$do64bitVIS]) + # Force 64bit on with VIS + AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) + + # Step 0.c: Check if visibility support is available. Do this here so + # that platform specific alternatives can be used below if this fails. + + AC_CACHE_CHECK([if compiler supports visibility "hidden"], + tcl_cv_cc_visibility_hidden, [ + hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" + AC_TRY_LINK([ + extern __attribute__((__visibility__("hidden"))) void f(void); + void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, + tcl_cv_cc_visibility_hidden=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ + AC_DEFINE(MODULE_SCOPE, + [extern __attribute__((__visibility__("hidden")))], + [Compiler support for module scope symbols]) + ]) + + # Step 0.d: Disable -rpath support? + + AC_MSG_CHECKING([if rpath support is requested]) + AC_ARG_ENABLE(rpath, + AC_HELP_STRING([--disable-rpath], + [disable rpath support (default: on)]), + [doRpath=$enableval], [doRpath=yes]) + AC_MSG_RESULT([$doRpath]) + + # Step 1: set the variable "system" to hold the name and version number + # for the system. + + SC_CONFIG_SYSTEM + + # Step 2: check for existence of -ldl library. This is needed because + # Linux can use either -ldl or -ldld for dynamic loading. + + AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) + + # Require ranlib early so we can override it in special cases below. + LDAIX_SRC="" + AS_IF([test x"${SHLIB_VERSION}" = x], [SHLIB_VERSION="1.0"]) + + AC_REQUIRE([AC_PROG_RANLIB]) + + # Step 3: set configuration options based on system name and version. + + do64bit_ok=no + LDFLAGS_ORIG="$LDFLAGS" + # When ld needs options to work in 64-bit mode, put them in + # LDFLAGS_ARCH so they eventually end up in LDFLAGS even if [load] + # is disabled by the user. [Bug 1016796] + LDFLAGS_ARCH="" + TCL_EXPORT_FILE_SUFFIX="" + UNSHARED_LIB_SUFFIX="" + TCL_TRIM_DOTS='`echo ${VERSION} | tr -d .`' + ECHO_VERSION='`echo ${VERSION}`' + TCL_LIB_VERSIONS_OK=ok + CFLAGS_DEBUG=-g + CFLAGS_OPTIMIZE=-O + AS_IF([test "$GCC" = yes], [ + CFLAGS_WARNING="-Wall" + ], [CFLAGS_WARNING=""]) + TCL_NEEDS_EXP_FILE=0 + TCL_BUILD_EXP_FILE="" + TCL_EXP_FILE="" +dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. +dnl AC_CHECK_TOOL(AR, ar) + AC_CHECK_PROG(AR, ar, ar) + AS_IF([test "${AR}" = ""], [ + AC_MSG_ERROR([Required archive tool 'ar' not found on PATH.]) + ]) + STLIB_LD='${AR} cr' + LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" + PLAT_OBJS="" + PLAT_SRCS="" + case $system in + AIX-*) + AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ + # AIX requires the _r compiler when gcc isn't being used + case "${CC}" in + *_r) + # ok ... + ;; + *) + CC=${CC}_r + ;; + esac + AC_MSG_RESULT([Using $CC for compiling with threads]) + ]) + LIBS="$LIBS -lc" + SHLIB_CFLAGS="" + # Note: need the LIBS below, otherwise Tk won't find Tcl's + # symbols when dynamically loaded into tclsh. + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + + DL_OBJS="tclLoadDl.o" + LD_LIBRARY_PATH_VAR="LIBPATH" + + # Check to enable 64-bit flags for compiler/linker on AIX 4+ + LDAIX_SRC='$(UNIX_DIR)/ldAix' + AS_IF([test "$do64bit" = yes -a "`uname -v`" -gt 3], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -q64" + LDFLAGS_ARCH="-q64" + RANLIB="${RANLIB} -X64" + AR="${AR} -X64" + SHLIB_LD_FLAGS="-b64" + ]) + ]) + + AS_IF([test "`uname -m`" = ia64], [ + # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + # AIX-5 has dl* in libc.so + DL_LIBS="" + AS_IF([test "$GCC" = yes], [ + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + ], [ + CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' + ]) + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ], [ + AS_IF([test "$GCC" = yes], [SHLIB_LD='${CC} -shared'], [ + SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" + ]) + SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + TCL_NEEDS_EXP_FILE=1 + TCL_EXPORT_FILE_SUFFIX='${VERSION}.exp' + ]) + + # AIX v<=4.1 has some different flags than 4.2+ + AS_IF([test "$system" = "AIX-4.1" -o "`uname -v`" -lt 4], [ + AC_LIBOBJ([tclLoadAix]) + DL_LIBS="-lld" + ]) + + # On AIX <=v4 systems, libbsd.a has to be linked in to support + # non-blocking file IO. This library has to be linked in after + # the MATH_LIBS or it breaks the pow() function. The way to + # insure proper sequencing, is to add it to the tail of MATH_LIBS. + # This library also supplies gettimeofday. + # + # AIX does not have a timezone field in struct tm. When the AIX + # bsd library is used, the timezone global and the gettimeofday + # methods are to be avoided for timezone deduction instead, we + # deduce the timezone by comparing the localtime result on a + # known GMT value. + + AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) + AS_IF([test $libbsd = yes], [ + MATH_LIBS="$MATH_LIBS -lbsd" + AC_DEFINE(USE_DELTA_FOR_TZ, 1, [Do we need a special AIX hack for timezones?]) + ]) + ;; + BeOS*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -nostart' + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + + #----------------------------------------------------------- + # Check for inet_ntoa in -lbind, for BeOS (which also needs + # -lsocket, even if the network functions are in -lnet which + # is always linked to, for compatibility. + #----------------------------------------------------------- + AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) + ;; + BSD/OS-2.1*|BSD/OS-3*) + SHLIB_CFLAGS="" + SHLIB_LD="shlicc -r" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + BSD/OS-4.*) + SHLIB_CFLAGS="-export-dynamic -fPIC" + SHLIB_LD='${CC} -shared' + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="$LDFLAGS -export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + dgux*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + HP-UX-*.11.*) + # Use updated header definitions where possible + AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) + AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) + LIBS="$LIBS -lxnet" # Use the XOPEN network library + + AS_IF([test "`uname -m`" = ia64], [ + SHLIB_SUFFIX=".so" + ], [ + SHLIB_SUFFIX=".sl" + ]) + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + SHLIB_LD_LIBS='${LIBS}' + DL_OBJS="tclLoadShl.o" + DL_LIBS="-ldld" + LDFLAGS="$LDFLAGS -Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + ]) + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + SHLIB_LD_LIBS='${LIBS}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + + # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc + #CFLAGS="$CFLAGS +DAportable" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = "yes"], [ + AS_IF([test "$GCC" = yes], [ + case `${CC} -dumpmachine` in + hppa64*) + # 64-bit gcc in use. Fix flags for GNU ld. + do64bit_ok=yes + SHLIB_LD='${CC} -shared' + SHLIB_LD_LIBS='${LIBS}' + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ;; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]) + ;; + esac + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS +DD64" + LDFLAGS_ARCH="+DD64" + ]) + ]) ;; + HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) + SHLIB_SUFFIX=".sl" + AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) + AS_IF([test "$tcl_ok" = yes], [ + SHLIB_CFLAGS="+z" + SHLIB_LD="ld -b" + SHLIB_LD_LIBS="" + DL_OBJS="tclLoadShl.o" + DL_LIBS="-ldld" + LDFLAGS="$LDFLAGS -Wl,-E" + CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' + LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' + LD_LIBRARY_PATH_VAR="SHLIB_PATH" + ]) ;; + IRIX-5.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -shared -rdata_shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + ;; + IRIX-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [ + CFLAGS="$CFLAGS -mabi=n32" + LDFLAGS="$LDFLAGS -mabi=n32" + ], [ + case $system in + IRIX-6.3) + # Use to build 6.2 compatible binaries on 6.3. + CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" + ;; + *) + CFLAGS="$CFLAGS -n32" + ;; + esac + LDFLAGS="$LDFLAGS -n32" + ]) + ;; + IRIX64-6.*) + SHLIB_CFLAGS="" + SHLIB_LD="ld -n32 -shared -rdata_shared" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + + # Check to enable 64-bit flags for compiler/linker + + AS_IF([test "$do64bit" = yes], [ + AS_IF([test "$GCC" = yes], [ + AC_MSG_WARN([64bit mode not supported by gcc]) + ], [ + do64bit_ok=yes + SHLIB_LD="ld -64 -shared -rdata_shared" + CFLAGS="$CFLAGS -64" + LDFLAGS_ARCH="-64" + ]) + ]) + ;; + Linux*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + + CFLAGS_OPTIMIZE="-O2" + # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings + # when you inline the string and math operations. Turn this off to + # get rid of the warnings. + #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" + + SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + AS_IF([test $do64bit = yes], [ + AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -m64" + AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_m64 = yes], [ + CFLAGS="$CFLAGS -m64" + do64bit_ok=yes + ]) + ]) + + # The combo of gcc + glibc has a bug related to inlining of + # functions like strtod(). The -fno-builtin flag should address + # this problem but it does not work. The -fno-inline flag is kind + # of overkill but it works. Disable inlining only when one of the + # files in compat/*.c is being linked in. + + AS_IF([test x"${USE_COMPAT}" != x],[CFLAGS="$CFLAGS -fno-inline"]) + ;; + GNU*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + + SHLIB_LD='${CC} -shared' + DL_OBJS="" + DL_LIBS="-ldl" + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) + ;; + Lynx*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + CFLAGS_OPTIMIZE=-02 + SHLIB_LD='${CC} -shared' + DL_OBJS="tclLoadDl.o" + DL_LIBS="-mshared -ldl" + LD_FLAGS="-Wl,--export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + ;; + MP-RAS-02*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + MP-RAS-*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + LDFLAGS="$LDFLAGS -Wl,-Bexport" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + NetBSD-1.*|FreeBSD-[[1-2]].*) + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ + AC_EGREP_CPP(yes, [ +#ifdef __ELF__ + yes +#endif + ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) + AS_IF([test $tcl_cv_ld_elf = yes], [ + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' + ], [ + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' + ]) + + # Ancient FreeBSD doesn't handle version numbers with dots. + + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + OpenBSD-*) + CFLAGS_OPTIMIZE='-O2' + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' + AC_CACHE_CHECK([for ELF], tcl_cv_ld_elf, [ + AC_EGREP_CPP(yes, [ +#ifdef __ELF__ + yes +#endif + ], tcl_cv_ld_elf=yes, tcl_cv_ld_elf=no)]) + AS_IF([test $tcl_cv_ld_elf = yes], [ + LDFLAGS=-Wl,-export-dynamic + ], [LDFLAGS=""]) + + # OpenBSD doesn't do version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + NetBSD-*|FreeBSD-*) + # FreeBSD 3.* and greater have ELF. + # NetBSD 2.* has ELF and can use 'cc -shared' to build shared libs + SHLIB_CFLAGS="-fPIC" + SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + LDFLAGS="$LDFLAGS -export-dynamic" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "${TCL_THREADS}" = "1"], [ + # The -pthread needs to go in the CFLAGS, not LIBS + LIBS=`echo $LIBS | sed s/-pthread//` + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + case $system in + FreeBSD-3.*) + # FreeBSD-3 doesn't handle version numbers with dots. + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' + TCL_LIB_VERSIONS_OK=nodots + ;; + esac + ;; + Darwin-*) + CFLAGS_OPTIMIZE="-Os" + SHLIB_CFLAGS="-fno-common" + # To avoid discrepancies between what headers configure sees during + # preprocessing tests and compiling tests, move any -isysroot and + # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: + CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" + CFLAGS="`echo " ${CFLAGS}" | \ + awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ + if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" + AS_IF([test $do64bit = yes], [ + case `arch` in + ppc) + AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], + tcl_cv_cc_arch_ppc64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, + tcl_cv_cc_arch_ppc64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ + CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" + do64bit_ok=yes + ]);; + i386) + AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], + tcl_cv_cc_arch_x86_64, [ + hold_cflags=$CFLAGS + CFLAGS="$CFLAGS -arch x86_64" + AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, + tcl_cv_cc_arch_x86_64=no) + CFLAGS=$hold_cflags]) + AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ + CFLAGS="$CFLAGS -arch x86_64" + do64bit_ok=yes + ]);; + *) + AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; + esac + ], [ + # Check for combined 32-bit and 64-bit fat build + AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ + && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ + fat_32_64=yes]) + ]) + SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS}' + AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" + AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_single_module = yes], [ + SHLIB_LD="${SHLIB_LD} -Wl,-single_module" + ]) + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".dylib" + DL_OBJS="tclLoadDyld.o" + DL_LIBS="" + # Don't use -prebind when building for Mac OS X 10.4 or later only: + AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ + "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ + LDFLAGS="$LDFLAGS -prebind"]) + LDFLAGS="$LDFLAGS -headerpad_max_install_names" + AC_CACHE_CHECK([if ld accepts -search_paths_first flag], + tcl_cv_ld_search_paths_first, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, + tcl_cv_ld_search_paths_first=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ + LDFLAGS="$LDFLAGS -Wl,-search_paths_first" + ]) + AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ + AC_DEFINE(MODULE_SCOPE, [__private_extern__], + [Compiler support for module scope symbols]) + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" + AC_DEFINE(MAC_OSX_TCL, 1, [Is this a Mac I see before me?]) + PLAT_OBJS='${MAC_OSX_OBJS}' + PLAT_SRCS='${MAC_OSX_SRCS}' + AC_MSG_CHECKING([whether to use CoreFoundation]) + AC_ARG_ENABLE(corefoundation, + AC_HELP_STRING([--enable-corefoundation], + [use CoreFoundation API on MacOSX (default: on)]), + [tcl_corefoundation=$enableval], [tcl_corefoundation=yes]) + AC_MSG_RESULT([$tcl_corefoundation]) + AS_IF([test $tcl_corefoundation = yes], [ + AC_CACHE_CHECK([for CoreFoundation.framework], + tcl_cv_lib_corefoundation, [ + hold_libs=$LIBS + AS_IF([test "$fat_32_64" = yes], [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + # On Tiger there is no 64-bit CF, so remove 64-bit + # archs from CFLAGS et al. while testing for + # presence of CF. 64-bit CF is disabled in + # tclUnixPort.h if necessary. + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc64 / /g" -e "s/-arch x86_64 / /g"`"' + done]) + LIBS="$LIBS -framework CoreFoundation" + AC_TRY_LINK([#include ], + [CFBundleRef b = CFBundleGetMainBundle();], + tcl_cv_lib_corefoundation=yes, + tcl_cv_lib_corefoundation=no) + AS_IF([test "$fat_32_64" = yes], [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + LIBS=$hold_libs]) + AS_IF([test $tcl_cv_lib_corefoundation = yes], [ + LIBS="$LIBS -framework CoreFoundation" + AC_DEFINE(HAVE_COREFOUNDATION, 1, + [Do we have access to Darwin CoreFoundation.framework?]) + ], [tcl_corefoundation=no]) + AS_IF([test "$fat_32_64" = yes -a $tcl_corefoundation = yes],[ + AC_CACHE_CHECK([for 64-bit CoreFoundation], + tcl_cv_lib_corefoundation_64, [ + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' + done + AC_TRY_LINK([#include ], + [CFBundleRef b = CFBundleGetMainBundle();], + tcl_cv_lib_corefoundation_64=yes, + tcl_cv_lib_corefoundation_64=no) + for v in CFLAGS CPPFLAGS LDFLAGS; do + eval $v'="$hold_'$v'"' + done]) + AS_IF([test $tcl_cv_lib_corefoundation_64 = no], [ + AC_DEFINE(NO_COREFOUNDATION_64, 1, + [Is Darwin CoreFoundation unavailable for 64-bit?]) + LDFLAGS="$LDFLAGS -Wl,-no_arch_warnings" + ]) + ]) + ]) + ;; + NEXTSTEP-*) + SHLIB_CFLAGS="" + SHLIB_LD='${CC} -nostdlib -r' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadNext.o" + DL_LIBS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + OS/390-*) + CFLAGS_OPTIMIZE="" # Optimizer is buggy + AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h + [Should OS/390 do the right thing with sockets?]) + ;; + OSF1-1.0|OSF1-1.1|OSF1-1.2) + # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 + SHLIB_CFLAGS="" + # Hack: make package name same as library name + SHLIB_LD='ld -R -export $@:' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadOSF.o" + DL_LIBS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + OSF1-1.*) + # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 + SHLIB_CFLAGS="-fPIC" + AS_IF([test "$SHARED_BUILD" = 1], [SHLIB_LD="ld -shared"], [ + SHLIB_LD="ld -non_shared" + ]) + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + OSF1-V*) + # Digital OSF/1 + SHLIB_CFLAGS="" + AS_IF([test "$SHARED_BUILD" = 1], [ + SHLIB_LD='ld -shared -expect_unresolved "*"' + ], [ + SHLIB_LD='ld -non_shared -expect_unresolved "*"' + ]) + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + AS_IF([test $doRpath = yes], [ + CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) + AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ + CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) + # see pthread_intro(3) for pthread support on osf1, k.furukawa + AS_IF([test "${TCL_THREADS}" = 1], [ + CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" + CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" + LIBS=`echo $LIBS | sed s/-lpthreads//` + AS_IF([test "$GCC" = yes], [ + LIBS="$LIBS -lpthread -lmach -lexc" + ], [ + CFLAGS="$CFLAGS -pthread" + LDFLAGS="$LDFLAGS -pthread" + ]) + ]) + ;; + QNX-6*) + # QNX RTP + # This may work for all QNX, but it was only reported for v6. + SHLIB_CFLAGS="-fPIC" + SHLIB_LD="ld -Bshareable -x" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + # dlopen is in -lc on QNX + DL_LIBS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SCO_SV-3.2*) + # Note, dlopen is available only on SCO 3.2.5 and greater. However, + # this test works, since "uname -s" was non-standard in 3.2.4 and + # below. + AS_IF([test "$GCC" = yes], [ + SHLIB_CFLAGS="-fPIC -melf" + LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" + ], [ + SHLIB_CFLAGS="-Kpic -belf" + LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" + ]) + SHLIB_LD="ld -G" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SINIX*5.4*) + SHLIB_CFLAGS="-K PIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + SunOS-4*) + SHLIB_CFLAGS="-PIC" + SHLIB_LD="ld" + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + + # SunOS can't handle version numbers with dots in them in library + # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it + # requires an extra version number at the end of .so file names. + # So, the library has to have a name like libtcl75.so.1.0 + + SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' + UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' + TCL_LIB_VERSIONS_OK=nodots + ;; + SunOS-5.[[0-6]]) + # Careful to not let 5.10+ fall into this case + + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + + # Note: need the LIBS below, otherwise Tk won't find Tcl's + # symbols when dynamically loaded into tclsh. + + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ], [ + SHLIB_LD="/usr/ccs/bin/ld -G -z text" + CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + ]) + ;; + SunOS-5*) + # Note: If _REENTRANT isn't defined, then Solaris + # won't define thread-safe library routines. + + AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) + AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, + [Do we really want to follow the standard? Yes we do!]) + + SHLIB_CFLAGS="-KPIC" + + # Check to enable 64-bit flags for compiler/linker + AS_IF([test "$do64bit" = yes], [ + arch=`isainfo` + AS_IF([test "$arch" = "sparcv9 sparc"], [ + AS_IF([test "$GCC" = yes], [ + AS_IF([test "`${CC} -dumpversion | awk -F. '{print [$]1}'`" -lt 3], [ + AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) + ], [ + do64bit_ok=yes + CFLAGS="$CFLAGS -m64 -mcpu=v9" + LDFLAGS="$LDFLAGS -m64 -mcpu=v9" + SHLIB_CFLAGS="-fPIC" + ]) + ], [ + do64bit_ok=yes + AS_IF([test "$do64bitVIS" = yes], [ + CFLAGS="$CFLAGS -xarch=v9a" + LDFLAGS_ARCH="-xarch=v9a" + ], [ + CFLAGS="$CFLAGS -xarch=v9" + LDFLAGS_ARCH="-xarch=v9" + ]) + # Solaris 64 uses this as well + #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" + ]) + ], [AS_IF([test "$arch" = "amd64 i386"], [ + AS_IF([test "$GCC" = yes], [ + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + do64bit_ok=yes + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + AC_MSG_WARN([64bit mode not supported with GCC on $system]);; + esac + ], [ + do64bit_ok=yes + case $system in + SunOS-5.1[[1-9]]*|SunOS-5.[[2-9]][[0-9]]*) + CFLAGS="$CFLAGS -m64" + LDFLAGS="$LDFLAGS -m64";; + *) + CFLAGS="$CFLAGS -xarch=amd64" + LDFLAGS="$LDFLAGS -xarch=amd64";; + esac + ]) + ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) + ]) + + #-------------------------------------------------------------------- + # On Solaris 5.x i386 with the sunpro compiler we need to link + # with sunmath to get floating point rounding control + #-------------------------------------------------------------------- + AS_IF([test "$GCC" = yes],[use_sunmath=no],[ + arch=`isainfo` + AC_MSG_CHECKING([whether to use -lsunmath for fp rounding control]) + AS_IF([test "$arch" = "amd64 i386"], [ + AC_MSG_RESULT([yes]) + MATH_LIBS="-lsunmath $MATH_LIBS" + AC_CHECK_HEADER(sunmath.h) + use_sunmath=yes + ], [ + AC_MSG_RESULT([no]) + use_sunmath=no + ]) + ]) + + # Note: need the LIBS below, otherwise Tk won't find Tcl's + # symbols when dynamically loaded into tclsh. + + SHLIB_LD_LIBS='${LIBS}' + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + AS_IF([test "$GCC" = yes], [ + SHLIB_LD='${CC} -shared' + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} + AS_IF([test "$do64bit_ok" = yes], [ + AS_IF([test "$arch" = "sparcv9 sparc"], [ + # We need to specify -static-libgcc or we need to + # add the path to the sparv9 libgcc. + SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" + # for finding sparcv9 libgcc, get the regular libgcc + # path, remove so name and append 'sparcv9' + #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." + #CC_SEARCH_FLAGS="${CC_SEARCH_FLAGS},-R,$v9gcclibdir" + ], [AS_IF([test "$arch" = "amd64 i386"], [ + SHLIB_LD="$SHLIB_LD -m64 -static-libgcc" + ])]) + ]) + ], [ + AS_IF([test "$use_sunmath" = yes], [textmode=textoff],[textmode=text]) + case $system in + SunOS-5.[[1-9]][[0-9]]*) + SHLIB_LD="\${CC} -G -z $textmode \${LDFLAGS}";; + *) + SHLIB_LD="/usr/ccs/bin/ld -G -z $textmode";; + esac + CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' + LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' + ]) + ;; + UNIX_SV* | UnixWare-5*) + SHLIB_CFLAGS="-KPIC" + SHLIB_LD='${CC} -G' + SHLIB_LD_LIBS="" + SHLIB_SUFFIX=".so" + DL_OBJS="tclLoadDl.o" + DL_LIBS="-ldl" + # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers + # that don't grok the -Bexport option. Test that it does. + AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ + hold_ldflags=$LDFLAGS + LDFLAGS="$LDFLAGS -Wl,-Bexport" + AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) + LDFLAGS=$hold_ldflags]) + AS_IF([test $tcl_cv_ld_Bexport = yes], [ + LDFLAGS="$LDFLAGS -Wl,-Bexport" + ]) + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + ;; + esac + + AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = no], [ + AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) + ]) + + AS_IF([test "$do64bit" = yes -a "$do64bit_ok" = yes], [ + AC_DEFINE(TCL_CFG_DO64BIT, 1, [Is this a 64-bit build?]) + ]) + +dnl # Add any CPPFLAGS set in the environment to our CFLAGS, but delay doing so +dnl # until the end of configure, as configure's compile and link tests use +dnl # both CPPFLAGS and CFLAGS (unlike our compile and link) but configure's +dnl # preprocessing tests use only CPPFLAGS. + AC_CONFIG_COMMANDS_PRE([CFLAGS="${CFLAGS} ${CPPFLAGS}"; CPPFLAGS=""]) + + # Step 4: disable dynamic loading if requested via a command-line switch. + + AC_ARG_ENABLE(load, + AC_HELP_STRING([--enable-load], + [allow dynamic loading and "load" command (default: on)]), + [tcl_ok=$enableval], [tcl_ok=yes]) + AS_IF([test "$tcl_ok" = no], [DL_OBJS=""]) + + AS_IF([test "x$DL_OBJS" != x], [BUILD_DLTEST="\$(DLTEST_TARGETS)"], [ + AC_MSG_WARN([Can't figure out how to do dynamic loading or shared libraries on this system.]) + SHLIB_CFLAGS="" + SHLIB_LD="" + SHLIB_SUFFIX="" + DL_OBJS="tclLoadNone.o" + DL_LIBS="" + LDFLAGS="$LDFLAGS_ORIG" + CC_SEARCH_FLAGS="" + LD_SEARCH_FLAGS="" + BUILD_DLTEST="" + ]) + LDFLAGS="$LDFLAGS $LDFLAGS_ARCH" + + # If we're running gcc, then change the C flags for compiling shared + # libraries to the right flags for gcc, instead of those for the + # standard manufacturer compiler. + + AS_IF([test "$DL_OBJS" != "tclLoadNone.o" -a "$GCC" = yes], [ + case $system in + AIX-*) ;; + BSD/OS*) ;; + IRIX*) ;; + NetBSD-*|FreeBSD-*) ;; + Darwin-*) ;; + SCO_SV-3.2*) ;; + *) SHLIB_CFLAGS="-fPIC" ;; + esac]) + + AS_IF([test "$SHARED_LIB_SUFFIX" = ""], [ + SHARED_LIB_SUFFIX='${VERSION}${SHLIB_SUFFIX}']) + AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ + UNSHARED_LIB_SUFFIX='${VERSION}.a']) + + AS_IF([test "${SHARED_BUILD}" = 1 -a "${SHLIB_SUFFIX}" != ""], [ + LIB_SUFFIX=${SHARED_LIB_SUFFIX} + MAKE_LIB='${SHLIB_LD} -o [$]@ ${OBJS} ${SHLIB_LD_LIBS} ${TCL_SHLIB_LD_EXTRAS} ${TK_SHLIB_LD_EXTRAS} ${LD_SEARCH_FLAGS}' + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)"/$(LIB_FILE)' + ], [ + LIB_SUFFIX=${UNSHARED_LIB_SUFFIX} + + AS_IF([test "$RANLIB" = ""], [ + MAKE_LIB='$(STLIB_LD) [$]@ ${OBJS}' + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)"/$(LIB_FILE)' + ], [ + MAKE_LIB='${STLIB_LD} [$]@ ${OBJS} ; ${RANLIB} [$]@' + INSTALL_LIB='$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)"/$(LIB_FILE) ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(LIB_FILE))' + ]) + ]) + + # Stub lib does not depend on shared/static configuration + AS_IF([test "$RANLIB" = ""], [ + MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS}' + INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)"' + ], [ + MAKE_STUB_LIB='${STLIB_LD} [$]@ ${STUB_LIB_OBJS} ; ${RANLIB} [$]@' + INSTALL_STUB_LIB='$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)"/$(STUB_LIB_FILE) ; (cd "$(LIB_INSTALL_DIR)" ; $(RANLIB) $(STUB_LIB_FILE))' + ]) + + # Define TCL_LIBS now that we know what DL_LIBS is. + # The trick here is that we don't want to change the value of TCL_LIBS if + # it is already set when tclConfig.sh had been loaded by Tk. + AS_IF([test "x${TCL_LIBS}" = x], [ + TCL_LIBS="${DL_LIBS} ${LIBS} ${MATH_LIBS}"]) + AC_SUBST(TCL_LIBS) + + # FIXME: This subst was left in only because the TCL_DL_LIBS + # entry in tclConfig.sh uses it. It is not clear why someone + # would use TCL_DL_LIBS instead of TCL_LIBS. + AC_SUBST(DL_LIBS) + + AC_SUBST(DL_OBJS) + AC_SUBST(PLAT_OBJS) + AC_SUBST(PLAT_SRCS) + AC_SUBST(LDAIX_SRC) + AC_SUBST(CFLAGS) + AC_SUBST(CFLAGS_DEBUG) + AC_SUBST(CFLAGS_OPTIMIZE) + AC_SUBST(CFLAGS_WARNING) + + AC_SUBST(LDFLAGS) + AC_SUBST(LDFLAGS_DEBUG) + AC_SUBST(LDFLAGS_OPTIMIZE) + AC_SUBST(CC_SEARCH_FLAGS) + AC_SUBST(LD_SEARCH_FLAGS) + + AC_SUBST(STLIB_LD) + AC_SUBST(SHLIB_LD) + AC_SUBST(TCL_SHLIB_LD_EXTRAS) + AC_SUBST(TK_SHLIB_LD_EXTRAS) + AC_SUBST(SHLIB_LD_LIBS) + AC_SUBST(SHLIB_CFLAGS) + AC_SUBST(SHLIB_SUFFIX) + AC_DEFINE_UNQUOTED(TCL_SHLIB_EXT,"${SHLIB_SUFFIX}", + [What is the default extension for shared libraries?]) + + AC_SUBST(MAKE_LIB) + AC_SUBST(MAKE_STUB_LIB) + AC_SUBST(INSTALL_LIB) + AC_SUBST(INSTALL_STUB_LIB) + AC_SUBST(RANLIB) +]) + +#-------------------------------------------------------------------- +# SC_SERIAL_PORT +# +# Determine which interface to use to talk to the serial port. +# Note that #include lines must begin in leftmost column for +# some compilers to recognize them as preprocessor directives, +# and some build environments have stdin not pointing at a +# pseudo-terminal (usually /dev/null instead.) +# +# Arguments: +# none +# +# Results: +# +# Defines only one of the following vars: +# HAVE_SYS_MODEM_H +# USE_TERMIOS +# USE_TERMIO +# USE_SGTTY +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_SERIAL_PORT], [ + AC_CHECK_HEADERS(sys/modem.h) + AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ + AC_TRY_RUN([ +#include + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no ; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct termios t; + if (tcgetattr(0, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + cfsetospeed(&t, 0); + t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; +}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct termio t; + if (ioctl(0, TCGETA, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; + return 0; + } + return 1; + }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) + fi + if test $tcl_cv_api_serial = no; then + AC_TRY_RUN([ +#include +#include + +int main() { + struct sgttyb t; + if (ioctl(0, TIOCGETP, &t) == 0 + || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { + t.sg_ospeed = 0; + t.sg_flags |= ODDP | EVENP | RAW; + return 0; + } + return 1; +}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) + fi]) + case $tcl_cv_api_serial in + termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; + termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; + sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; + esac +]) + +#-------------------------------------------------------------------- +# SC_MISSING_POSIX_HEADERS +# +# Supply substitutes for missing POSIX header files. Special +# notes: +# - stdlib.h doesn't define strtol, strtoul, or +# strtod insome versions of SunOS +# - some versions of string.h don't declare procedures such +# as strstr +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# NO_DIRENT_H +# NO_VALUES_H +# HAVE_LIMITS_H or NO_LIMITS_H +# NO_STDLIB_H +# NO_STRING_H +# NO_SYS_WAIT_H +# NO_DLFCN_H +# HAVE_SYS_PARAM_H +# +# HAVE_STRING_H ? +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_MISSING_POSIX_HEADERS], [ + AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ + AC_TRY_LINK([#include +#include ], [ +#ifndef _POSIX_SOURCE +# ifdef __Lynx__ + /* + * Generate compilation error to make the test fail: Lynx headers + * are only valid if really in the POSIX environment. + */ + + missing_procedure(); +# endif +#endif +DIR *d; +struct dirent *entryPtr; +char *p; +d = opendir("foobar"); +entryPtr = readdir(d); +p = entryPtr->d_name; +closedir(d); +], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) + + if test $tcl_cv_dirent_h = no; then + AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) + fi + + AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(limits.h, + [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], + [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) + AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) + if test $tcl_ok = 0; then + AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) + fi + AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) + AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) + AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) + + # See also memmove check below for a place where NO_STRING_H can be + # set and why. + + if test $tcl_ok = 0; then + AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) + fi + + AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) + AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) + + # OS/390 lacks sys/param.h (and doesn't need it, by chance). + AC_HAVE_HEADERS(sys/param.h) +]) + +#-------------------------------------------------------------------- +# SC_PATH_X +# +# Locate the X11 header files and the X11 library archive. Try +# the ac_path_x macro first, but if it doesn't find the X stuff +# (e.g. because there's no xmkmf program) then check through +# a list of possible directories. Under some conditions the +# autoconf macro will return an include directory that contains +# no include files, so double-check its result just to be safe. +# +# Arguments: +# none +# +# Results: +# +# Sets the the following vars: +# XINCLUDES +# XLIBSW +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_PATH_X], [ + AC_PATH_X + not_really_there="" + if test "$no_x" = ""; then + if test "$x_includes" = ""; then + AC_TRY_CPP([#include ], , not_really_there="yes") + else + if test ! -r $x_includes/X11/Intrinsic.h; then + not_really_there="yes" + fi + fi + fi + if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then + AC_MSG_CHECKING([for X11 header files]) + found_xincludes="no" + AC_TRY_CPP([#include ], found_xincludes="yes", found_xincludes="no") + if test "$found_xincludes" = "no"; then + dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" + for i in $dirs ; do + if test -r $i/X11/Intrinsic.h; then + AC_MSG_RESULT([$i]) + XINCLUDES=" -I$i" + found_xincludes="yes" + break + fi + done + fi + else + if test "$x_includes" != ""; then + XINCLUDES="-I$x_includes" + found_xincludes="yes" + fi + fi + if test found_xincludes = "no"; then + AC_MSG_RESULT([couldn't find any!]) + fi + + if test "$no_x" = yes; then + AC_MSG_CHECKING([for X11 libraries]) + XLIBSW=nope + dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" + for i in $dirs ; do + if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl -o -r $i/libX11.dylib; then + AC_MSG_RESULT([$i]) + XLIBSW="-L$i -lX11" + x_libraries="$i" + break + fi + done + else + if test "$x_libraries" = ""; then + XLIBSW=-lX11 + else + XLIBSW="-L$x_libraries -lX11" + fi + fi + if test "$XLIBSW" = nope ; then + AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) + fi + if test "$XLIBSW" = nope ; then + AC_MSG_RESULT([could not find any! Using -lX11.]) + XLIBSW=-lX11 + fi +]) + +#-------------------------------------------------------------------- +# SC_BLOCKING_STYLE +# +# The statements below check for systems where POSIX-style +# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. +# On these systems (mostly older ones), use the old BSD-style +# FIONBIO approach instead. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# HAVE_SYS_IOCTL_H +# HAVE_SYS_FILIO_H +# USE_FIONBIO +# O_NONBLOCK +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_BLOCKING_STYLE], [ + AC_CHECK_HEADERS(sys/ioctl.h) + AC_CHECK_HEADERS(sys/filio.h) + SC_CONFIG_SYSTEM + AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) + case $system in + # There used to be code here to use FIONBIO under AIX. However, it + # was reported that FIONBIO doesn't work under AIX 3.2.5. Since + # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO + # code (JO, 5/31/97). + + OSF*) + AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) + AC_MSG_RESULT([FIONBIO]) + ;; + SunOS-4*) + AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) + AC_MSG_RESULT([FIONBIO]) + ;; + *) + AC_MSG_RESULT([O_NONBLOCK]) + ;; + esac +]) + +#-------------------------------------------------------------------- +# SC_TIME_HANLDER +# +# Checks how the system deals with time.h, what time structures +# are used on the system, and what fields the structures have. +# +# Arguments: +# none +# +# Results: +# +# Defines some of the following vars: +# USE_DELTA_FOR_TZ +# HAVE_TM_GMTOFF +# HAVE_TM_TZADJ +# HAVE_TIMEZONE_VAR +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TIME_HANDLER], [ + AC_CHECK_HEADERS(sys/time.h) + AC_HEADER_TIME + AC_STRUCT_TIMEZONE + + AC_CHECK_FUNCS(gmtime_r localtime_r mktime) + + AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ + AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], + tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) + if test $tcl_cv_member_tm_tzadj = yes ; then + AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) + fi + + AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ + AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], + tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) + if test $tcl_cv_member_tm_gmtoff = yes ; then + AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) + fi + + # + # Its important to include time.h in this check, as some systems + # (like convex) have timezone functions, etc. + # + AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ + AC_TRY_COMPILE([#include ], + [extern long timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) + if test $tcl_cv_timezone_long = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + else + # + # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. + # + AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ + AC_TRY_COMPILE([#include ], + [extern time_t timezone; + timezone += 1; + exit (0);], + tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) + if test $tcl_cv_timezone_time = yes ; then + AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# SC_BUGGY_STRTOD +# +# Under Solaris 2.4, strtod returns the wrong value for the +# terminating character under some conditions. Check for this +# and if the problem exists use a substitute procedure +# "fixstrtod" (provided by Tcl) that corrects the error. +# Also, on Compaq's Tru64 Unix 5.0, +# strtod(" ") returns 0.0 instead of a failure to convert. +# +# Arguments: +# none +# +# Results: +# +# Might defines some of the following vars: +# strtod (=fixstrtod) +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_BUGGY_STRTOD], [ + AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) + if test "$tcl_strtod" = 1; then + AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ + AC_TRY_RUN([ + extern double strtod(); + int main() { + char *infString="Inf", *nanString="NaN", *spaceString=" "; + char *term; + double value; + value = strtod(infString, &term); + if ((term != infString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(nanString, &term); + if ((term != nanString) && (term[-1] == 0)) { + exit(1); + } + value = strtod(spaceString, &term); + if (term == (spaceString+1)) { + exit(1); + } + exit(0); + }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, + tcl_cv_strtod_buggy=buggy)]) + if test "$tcl_cv_strtod_buggy" = buggy; then + AC_LIBOBJ([fixstrtod]) + USE_COMPAT=1 + AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) + fi + fi +]) + +#-------------------------------------------------------------------- +# SC_TCL_LINK_LIBS +# +# Search for the libraries needed to link the Tcl shell. +# Things like the math library (-lm) and socket stuff (-lsocket vs. +# -lnsl) are dealt with here. +# +# Arguments: +# None. +# +# Results: +# +# Might append to the following vars: +# LIBS +# MATH_LIBS +# +# Might define the following vars: +# HAVE_NET_ERRNO_H +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_LINK_LIBS], [ + #-------------------------------------------------------------------- + # On a few very rare systems, all of the libm.a stuff is + # already in libc.a. Set compiler flags accordingly. + # Also, Linux requires the "ieee" library for math to work + # right (and it must appear before "-lm"). + #-------------------------------------------------------------------- + + AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") + AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) + + #-------------------------------------------------------------------- + # Interactive UNIX requires -linet instead of -lsocket, plus it + # needs net/errno.h to define the socket-related error codes. + #-------------------------------------------------------------------- + + AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) + AC_CHECK_HEADER(net/errno.h, [ + AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) + + #-------------------------------------------------------------------- + # Check for the existence of the -lsocket and -lnsl libraries. + # The order here is important, so that they end up in the right + # order in the command line generated by make. Here are some + # special considerations: + # 1. Use "connect" and "accept" to check for -lsocket, and + # "gethostbyname" to check for -lnsl. + # 2. Use each function name only once: can't redo a check because + # autoconf caches the results of the last check and won't redo it. + # 3. Use -lnsl and -lsocket only if they supply procedures that + # aren't already present in the normal libraries. This is because + # IRIX 5.2 has libraries, but they aren't needed and they're + # bogus: they goof up name resolution if used. + # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. + # To get around this problem, check for both libraries together + # if -lsocket doesn't work by itself. + #-------------------------------------------------------------------- + + tcl_checkBoth=0 + AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) + if test "$tcl_checkSocket" = 1; then + AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, + LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) + fi + if test "$tcl_checkBoth" = 1; then + tk_oldLibs=$LIBS + LIBS="$LIBS -lsocket -lnsl" + AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) + fi + AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, + [LIBS="$LIBS -lnsl"])]) +]) + +#-------------------------------------------------------------------- +# SC_TCL_EARLY_FLAGS +# +# Check for what flags are needed to be passed so the correct OS +# features are available. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# _ISOC99_SOURCE +# _LARGEFILE64_SOURCE +# _LARGEFILE_SOURCE64 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_EARLY_FLAG],[ + AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), + AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, + AC_TRY_COMPILE([[#define ]$1[ 1 +]$2], $3, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, + [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) + if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then + AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) + tcl_flags="$tcl_flags $1" + fi +]) + +AC_DEFUN([SC_TCL_EARLY_FLAGS],[ + AC_MSG_CHECKING([for required early compiler flags]) + tcl_flags="" + SC_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], + [char *p = (char *)strtoll; char *q = (char *)strtoull;]) + SC_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], + [struct stat64 buf; int i = stat64("/", &buf);]) + SC_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ], + [char *p = (char *)open64;]) + if test "x${tcl_flags}" = "x" ; then + AC_MSG_RESULT([none]) + else + AC_MSG_RESULT([${tcl_flags}]) + fi +]) + +#-------------------------------------------------------------------- +# SC_TCL_64BIT_FLAGS +# +# Check for what is defined in the way of 64-bit features. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# TCL_WIDE_INT_IS_LONG +# TCL_WIDE_INT_TYPE +# HAVE_STRUCT_DIRENT64 +# HAVE_STRUCT_STAT64 +# HAVE_TYPE_OFF64_T +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_64BIT_FLAGS], [ + AC_MSG_CHECKING([for 64-bit integer type]) + AC_CACHE_VAL(tcl_cv_type_64bit,[ + tcl_cv_type_64bit=none + # See if the compiler knows natively about __int64 + AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], + tcl_type_64bit=__int64, tcl_type_64bit="long long") + # See if we should use long anyway Note that we substitute in the + # type that is our current guess for a 64-bit type inside this check + # program, so it should be modified only carefully... + AC_TRY_COMPILE(,[switch (0) { + case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; + }],tcl_cv_type_64bit=${tcl_type_64bit})]) + if test "${tcl_cv_type_64bit}" = none ; then + AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) + AC_MSG_RESULT([using long]) + else + AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, + [What type should be used to define wide integers?]) + AC_MSG_RESULT([${tcl_cv_type_64bit}]) + + # Now check for auxiliary declarations + AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ + AC_TRY_COMPILE([#include +#include ],[struct dirent64 p;], + tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) + if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) + fi + + AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ + AC_TRY_COMPILE([#include ],[struct stat64 p; +], + tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) + if test "x${tcl_cv_struct_stat64}" = "xyes" ; then + AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) + fi + + AC_CHECK_FUNCS(open64 lseek64) + AC_MSG_CHECKING([for off64_t]) + AC_CACHE_VAL(tcl_cv_type_off64_t,[ + AC_TRY_COMPILE([#include ],[off64_t offset; +], + tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) + dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the + dnl functions lseek64 and open64 are defined. + if test "x${tcl_cv_type_off64_t}" = "xyes" && \ + test "x${ac_cv_func_lseek64}" = "xyes" && \ + test "x${ac_cv_func_open64}" = "xyes" ; then + AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi +]) + +#-------------------------------------------------------------------- +# SC_TCL_CFG_ENCODING TIP #59 +# +# Declare the encoding to use for embedded configuration information. +# +# Arguments: +# None. +# +# Results: +# Might append to the following vars: +# DEFS (implicit) +# +# Will define the following vars: +# TCL_CFGVAL_ENCODING +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_CFG_ENCODING], [ + AC_ARG_WITH(encoding, + AC_HELP_STRING([--with-encoding], + [encoding for configuration values (default: iso8859-1)]), + with_tcencoding=${withval}) + + if test x"${with_tcencoding}" != x ; then + AC_DEFINE_UNQUOTED(TCL_CFGVAL_ENCODING,"${with_tcencoding}", + [What encoding should be used for embedded configuration info?]) + else + AC_DEFINE(TCL_CFGVAL_ENCODING,"iso8859-1", + [What encoding should be used for embedded configuration info?]) + fi +]) + +#-------------------------------------------------------------------- +# SC_TCL_CHECK_BROKEN_FUNC +# +# Check for broken function. +# +# Arguments: +# funcName - function to test for +# advancedTest - the advanced test to run if the function is present +# +# Results: +# Might cause compatability versions of the function to be used. +# Might affect the following vars: +# USE_COMPAT (implicit) +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_CHECK_BROKEN_FUNC],[ + AC_CHECK_FUNC($1, tcl_ok=1, tcl_ok=0) + if test ["$tcl_ok"] = 1; then + AC_CACHE_CHECK([proper ]$1[ implementation], [tcl_cv_]$1[_unbroken], + AC_TRY_RUN([[int main() {]$2[}]],[tcl_cv_]$1[_unbroken]=ok, + [tcl_cv_]$1[_unbroken]=broken,[tcl_cv_]$1[_unbroken]=unknown)) + if test ["$tcl_cv_]$1[_unbroken"] = "ok"; then + tcl_ok=1 + else + tcl_ok=0 + fi + fi + if test ["$tcl_ok"] = 0; then + AC_LIBOBJ($1) + USE_COMPAT=1 + fi +]) + +#-------------------------------------------------------------------- +# SC_TCL_GETHOSTBYADDR_R +# +# Check if we have MT-safe variant of gethostbyaddr(). +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# HAVE_GETHOSTBYADDR_R +# HAVE_GETHOSTBYADDR_R_7 +# HAVE_GETHOSTBYADDR_R_8 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETHOSTBYADDR_R], [AC_CHECK_FUNC(gethostbyaddr_r, [ + AC_CACHE_CHECK([for gethostbyaddr_r with 7 args], tcl_cv_api_gethostbyaddr_r_7, [ + AC_TRY_COMPILE([ + #include + ], [ + char *addr; + int length; + int type; + struct hostent *result; + char buffer[2048]; + int buflen = 2048; + int h_errnop; + + (void) gethostbyaddr_r(addr, length, type, result, buffer, buflen, + &h_errnop); + ], tcl_cv_api_gethostbyaddr_r_7=yes, tcl_cv_api_gethostbyaddr_r_7=no)]) + tcl_ok=$tcl_cv_api_gethostbyaddr_r_7 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYADDR_R_7, 1, + [Define to 1 if gethostbyaddr_r takes 7 args.]) + else + AC_CACHE_CHECK([for gethostbyaddr_r with 8 args], tcl_cv_api_gethostbyaddr_r_8, [ + AC_TRY_COMPILE([ + #include + ], [ + char *addr; + int length; + int type; + struct hostent *result, *resultp; + char buffer[2048]; + int buflen = 2048; + int h_errnop; + + (void) gethostbyaddr_r(addr, length, type, result, buffer, buflen, + &resultp, &h_errnop); + ], tcl_cv_api_gethostbyaddr_r_8=yes, tcl_cv_api_gethostbyaddr_r_8=no)]) + tcl_ok=$tcl_cv_api_gethostbyaddr_r_8 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYADDR_R_8, 1, + [Define to 1 if gethostbyaddr_r takes 8 args.]) + fi + fi + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYADDR_R, 1, + [Define to 1 if gethostbyaddr_r is available.]) + fi +])]) + +#-------------------------------------------------------------------- +# SC_TCL_GETHOSTBYNAME_R +# +# Check to see what variant of gethostbyname_r() we have. +# Based on David Arnold's example from the comp.programming.threads +# FAQ Q213 +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# HAVE_GETHOSTBYADDR_R +# HAVE_GETHOSTBYADDR_R_3 +# HAVE_GETHOSTBYADDR_R_5 +# HAVE_GETHOSTBYADDR_R_6 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETHOSTBYNAME_R], [AC_CHECK_FUNC(gethostbyname_r, [ + AC_CACHE_CHECK([for gethostbyname_r with 6 args], tcl_cv_api_gethostbyname_r_6, [ + AC_TRY_COMPILE([ + #include + ], [ + char *name; + struct hostent *he, *res; + char buffer[2048]; + int buflen = 2048; + int h_errnop; + + (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop); + ], tcl_cv_api_gethostbyname_r_6=yes, tcl_cv_api_gethostbyname_r_6=no)]) + tcl_ok=$tcl_cv_api_gethostbyname_r_6 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R_6, 1, + [Define to 1 if gethostbyname_r takes 6 args.]) + else + AC_CACHE_CHECK([for gethostbyname_r with 5 args], tcl_cv_api_gethostbyname_r_5, [ + AC_TRY_COMPILE([ + #include + ], [ + char *name; + struct hostent *he; + char buffer[2048]; + int buflen = 2048; + int h_errnop; + + (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop); + ], tcl_cv_api_gethostbyname_r_5=yes, tcl_cv_api_gethostbyname_r_5=no)]) + tcl_ok=$tcl_cv_api_gethostbyname_r_5 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R_5, 1, + [Define to 1 if gethostbyname_r takes 5 args.]) + else + AC_CACHE_CHECK([for gethostbyname_r with 3 args], tcl_cv_api_gethostbyname_r_3, [ + AC_TRY_COMPILE([ + #include + ], [ + char *name; + struct hostent *he; + struct hostent_data data; + + (void) gethostbyname_r(name, he, &data); + ], tcl_cv_api_gethostbyname_r_3=yes, tcl_cv_api_gethostbyname_r_3=no)]) + tcl_ok=$tcl_cv_api_gethostbyname_r_3 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R_3, 1, + [Define to 1 if gethostbyname_r takes 3 args.]) + fi + fi + fi + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETHOSTBYNAME_R, 1, + [Define to 1 if gethostbyname_r is available.]) + fi +])]) + +#-------------------------------------------------------------------- +# SC_TCL_GETADDRINFO +# +# Check if we have 'getaddrinfo' +# +# Arguments: +# None +# +# Results: +# Might define the following vars: +# HAVE_GETADDRINFO +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETADDRINFO], [AC_CHECK_FUNC(getaddrinfo, [ + AC_CACHE_CHECK([for working getaddrinfo], tcl_cv_api_getaddrinfo, [ + AC_TRY_COMPILE([ + #include + ], [ + const char *name, *port; + struct addrinfo *aiPtr, hints; + (void)getaddrinfo(name,port, &hints, &aiPtr); + (void)freeaddrinfo(aiPtr); + ], tcl_cv_api_getaddrinfo=yes, tcl_cv_getaddrinfo=no)]) + tcl_ok=$tcl_cv_api_getaddrinfo + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETADDRINFO, 1, + [Define to 1 if getaddrinfo is available.]) + fi +])]) + +#-------------------------------------------------------------------- +# SC_TCL_GETPWUID_R +# +# Check if we have MT-safe variant of getpwuid() and if yes, +# which one exactly. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# HAVE_GETPWUID_R +# HAVE_GETPWUID_R_4 +# HAVE_GETPWUID_R_5 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETPWUID_R], [AC_CHECK_FUNC(getpwuid_r, [ + AC_CACHE_CHECK([for getpwuid_r with 5 args], tcl_cv_api_getpwuid_r_5, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + uid_t uid; + struct passwd pw, *pwp; + char buf[512]; + int buflen = 512; + + (void) getpwuid_r(uid, &pw, buf, buflen, &pwp); + ], tcl_cv_api_getpwuid_r_5=yes, tcl_cv_api_getpwuid_r_5=no)]) + tcl_ok=$tcl_cv_api_getpwuid_r_5 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETPWUID_R_5, 1, + [Define to 1 if getpwuid_r takes 5 args.]) + else + AC_CACHE_CHECK([for getpwuid_r with 4 args], tcl_cv_api_getpwuid_r_4, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + uid_t uid; + struct passwd pw; + char buf[512]; + int buflen = 512; + + (void)getpwnam_r(uid, &pw, buf, buflen); + ], tcl_cv_api_getpwuid_r_4=yes, tcl_cv_api_getpwuid_r_4=no)]) + tcl_ok=$tcl_cv_api_getpwuid_r_4 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETPWUID_R_4, 1, + [Define to 1 if getpwuid_r takes 4 args.]) + fi + fi + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETPWUID_R, 1, + [Define to 1 if getpwuid_r is available.]) + fi +])]) + +#-------------------------------------------------------------------- +# SC_TCL_GETPWNAM_R +# +# Check if we have MT-safe variant of getpwnam() and if yes, +# which one exactly. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# HAVE_GETPWNAM_R +# HAVE_GETPWNAM_R_4 +# HAVE_GETPWNAM_R_5 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETPWNAM_R], [AC_CHECK_FUNC(getpwnam_r, [ + AC_CACHE_CHECK([for getpwnam_r with 5 args], tcl_cv_api_getpwnam_r_5, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + char *name; + struct passwd pw, *pwp; + char buf[512]; + int buflen = 512; + + (void) getpwnam_r(name, &pw, buf, buflen, &pwp); + ], tcl_cv_api_getpwnam_r_5=yes, tcl_cv_api_getpwnam_r_5=no)]) + tcl_ok=$tcl_cv_api_getpwnam_r_5 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETPWNAM_R_5, 1, + [Define to 1 if getpwnam_r takes 5 args.]) + else + AC_CACHE_CHECK([for getpwnam_r with 4 args], tcl_cv_api_getpwnam_r_4, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + char *name; + struct passwd pw; + char buf[512]; + int buflen = 512; + + (void)getpwnam_r(name, &pw, buf, buflen); + ], tcl_cv_api_getpwnam_r_4=yes, tcl_cv_api_getpwnam_r_4=no)]) + tcl_ok=$tcl_cv_api_getpwnam_r_4 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETPWNAM_R_4, 1, + [Define to 1 if getpwnam_r takes 4 args.]) + fi + fi + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETPWNAM_R, 1, + [Define to 1 if getpwnam_r is available.]) + fi +])]) + +#-------------------------------------------------------------------- +# SC_TCL_GETGRGID_R +# +# Check if we have MT-safe variant of getgrgid() and if yes, +# which one exactly. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# HAVE_GETGRGID_R +# HAVE_GETGRGID_R_4 +# HAVE_GETGRGID_R_5 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETGRGID_R], [AC_CHECK_FUNC(getgrgid_r, [ + AC_CACHE_CHECK([for getgrgid_r with 5 args], tcl_cv_api_getgrgid_r_5, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + gid_t gid; + struct group gr, *grp; + char buf[512]; + int buflen = 512; + + (void) getgrgid_r(gid, &gr, buf, buflen, &grp); + ], tcl_cv_api_getgrgid_r_5=yes, tcl_cv_api_getgrgid_r_5=no)]) + tcl_ok=$tcl_cv_api_getgrgid_r_5 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETGRGID_R_5, 1, + [Define to 1 if getgrgid_r takes 5 args.]) + else + AC_CACHE_CHECK([for getgrgid_r with 4 args], tcl_cv_api_getgrgid_r_4, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + gid_t gid; + struct group gr; + char buf[512]; + int buflen = 512; + + (void)getgrgid_r(gid, &gr, buf, buflen); + ], tcl_cv_api_getgrgid_r_4=yes, tcl_cv_api_getgrgid_r_4=no)]) + tcl_ok=$tcl_cv_api_getgrgid_r_4 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETGRGID_R_4, 1, + [Define to 1 if getgrgid_r takes 4 args.]) + fi + fi + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETGRGID_R, 1, + [Define to 1 if getgrgid_r is available.]) + fi +])]) + +#-------------------------------------------------------------------- +# SC_TCL_GETGRNAM_R +# +# Check if we have MT-safe variant of getgrnam() and if yes, +# which one exactly. +# +# Arguments: +# None +# +# Results: +# +# Might define the following vars: +# HAVE_GETGRNAM_R +# HAVE_GETGRNAM_R_4 +# HAVE_GETGRNAM_R_5 +# +#-------------------------------------------------------------------- + +AC_DEFUN([SC_TCL_GETGRNAM_R], [AC_CHECK_FUNC(getgrnam_r, [ + AC_CACHE_CHECK([for getgrnam_r with 5 args], tcl_cv_api_getgrnam_r_5, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + char *name; + struct group gr, *grp; + char buf[512]; + int buflen = 512; + + (void) getgrnam_r(name, &gr, buf, buflen, &grp); + ], tcl_cv_api_getgrnam_r_5=yes, tcl_cv_api_getgrnam_r_5=no)]) + tcl_ok=$tcl_cv_api_getgrnam_r_5 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETGRNAM_R_5, 1, + [Define to 1 if getgrnam_r takes 5 args.]) + else + AC_CACHE_CHECK([for getgrnam_r with 4 args], tcl_cv_api_getgrnam_r_4, [ + AC_TRY_COMPILE([ + #include + #include + ], [ + char *name; + struct group gr; + char buf[512]; + int buflen = 512; + + (void)getgrnam_r(name, &gr, buf, buflen); + ], tcl_cv_api_getgrnam_r_4=yes, tcl_cv_api_getgrnam_r_4=no)]) + tcl_ok=$tcl_cv_api_getgrnam_r_4 + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETGRNAM_R_4, 1, + [Define to 1 if getgrnam_r takes 4 args.]) + fi + fi + if test "$tcl_ok" = yes; then + AC_DEFINE(HAVE_GETGRNAM_R, 1, + [Define to 1 if getgrnam_r is available.]) + fi +])]) + +# Local Variables: +# mode: autoconf +# End: diff --git a/build/xml.m4 b/build/xml.m4 new file mode 100644 index 00000000..faf2aa1d --- /dev/null +++ b/build/xml.m4 @@ -0,0 +1,111 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl xml.m4 Trafficserver's Xml autoconf macros +dnl + +dnl +dnl TS_CHECK_XML: look for xml libraries and headers +dnl +AC_DEFUN([TS_CHECK_XML], [ + enable_xml=no + + TS_CHECK_XML_EXPAT + dnl add checks for other varieties of xml here +]) +dnl + +AC_DEFUN([TS_CHECK_XML_EXPAT], [ +enable_expat=no +AC_ARG_WITH(expat, [AC_HELP_STRING([--with-expat=DIR],[use a specific Expat library])], +[ + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + expat_base_dir="$withval" + if test "$withval" != "no"; then + enable_expat=yes + case "$withval" in + *":"*) + expat_include="`echo $withval |sed -e 's/:.*$//'`" + expat_ldflags="`echo $withval |sed -e 's/^.*://'`" + AC_MSG_CHECKING(checking for Expat includes in $expat_include libs in $expat_ldflags ) + ;; + *) + expat_include="$withval/include" + expat_ldflags="$withval/lib" + AC_MSG_CHECKING(checking for Expat includes in $withval) + ;; + esac + fi + fi +]) + +if test "x$expat_base_dir" = "x"; then + AC_MSG_CHECKING([for Expat location]) + AC_CACHE_VAL(ats_cv_expat_dir,[ + for dir in /usr/local /usr; do + if test -d $dir && test -f $dir/include/expat.h; then + ats_cv_expat_dir=$dir + break + fi + done + ]) + expat_base_dir=$ats_cv_expat_dir + if test "x$expat_base_dir" = "x"; then + enable_expat=no + AC_MSG_RESULT([not found]) + else + enable_expat=yes + expat_include="$expat_base_dir/include" + expat_ldflags="$expat_base_dir/lib" + AC_MSG_RESULT([${expat_base_dir}]) + fi +else + if test -d $expat_include && test -d $expat_ldflags && test -f $expat_include/expat.h; then + AC_MSG_RESULT([ok]) + else + AC_MSG_RESULT([not found]) + fi +fi + +expath=0 +if test "$enable_expat" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + expat_have_headers=0 + expat_have_libs=0 + if test "$expat_base_dir" != "/usr"; then + TS_ADDTO(CPPFLAGS, [-I${expat_include}]) + TS_ADDTO(LDFLAGS, [-L${expat_ldflags}]) + TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R${expat_ldflags}]) + fi + AC_CHECK_LIB(expat, XML_SetUserData, [expat_have_libs=1]) + if test "$expat_have_libs" != "0"; then + TS_FLAG_HEADERS(expat.h, [expat_have_headers=1]) + fi + if test "$expat_have_headers" != "0"; then + enable_xml=yes + + AC_SUBST([LIBEXPAT],["-lexpat"]) + AC_DEFINE([HAVE_LIBEXPAT],[1],[Define to 1 if you have Expat library]) + else + enable_expat=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi +AC_SUBST(expath) +]) diff --git a/build/zlib.m4 b/build/zlib.m4 new file mode 100644 index 00000000..50fbe02e --- /dev/null +++ b/build/zlib.m4 @@ -0,0 +1,100 @@ +dnl -------------------------------------------------------- -*- autoconf -*- +dnl Licensed to the Apache Software Foundation (ASF) under one or more +dnl contributor license agreements. See the NOTICE file distributed with +dnl this work for additional information regarding copyright ownership. +dnl The ASF licenses this file to You under the Apache License, Version 2.0 +dnl (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl +dnl http://www.apache.org/licenses/LICENSE-2.0 +dnl +dnl Unless required by applicable law or agreed to in writing, software +dnl distributed under the License is distributed on an "AS IS" BASIS, +dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +dnl See the License for the specific language governing permissions and +dnl limitations under the License. + +dnl +dnl zlib.m4: Trafficserver's zlib autoconf macros +dnl + +dnl +dnl TS_CHECK_ZLIB: look for zlib libraries and headers +dnl +AC_DEFUN([TS_CHECK_ZLIB], [ +enable_zlib=no +AC_ARG_WITH(zlib, [AC_HELP_STRING([--with-zlib=DIR],[use a specific zlib library])], +[ + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + zlib_base_dir="$withval" + if test "$withval" != "no"; then + enable_zlib=yes + case "$withval" in + *":"*) + zlib_include="`echo $withval |sed -e 's/:.*$//'`" + zlib_ldflags="`echo $withval |sed -e 's/^.*://'`" + AC_MSG_CHECKING(checking for zlib includes in $zlib_include libs in $zlib_ldflags ) + ;; + *) + zlib_include="$withval/include" + zlib_ldflags="$withval/lib" + AC_MSG_CHECKING(checking for zlib includes in $withval) + ;; + esac + fi + fi +]) + +if test "x$zlib_base_dir" = "x"; then + AC_MSG_CHECKING([for zlib location]) + AC_CACHE_VAL(ats_cv_zlib_dir,[ + for dir in /usr/local /usr ; do + if test -d $dir && test -f $dir/include/zlib.h; then + ats_cv_zlib_dir=$dir + break + fi + done + ]) + zlib_base_dir=$ats_cv_zlib_dir + if test "x$zlib_base_dir" = "x"; then + enable_zlib=no + AC_MSG_RESULT([not found]) + else + enable_zlib=yes + zlib_include="$zlib_base_dir/include" + zlib_ldflags="$zlib_base_dir/lib" + AC_MSG_RESULT([$zlib_base_dir]) + fi +else + if test -d $zlib_include && test -d $zlib_ldflags && test -f $zlib_include/zlib.h; then + AC_MSG_RESULT([ok]) + else + AC_MSG_RESULT([not found]) + fi +fi + +zlibh=0 +if test "$enable_zlib" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + zlib_have_headers=0 + zlib_have_libs=0 + if test "$zlib_base_dir" != "/usr"; then + TS_ADDTO(CPPFLAGS, [-I${zlib_include}]) + TS_ADDTO(LDFLAGS, [-L${zlib_ldflags}]) + TS_ADDTO(LIBTOOL_LINK_FLAGS, [-rpath ${zlib_ldflags}]) + fi + AC_CHECK_LIB(z, compressBound, [zlib_have_libs=1]) + if test "$zlib_have_libs" != "0"; then + TS_FLAG_HEADERS(zlib.h, [zlib_have_headers=1]) + fi + if test "$zlib_have_headers" != "0"; then + TS_ADDTO(LIBS, [-lz]) + else + enable_zlib=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi +AC_SUBST(zlibh) +]) diff --git a/ci/README b/ci/README new file mode 100644 index 00000000..9450a791 --- /dev/null +++ b/ci/README @@ -0,0 +1,6 @@ +This directory is used by Apache Build Services (Buildbot) + +Any file listed in the rat-excludes.txt file won't figure in the rat reports +since some files don't need license headers, and can be excluded +Every build by buildbot also produces a rat report and publishes it on the +Build Services website diff --git a/ci/rat-excludes.txt b/ci/rat-excludes.txt new file mode 100644 index 00000000..432413a9 --- /dev/null +++ b/ci/rat-excludes.txt @@ -0,0 +1,108 @@ +ci/ +proxy/config/ +iocore/fastio/inkfio/inkfio.conf +**/*.a +**/*.so +**/*.o +**/*.Po +**/*.in +**/*.Plo +**/*.la +**/*.lai +**/*.lo +**/Makefile +.gitignore +.indent.pro +aclocal.m4 +CHANGES +autom4te.cache/ +build/ +LAYOUT +configure +tags +libtool +config.log +config.status +config.nice +configure +REVIEWERS +proxy/README-stats.otl +proxy/http/README.via +proxy/ClassH.txt +proxy/DebugStreamLevels.txt +proxy/trafficserver-release +proxy/cache_test.config +proxy/congest/FeatureSpec.txt +proxy/http/stats.memo +proxy/issues.txt +mgmt/cli/cli_detailed_command_list.txt +mgmt/cli/cli_feature_spec.txt +example/README.internal +example/blacklist-1/blacklist.txt +example/thread-pool/TESTPLAN.txt +example/thread-pool/test/SynTest/ +example/thread-pool/test/SDKTest/SDKtest_server.config +example/app-template/records.config +test/SDKtest/client/SDKtest_client.config +test/SDKtest/client/api/host.allow +test/SDKtest/client/api/host.forbid +test/SDKtest/client/byterate.3000 +test/SDKtest/client/byterate.fast +test/SDKtest/client/byterate.modem +test/SDKtest/client/docsize.10000 +test/SDKtest/client/docsize.isp +test/SDKtest/client/docsize.real +test/SDKtest/client/docsize.specweb +test/SDKtest/client/thinktime.0 +test/SDKtest/client/thinktime.1sec +test/SDKtest/client/thinktime.slow +doc/dot/ +doc/Doxyfile +doc/Doxyfile.in +lib/ts/ParseRulesCType +lib/ts/ParseRulesCTypeToLower +lib/ts/ParseRulesCTypeToUpper +lib/ts/fastlz.h +lib/ts/fastlz.c +lib/ts/stamp-h1 +lib/ts/test_Map +lib/ts/test_Vec +lib/ts/test_arena +lib/ts/test_atomic +lib/ts/test_freelist +iocore/aio/sample.cfg +iocore/cache/Notes +iocore/cache/cache_test.config +iocore/fastio/tools/advbmark/runme +lib/records/test_records.config +mgmt/stats/spec +proxy/mime.types +proxy/msgs/TSMessages.mc +proxy/msgs/TSMsgs.rc +test/SDKtest/synth_server/SDKtest_server.config +test/deft/defs/climatelab.def +test/deft/defs/localhost.def +test/plugin/INKHttpHooksTrans/altSelect.notes +mgmt/cli/hashtable.cc +lib/ts/ink_res_init.cc +lib/ts/ink_res_mkquery.cc +lib/ts/ink_rand.h +lib/ts/ink_rand.cc +lib/tsconfig/BisonHeaderToC++.sed +README.libev +README-EC2 +REVIEWERS +contrib/perl/AdminClient/Changes +contrib/perl/AdminClient/MANIFEST +ats-install/ +cop/traffic_cop +mgmt/api/remote/traffic_api_cli_remote +mgmt/cli/traffic_line +mgmt/cli/traffic_shell +mgmt/traffic_manager +proxy/traffic_server +proxy/traffic_logcat +proxy/traffic_logstats +proxy/traffic_sac +lib/tsconfig/test-1.tsconfig +rc/solaris.txt diff --git a/config.layout b/config.layout new file mode 100644 index 00000000..61e86fa8 --- /dev/null +++ b/config.layout @@ -0,0 +1,211 @@ +## +## config.layout -- Pre-defined Installation Path Layouts +## +## Licensed to the Apache Software Foundation (ASF) under one +## or more contributor license agreements. See the NOTICE file +## distributed with this work for additional information +## regarding copyright ownership. The ASF licenses this file +## to you under the Apache License, Version 2.0 (the +## "License"); you may not use this file except in compliance +## with the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## +## Hints: +## - layouts can be loaded with configure's --enable-layout=ID option +## - when no --enable-layout option is given, the default layout is +## `Trafficserver' +## - a trailing plus character (`+') on paths is replaced with a +## `/' suffix where is currently hardcoded to +## 'trafficserver'. +## (This may become a configurable parameter at some point.) +## + +# Classical TrafficServer path layout. + + prefix: /usr/local + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec+ + infodir: ${prefix}/info + mandir: ${prefix}/man + sysconfdir: ${prefix}/etc+ + datadir: ${prefix}/share+ + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: ${prefix}/var + runtimedir: ${localstatedir}+ + logdir: ${localstatedir}/log+ + cachedir: ${localstatedir}+ + + +# Classical Apache path layout. + + prefix: /usr/local/trafficserver + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/modules + infodir: ${prefix}/info + mandir: ${prefix}/man + sysconfdir: ${prefix}/conf + datadir: ${prefix}/share + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: ${prefix} + runtimedir: ${localstatedir}/logs + logdir: ${localstatedir}/logs + cachedir: ${localstatedir}/cache + + +# GNU standards conforming path layout. +# See FSF's GNU project `make-stds' document for details. + + prefix: /usr/local + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + infodir: ${prefix}/info + mandir: ${prefix}/man + sysconfdir: ${prefix}/etc+ + datadir: ${prefix}/share+ + installbuilddir: ${datadir}/build + includedir: ${prefix}/include+ + localstatedir: ${prefix}/var+ + runtimedir: ${localstatedir}/run + logdir: ${localstatedir}/log + cachedir: ${localstatedir}/cache + + +# Mac OS X Server (Rhapsody) + + prefix: /Local/Library/TrafficServer + exec_prefix: /usr + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: /System/Library/TrafficServer/Modules + infodir: ${exec_prefix}/share/info + mandir: ${exec_prefix}/share/man + sysconfdir: ${prefix}/Configuration + datadir: ${prefix}/Share + installbuilddir: /System/Library/TrafficServer/Build + includedir: /System/Library/Frameworks/TrafficServer.framework/Versions/2.0/Headers + localstatedir: /var + runtimedir: ${prefix}/Logs + logdir: ${prefix}/Logs + cachedir: ${prefix}/TrafficServerCache + + +# Darwin/Mac OS Layout + + prefix: /usr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec+ + infodir: ${prefix}/share/info + mandir: ${prefix}/share/man + datadir: /Library/TrafficServer + sysconfdir: /etc+ + installbuilddir: ${prefix}/share/trafficserver/build + includedir: ${prefix}/include+ + localstatedir: /var+ + runtimedir: ${localstatedir}/run + logdir: ${localstatedir}/log + cachedir: ${localstatedir}/cache + + +# According to the /opt filesystem conventions + + prefix: /opt/trafficserver + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + infodir: ${prefix}/info + mandir: ${prefix}/man + sysconfdir: /etc${prefix} + datadir: ${prefix}/share + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: /var${prefix} + runtimedir: ${localstatedir}/run + logdir: ${localstatedir}/logs + cachedir: ${localstatedir}/cache + + + +# Solaris 8 Layout + + prefix: /usr/trafficserver + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/bin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + infodir: ${prefix}/info + mandir: ${prefix}/man + sysconfdir: /etc+ + datadir: /var+ + installbuilddir: ${datadir}/build + includedir: ${prefix}/include + localstatedir: ${prefix} + runtimedir: /var/run+ + logdir: ${datadir}/logs + cachedir: ${datadir}/cache + + + +# Debian layout + + prefix: /usr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib+ + libexecdir: ${exec_prefix}/lib/trafficserver/modules + infodir: ${prefix}/share/info + mandir: ${prefix}/share/man + sysconfdir: /etc+ + datadir: /var/cache+ + installbuilddir: ${prefix}/share/trafficserver/build + includedir: ${prefix}/include + localstatedir: /var/run + runtimedir: /var/run+ + logdir: /var/log+ + cachedir: /var/cache+ + + +# Gentoo Linux TrafficServer path layout. + + prefix: /usr + exec_prefix: ${prefix} + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib+ + libexecdir: ${libdir}/plugins + infodir: ${prefix}/share/info + mandir: ${prefix}/share/man + sysconfdir: /etc+ + datadir: ${prefix}/share+ + installbuilddir: ${datadir}/build + includedir: ${prefix}/include+ + localstatedir: /var+ + runtimedir: /var/run+ + logdir: /var/log+ + cachedir: /var/cache+ + diff --git a/configure b/configure new file mode 100755 index 00000000..40a4cbe4 --- /dev/null +++ b/configure @@ -0,0 +1,24565 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.68 for Apache Traffic Server 3.0.5. +# +# Report bugs to . +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: dev@trafficserver.apache.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='Apache Traffic Server' +PACKAGE_TARNAME='trafficserver' +PACKAGE_VERSION='3.0.5' +PACKAGE_STRING='Apache Traffic Server 3.0.5' +PACKAGE_BUGREPORT='dev@trafficserver.apache.org' +PACKAGE_URL='http://trafficserver.apache.org' + +ac_unique_file="proxy/Main.cc" +ac_default_prefix=/usr/local/trafficserver +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +TFW_PACKAGE_SUFFIX +SHARED_LDFLAGS +SHARED_CXXLINKFLAGS +SHARED_CXXFLAGS +SHARED_CFLAGS +MGMT_DEFS +iocore_include_dirs +LIBTOOL_LINK_FLAGS +EXTRA_CXX_LDFLAGS +EXTRA_CC_LDFLAGS +EXPAT_LDFLAGS +API_DEFS +gethostbyname_r_hostent_data +gethostbyname_r_glibc2 +default_loopback_iface +ip_transparent +use_tproxy +netinet_ip_icmph +netinet_iph +net_ppp_defsh +mathh +sys_sysmacrosh +sys_paramh +sys_mounth +stroptsh +cpioh +allocah +valuesh +libgenh +floath +waith +malloch +siginfoh +ctypeh +netdbh +arpa_nameser_compath +arpa_nameserh +arpa_ineth +sys_systeminfoh +sys_sysinfoh +sys_sysctlh +sys_sockioh +sys_byteorderh +sys_ioctlh +netinet_tcph +netinet_in_systmh +netinet_inh +endianh +machine_endianh +sys_eventh +sys_epollh +use_posix_cap +LIBCAP +need_union_semun +has_demangle +LIBDEMANGLE +has_profiler +LIBPROFILER +use_port +use_kqueue +use_epoll +use_libev +has_backtrace +execinfoh +LIBEXECINFO +pcre_pcreh +pcreh +LIBPCRE +has_eventfd +has_strlcat +has_strlcpy +has_strndup +has_srand48_r +has_lrand48_r +has_posix_fadvise +has_posix_memalign +has_clock_gettime +expath +LIBEXPAT +LIBTCL +TCL_STUB_LIB_SPEC +TCL_STUB_LIB_FLAG +TCL_STUB_LIB_FILE +TCL_LIB_SPEC +TCL_LIB_FLAG +TCL_LIB_FILE +TCL_SRC_DIR +TCL_BIN_DIR +TCL_PATCH_LEVEL +TCL_VERSION +lzmah +zlibh +LIBSSL +LIBCRYPT +LIBEV +LIBICONV +LIBRT +LIBTHREAD +LIBRESOLV +LIBNSL +LIBSOCKET +LIBDL +LIBMLD +LIBEXC +defer_accept +ac_cv_sizeof_voidp +PERL +DOXYGEN +LEXLIB +LEX_OUTPUT_ROOT +LEX +YFLAGS +YACC +ASCPP +RM +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +LIBTOOL +LN_S +am__fastdepCCAS_FALSE +am__fastdepCCAS_TRUE +CCASDEPMODE +CCASFLAGS +CCAS +CXXCPP +CPP +SED +CCACHE +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +pkgcachedir +pkglogdir +pkgruntimedir +pkglocalstatedir +pkgdatadir +pkgsysconfdir +pkglibexecdir +pkglibdir +pkgsbindir +pkgbindir +cachedir +rel_cachedir +exp_cachedir +logdir +rel_logdir +exp_logdir +runtimedir +rel_runtimedir +exp_runtimedir +rel_localstatedir +exp_localstatedir +rel_includedir +exp_includedir +installbuilddir +rel_installbuilddir +exp_installbuilddir +rel_datadir +exp_datadir +rel_sysconfdir +exp_sysconfdir +rel_mandir +exp_mandir +rel_infodir +exp_infodir +rel_libexecdir +exp_libexecdir +rel_libdir +exp_libdir +rel_sbindir +exp_sbindir +rel_bindir +exp_bindir +rel_exec_prefix +exp_exec_prefix +rel_prefix +exp_prefix +max_api_stats +BUILD_WCCP_FALSE +BUILD_WCCP_TRUE +has_wccp +has_inkapi +enable_remote_cov_commit +STATIC_LIBTS_FALSE +STATIC_LIBTS_TRUE +STANDALONE_IOCORE_FALSE +STANDALONE_IOCORE_TRUE +ink_with_modules_process +ink_with_modules_local +ink_with_modules_def +IOCORE_MODULARIZED_DEFS +has_standalone_iocore +is_micro_build +has_purify +BUILD_TESTS_FALSE +BUILD_TESTS_TRUE +has_tests +use_diags +use_fast_sdk +pkgsysgroup +pkgsysuser +build_group +build_person +build_machine +HOST_GUESS +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +TS_VERSION_MICRO +TS_VERSION_MINOR +TS_VERSION_MAJOR +TS_VERSION_NUMBER +TS_VERSION_STRING +TS_LIBTOOL_VERSION +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_layout +with_user +with_group +enable_debug +enable_fast_sdk +enable_diags +enable_tests +enable_purify +enable_libev +enable_micro +enable_standalone_iocore +enable_static_libts +enable_remote_cov_commit +enable_api +enable_wccp +with_profiler +enable_eventfd +enable_posix_cap +enable_ccache +enable_tproxy +with_max_api_stats +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +with_sysroot +enable_libtool_lock +with_architecture +with_openssl +with_zlib +with_lzma +with_tcl +with_expat +with_pcre +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CXXCPP +CCAS +CCASFLAGS +YACC +YFLAGS +DOXYGEN +PERL' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures Apache Traffic Server 3.0.5 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/trafficserver] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of Apache Traffic Server 3.0.5:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-layout=LAYOUT Enable LAYOUT specified inside config.layout file + (defaults to TrafficServer) + --enable-debug turn on debugging + --enable-fast-sdk enable fast SDK APIs (no input parameter sanity + checks) + --disable-diags turn off diags + --disable-tests turn off regression tests + --enable-purify enable support for Purify + --enable-libev use libev even if not required + --enable-micro enable micro-TS build [default: no] + --enable-standalone-iocore + build just standalone iocore + --enable-static-libts build some static libts (dev only) + --enable-remote-cov-commit=HOST + commit cov defects to remote host [HOST=localhost] + --disable-api do not enable API and plugin support + --enable-wccp enable WCCP v2 + --disable-eventfd turn off eventfd and use pipes + --disable-posix-cap Use user id switching instead of POSIX capabilities + --enable-ccache Enable ccache (can cause bad builds) + --enable-tproxy[=ARG] Use TPROXY to enable connection transparency. 'auto' + or omitted for local system default, 'no' to + disable, 'force' to use built in default, number to + use as IP_TRANSPARENT sockopt. [default=auto] + + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-user specify the system user [default: nobody] + --with-group specify the system group [default: nobody] + --with-profiler enable support for profiler [default=no] + --with-max-api-stats max number of plugin stats [default=512] + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + --with-architecture=ARCH + use a specific CPU architecture + --with-openssl=DIR use a specific OpenSSL library + --with-zlib=DIR use a specific zlib library + --with-lzma=DIR use a specific lzma library + --with-tcl directory containing tcl configuration + (tclConfig.sh) + --with-expat=DIR use a specific Expat library + --with-pcre=DIR use a specific pcre library + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CXXCPP C++ preprocessor + CCAS assembler compiler command (defaults to CC) + CCASFLAGS assembler compiler flags (defaults to CFLAGS) + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + DOXYGEN full path of Doxygen executable + PERL full path of Perl executable + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +Apache Traffic Server home page: . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +Apache Traffic Server configure 3.0.5 +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## ------------------------------------------- ## +## Report this to dev@trafficserver.apache.org ## +## ------------------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by Apache Traffic Server $as_me 3.0.5, which was +generated by GNU Autoconf 2.68. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in build/aux "$srcdir"/build/aux; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in build/aux \"$srcdir\"/build/aux" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='trafficserver' + VERSION='3.0.5' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +ac_config_headers="$ac_config_headers lib/ts/ink_autoconf.h" + + +# Not sure this is needed, and seems to break with some versions of automake +#LT_INIT([dlopen]) + +# Libtool versioning uses different conventions on different +# platforms. At least on FreeBSD, libtool uses an overly complex +# convention that attempts to solve problems that most people just +# don't have and which just causes confusion for most end users. +# +TS_VERSION_MAJOR=$((3000005 / 1000000 )) +TS_VERSION_MINOR=$(((3000005 / 1000) % 1000 )) +TS_VERSION_MICRO=$((3000005 % 1000 )) +TS_LIBTOOL_MAJOR=`echo $((${TS_VERSION_MAJOR} + ${TS_VERSION_MINOR}))` +TS_LIBTOOL_VERSION=$TS_LIBTOOL_MAJOR:$TS_VERSION_MICRO:$TS_VERSION_MINOR +TS_VERSION_STRING=3.0.5 +TS_VERSION_NUMBER=3000005 + +# +# Substitute the above version numbers into the various files below. +# + + + + + + + + + + + +# +# Generate ./config.nice for reproducing runs of configure +# + + rm -f config.nice + cat >config.nice<> config.nice + fi + if test -n "$CXX"; then + echo "CXX=\"$CXX\"; export CXX" >> config.nice + fi + if test -n "$CFLAGS"; then + echo "CFLAGS=\"$CFLAGS\"; export CFLAGS" >> config.nice + fi + if test -n "$CXXFLAGS"; then + echo "CXXFLAGS=\"$CXXFLAGS\"; export CXXFLAGS" >> config.nice + fi + if test -n "$CPPFLAGS"; then + echo "CPPFLAGS=\"$CPPFLAGS\"; export CPPFLAGS" >> config.nice + fi + if test -n "$LDFLAGS"; then + echo "LDFLAGS=\"$LDFLAGS\"; export LDFLAGS" >> config.nice + fi + if test -n "$LTFLAGS"; then + echo "LTFLAGS=\"$LTFLAGS\"; export LTFLAGS" >> config.nice + fi + if test -n "$LIBS"; then + echo "LIBS=\"$LIBS\"; export LIBS" >> config.nice + fi + if test -n "$INCLUDES"; then + echo "INCLUDES=\"$INCLUDES\"; export INCLUDES" >> config.nice + fi + if test -n "$NOTEST_CFLAGS"; then + echo "NOTEST_CFLAGS=\"$NOTEST_CFLAGS\"; export NOTEST_CFLAGS" >> config.nice + fi + if test -n "$NOTEST_CXXFLAGS"; then + echo "NOTEST_CXXFLAGS=\"$NOTEST_CXXFLAGS\"; export NOTEST_CXXFLAGS" >> config.nice + fi + if test -n "$NOTEST_CPPFLAGS"; then + echo "NOTEST_CPPFLAGS=\"$NOTEST_CPPFLAGS\"; export NOTEST_CPPFLAGS" >> config.nice + fi + if test -n "$NOTEST_LDFLAGS"; then + echo "NOTEST_LDFLAGS=\"$NOTEST_LDFLAGS\"; export NOTEST_LDFLAGS" >> config.nice + fi + if test -n "$NOTEST_LIBS"; then + echo "NOTEST_LIBS=\"$NOTEST_LIBS\"; export NOTEST_LIBS" >> config.nice + fi + + # Retrieve command-line arguments. + eval "set x $0 $ac_configure_args" + shift + + for arg + do + +ats_last= +ats_cur="$arg" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +arg="${ats_cur}" + + echo "\"$arg\" \\" >> config.nice + done + echo '"$@"' >> config.nice + chmod +x config.nice + + +# XXX we can't just use AC_PREFIX_DEFAULT because that isn't subbed in +# by configure until it is too late. Is that how it should be or not? +# Something seems broken here. + + +# Get the layout here, so we can pass the required variables to Trafficserver + +# Check whether --enable-layout was given. +if test "${enable_layout+set}" = set; then : + enableval=$enable_layout; + LAYOUT=$enableval + +fi + + +if test -z "$LAYOUT"; then + LAYOUT="TrafficServer" +fi + + if test ! -f $srcdir/config.layout; then + echo "** Error: Layout file $srcdir/config.layout not found" + echo "** Error: Cannot use undefined layout '$LAYOUT'" + exit 1 + fi + # Catch layout names including a slash which will otherwise + # confuse the heck out of the sed script. + case $LAYOUT in + */*) + echo "** Error: $LAYOUT is not a valid layout name" + exit 1 ;; + esac + pldconf=./config.pld + + sed -e "1s/[ ]*<[lL]ayout[ ]*$LAYOUT[ ]*>[ ]*//;1t" \ + -e "1,/[ ]*<[lL]ayout[ ]*$LAYOUT[ ]*>[ ]*/d" \ + -e '/[ ]*<\/Layout>[ ]*/,$d' \ + -e "s/^[ ]*//g" \ + -e "s/:[ ]*/=\'/g" \ + -e "s/[ ]*$/'/g" \ + $srcdir/config.layout > $pldconf + layout_name=$LAYOUT + if test ! -s $pldconf; then + echo "** Error: unable to find layout $layout_name" + exit 1 + fi + . $pldconf + rm $pldconf + for var in prefix exec_prefix bindir sbindir libexecdir mandir infodir \ + sysconfdir datadir includedir localstatedir runtimedir \ + logdir libdir installbuilddir libsuffix cachedir; do + eval "val=\"\$$var\"" + case $val in + *+) + val=`echo $val | sed -e 's;\+$;;'` + eval "$var=\"\$val\"" + autosuffix=yes + ;; + *) + autosuffix=no + ;; + esac + val=`echo $val | sed -e 's:\(.\)/*$:\1:'` + val=`echo $val | sed -e 's:[\$]\([a-z_]*\):$\1:g'` + if test "$autosuffix" = "yes"; then + if echo $val | grep -i '/trafficserver$' >/dev/null; then + addtarget=no + else + addtarget=yes + fi + if test "$addtarget" = "yes"; then + val="$val/trafficserver" + fi + fi + eval "$var='$val'" + done + for var in bindir sbindir libexecdir mandir infodir sysconfdir \ + datadir localstatedir runtimedir logdir libdir cachedir; do + eval "val=\"\$$var\"" + case $val in + *+) + val=`echo $val | sed -e 's;\+$;;'` + eval "$var=\"\$val\"" + autosuffix=yes + ;; + *) + autosuffix=no + ;; + esac + org_val= + exp_val="$val" + while test "x$exp_val" != "x$org_val"; + do + org_val="$exp_val" + exp_val="`eval \"echo $exp_val\"`" + done + if echo $exp_val | grep -i '/trafficserver$' >/dev/null; then + addtarget=no + else + addtarget=yes + fi + if test "$addsuffix" = "yes" -a "$addtarget" = "yes"; then + val="$val/trafficserver" + fi + var="pkg$var" + eval "$var='$val'" + done + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for chosen layout" >&5 +$as_echo_n "checking for chosen layout... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $layout_name" >&5 +$as_echo "$layout_name" >&6; } + + +# Reparse the configure arguments so we can override the layout. + +ac_prev= +# Retrieve the command-line arguments. The eval is needed because +# the arguments are quoted to preserve accuracy. +eval "set x $ac_configure_args" +shift +for ac_option +do +# If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" + pkgbindir="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" + pkgdatadir="$ac_optarg" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" + pkglibdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" + pkglibexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" + pkglocalstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -runtimedir | --runtimedir | --runtimedi | --runtimed | --runtime | --runtim \ + | --runti | --runt | --run | --ru | --r) + ac_prev=runtimedir ;; + -runtimedir=* | --runtimedir=* | --runtimedi=* | --runtimed=* | --runtime=* \ + | --runtim=* | --runti=* | --runt=* | --run=* | --ru=* | --r=*) + ac_prev=runtimedir ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" + pkgsbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" + pkgsysconfdir="$ac_optarg" ;; + + esac +done + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) as_fn_error $? "expected an absolute path for --$ac_var: $ac_val" "$LINENO" 5;; + esac +done + + + +# +# Host detection +# +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +HOST_GUESS="$host" + + +# +# Build environment +# +build_person="`id -nu`" +build_group="`id -ng`" +build_machine="`uname -n`" + + + + + +# Check whether --with-user was given. +if test "${with_user+set}" = set; then : + withval=$with_user; + with_user="$withval" + +else + + with_user="nobody" + + +fi + + +default_group="`id -ng $with_user`" + +# Check whether --with-group was given. +if test "${with_group+set}" = set; then : + withval=$with_group; + with_group="$withval" + +else + + with_group=${default_group:-nobody} + + +fi + +pkgsysuser=$with_user + +pkgsysgroup=$with_group + + +# ----------------------------------------------------------------------------- +# 2. SITE CONFIGURATION + +# +# Debug +# + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5 +$as_echo_n "checking whether to enable debugging... " >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; +else + enable_debug=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug" >&5 +$as_echo "$enable_debug" >&6; } + +# +# Fast SDK APIs, this disables the parameter checks (assert) +# on all APIs. +# + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable fast SDK APIs" >&5 +$as_echo_n "checking whether to enable fast SDK APIs... " >&6; } +# Check whether --enable-fast-sdk was given. +if test "${enable_fast_sdk+set}" = set; then : + enableval=$enable_fast_sdk; +else + enable_fast_sdk=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_fast_sdk" >&5 +$as_echo "$enable_fast_sdk" >&6; } + + tsl_prefix="use" + tsl_stem="fast_sdk" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + + +# +# Diags +# + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable diags" >&5 +$as_echo_n "checking whether to enable diags... " >&6; } +# Check whether --enable-diags was given. +if test "${enable_diags+set}" = set; then : + enableval=$enable_diags; +else + enable_diags=yes + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_diags" >&5 +$as_echo "$enable_diags" >&6; } + + tsl_prefix="use" + tsl_stem="diags" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + + +# +# Build regression tests? +# + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable regression tests" >&5 +$as_echo_n "checking whether to enable regression tests... " >&6; } +# Check whether --enable-tests was given. +if test "${enable_tests+set}" = set; then : + enableval=$enable_tests; +else + enable_tests=yes + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tests" >&5 +$as_echo "$enable_tests" >&6; } + + tsl_prefix="has" + tsl_stem="tests" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + + if test 0 -ne $has_tests; then + BUILD_TESTS_TRUE= + BUILD_TESTS_FALSE='#' +else + BUILD_TESTS_TRUE='#' + BUILD_TESTS_FALSE= +fi + + +# +# Purify +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable purify" >&5 +$as_echo_n "checking whether to enable purify... " >&6; } +# Check whether --enable-purify was given. +if test "${enable_purify+set}" = set; then : + enableval=$enable_purify; +else + enable_purify=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_purify" >&5 +$as_echo "$enable_purify" >&6; } + + tsl_prefix="has" + tsl_stem="purify" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + + +# +# libev +# + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libev even if not required" >&5 +$as_echo_n "checking whether to use libev even if not required... " >&6; } +# Check whether --enable-libev was given. +if test "${enable_libev+set}" = set; then : + enableval=$enable_libev; +else + enable_libev=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libev" >&5 +$as_echo "$enable_libev" >&6; } + +# +# Micro +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable micro-TS" >&5 +$as_echo_n "checking whether to enable micro-TS... " >&6; } +# Check whether --enable-micro was given. +if test "${enable_micro+set}" = set; then : + enableval=$enable_micro; +else + enable_micro=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_micro" >&5 +$as_echo "$enable_micro" >&6; } +if test "x$enable_micro" = "xyes"; then : + is_micro_build=1 +else + is_micro_build=0 +fi + + +# +# Standalone iocore +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build a standalone iocore" >&5 +$as_echo_n "checking whether to build a standalone iocore... " >&6; } +# Check whether --enable-standalone-iocore was given. +if test "${enable_standalone_iocore+set}" = set; then : + enableval=$enable_standalone_iocore; +else + enable_standalone_iocore=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_standalone_iocore" >&5 +$as_echo "$enable_standalone_iocore" >&6; } + + tsl_prefix="has" + tsl_stem="standalone_iocore" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + +if test 0 -ne $has_standalone_iocore; then : + IOCORE_MODULARIZED_DEFS="" + + ink_with_modules_def="-DREC_BUILD_STAND_ALONE" + + ink_with_modules_local="" + + ink_with_modules_process="" + + +else + ink_with_modules_def="-DREC_BUILD_MGMT" + + ink_with_modules_local="-DLOCAL_MANAGER" + + ink_with_modules_process="-DPROCESS_MANAGER" + + + +fi + if test 0 -ne $has_standalone_iocore; then + STANDALONE_IOCORE_TRUE= + STANDALONE_IOCORE_FALSE='#' +else + STANDALONE_IOCORE_TRUE='#' + STANDALONE_IOCORE_FALSE= +fi + + +# +# Force some static linkage (for testing / development only) +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build some static libts (dev only)" >&5 +$as_echo_n "checking whether to build some static libts (dev only)... " >&6; } +# Check whether --enable-static-libts was given. +if test "${enable_static_libts+set}" = set; then : + enableval=$enable_static_libts; +else + enable_static_libts=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static_libts" >&5 +$as_echo "$enable_static_libts" >&6; } + + tsl_prefix="has" + tsl_stem="static_libts" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + if test 0 -ne $has_static_libts; then + STATIC_LIBTS_TRUE= + STATIC_LIBTS_FALSE='#' +else + STATIC_LIBTS_TRUE='#' + STATIC_LIBTS_FALSE= +fi + + +# +# Remote Coverity Prevent commit +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to commit cov defects to remote host" >&5 +$as_echo_n "checking whether to commit cov defects to remote host... " >&6; } +# Check whether --enable-remote-cov-commit was given. +if test "${enable_remote_cov_commit+set}" = set; then : + enableval=$enable_remote_cov_commit; +else + enable_remote_cov_commit=localhost + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_remote_cov_commit" >&5 +$as_echo "$enable_remote_cov_commit" >&6; } + + +# +# API +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable API and plugin support" >&5 +$as_echo_n "checking whether to enable API and plugin support... " >&6; } +# Check whether --enable-api was given. +if test "${enable_api+set}" = set; then : + enableval=$enable_api; +else + enable_api=yes + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_api" >&5 +$as_echo "$enable_api" >&6; } +if test "x$enable_api" = "xyes"; then : + has_inkapi=1 +else + has_inkapi=0 +fi + + +# +# WCCP +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable WCCP v2 support" >&5 +$as_echo_n "checking whether to enable WCCP v2 support... " >&6; } +# Check whether --enable-wccp was given. +if test "${enable_wccp+set}" = set; then : + enableval=$enable_wccp; +else + enable_wccp=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_wccp" >&5 +$as_echo "$enable_wccp" >&6; } + + tsl_prefix="has" + tsl_stem="wccp" + eval "tsl_enable=\$enable_${tsl_stem}" + if test "x$tsl_enable" = "xyes"; then : + eval "${tsl_prefix}_${tsl_stem}=1" +else + eval "${tsl_prefix}_${tsl_stem}=0" + +fi + + + if test 0 -ne $has_wccp; then + BUILD_WCCP_TRUE= + BUILD_WCCP_FALSE='#' +else + BUILD_WCCP_TRUE='#' + BUILD_WCCP_FALSE= +fi + + +# Google profiler +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable profiler" >&5 +$as_echo_n "checking whether to enable profiler... " >&6; } + +# Check whether --with-profiler was given. +if test "${with_profiler+set}" = set; then : + withval=$with_profiler; with_profiler=$withval +else + with_profiler=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_profiler" >&5 +$as_echo "$with_profiler" >&6; } + +# +# use eventfd() or pipes +# Found that ec2 is using an older kernel causing eventfd errors. +# Disable eventfd when using ATS on EC2 Fedora. +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable eventfd()" >&5 +$as_echo_n "checking whether to enable eventfd()... " >&6; } +# Check whether --enable-eventfd was given. +if test "${enable_eventfd+set}" = set; then : + enableval=$enable_eventfd; +else + enable_eventfd="yes" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_eventfd" >&5 +$as_echo "$enable_eventfd" >&6; } + +# +# use POSIX capabilities instead of user ID switching. +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use POSIX capabilities" >&5 +$as_echo_n "checking whether to use POSIX capabilities... " >&6; } +# Check whether --enable-posix-cap was given. +if test "${enable_posix_cap+set}" = set; then : + enableval=$enable_posix_cap; +else + enable_posix_cap="yes" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_posix_cap" >&5 +$as_echo "$enable_posix_cap" >&6; } + +# +# Enble ccache explicitly (it's disabled by default, because of build problems in some cases) +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ccache" >&5 +$as_echo_n "checking whether to enable ccache... " >&6; } +# Check whether --enable-ccache was given. +if test "${enable_ccache+set}" = set; then : + enableval=$enable_ccache; +else + enable_ccache="no" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_ccache" >&5 +$as_echo "$enable_ccache" >&6; } + +# +# Use TPROXY for connection transparency. +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable TPROXY based transparency" >&5 +$as_echo_n "checking whether to enable TPROXY based transparency... " >&6; } +# Check whether --enable-tproxy was given. +if test "${enable_tproxy+set}" = set; then : + enableval=$enable_tproxy; +else + enable_tproxy="auto" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tproxy" >&5 +$as_echo "$enable_tproxy" >&6; } + +# +# Configure how many stats to allocate for plugins. Default is 512. +# + +# Check whether --with-max-api-stats was given. +if test "${with_max_api_stats+set}" = set; then : + withval=$with_max_api_stats; max_api_stats=$withval +else + max_api_stats=512 + +fi + + + +# +# Installation directories +# For each var the following is evaluated +# foo Standard variable eg. ${prefix}/foo +# rel_foo Relative to prefix eg. foo +# + + +ats_last= +ats_cur="$prefix" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_prefix="${ats_cur}" + + +ats_stripped=`echo $exp_prefix | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_prefix" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_prefix="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_prefix="$exp_prefix" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_prefix" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_prefix" + + + + TS_VAR_SUBST="$TS_VAR_SUBST prefix" + + + + + +ats_last= +ats_cur="$exec_prefix" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_exec_prefix="${ats_cur}" + + +ats_stripped=`echo $exp_exec_prefix | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_exec_prefix" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_exec_prefix="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_exec_prefix="$exp_exec_prefix" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_exec_prefix" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_exec_prefix" + + + + TS_VAR_SUBST="$TS_VAR_SUBST exec_prefix" + + + + + +ats_last= +ats_cur="$bindir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_bindir="${ats_cur}" + + +ats_stripped=`echo $exp_bindir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_bindir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_bindir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_bindir="$exp_bindir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_bindir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_bindir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST bindir" + + + + + +ats_last= +ats_cur="$sbindir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_sbindir="${ats_cur}" + + +ats_stripped=`echo $exp_sbindir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_sbindir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_sbindir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_sbindir="$exp_sbindir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_sbindir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_sbindir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST sbindir" + + + + + +ats_last= +ats_cur="$libdir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_libdir="${ats_cur}" + + +ats_stripped=`echo $exp_libdir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_libdir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_libdir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_libdir="$exp_libdir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_libdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_libdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST libdir" + + + + + +ats_last= +ats_cur="$libexecdir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_libexecdir="${ats_cur}" + + +ats_stripped=`echo $exp_libexecdir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_libexecdir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_libexecdir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_libexecdir="$exp_libexecdir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_libexecdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_libexecdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST libexecdir" + + + + + +ats_last= +ats_cur="$infodir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_infodir="${ats_cur}" + + +ats_stripped=`echo $exp_infodir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_infodir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_infodir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_infodir="$exp_infodir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_infodir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_infodir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST infodir" + + + + + +ats_last= +ats_cur="$mandir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_mandir="${ats_cur}" + + +ats_stripped=`echo $exp_mandir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_mandir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_mandir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_mandir="$exp_mandir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_mandir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_mandir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST mandir" + + + + + +ats_last= +ats_cur="$sysconfdir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_sysconfdir="${ats_cur}" + + +ats_stripped=`echo $exp_sysconfdir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_sysconfdir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_sysconfdir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_sysconfdir="$exp_sysconfdir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_sysconfdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_sysconfdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST sysconfdir" + + + + + +ats_last= +ats_cur="$datadir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_datadir="${ats_cur}" + + +ats_stripped=`echo $exp_datadir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_datadir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_datadir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_datadir="$exp_datadir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_datadir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_datadir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST datadir" + + + + + +ats_last= +ats_cur="$installbuilddir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_installbuilddir="${ats_cur}" + + +ats_stripped=`echo $exp_installbuilddir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_installbuilddir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_installbuilddir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_installbuilddir="$exp_installbuilddir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_installbuilddir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_installbuilddir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST installbuilddir" + + + + + +ats_last= +ats_cur="$includedir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_includedir="${ats_cur}" + + +ats_stripped=`echo $exp_includedir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_includedir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_includedir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_includedir="$exp_includedir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_includedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_includedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST includedir" + + + + + +ats_last= +ats_cur="$localstatedir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_localstatedir="${ats_cur}" + + +ats_stripped=`echo $exp_localstatedir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_localstatedir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_localstatedir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_localstatedir="$exp_localstatedir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_localstatedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_localstatedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST localstatedir" + + + + + +ats_last= +ats_cur="$runtimedir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_runtimedir="${ats_cur}" + + +ats_stripped=`echo $exp_runtimedir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_runtimedir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_runtimedir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_runtimedir="$exp_runtimedir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_runtimedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_runtimedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST runtimedir" + + + + + +ats_last= +ats_cur="$logdir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_logdir="${ats_cur}" + + +ats_stripped=`echo $exp_logdir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_logdir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_logdir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_logdir="$exp_logdir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_logdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_logdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST logdir" + + + + + +ats_last= +ats_cur="$cachedir" +while test "x${ats_cur}" != "x${ats_last}"; +do + ats_last="${ats_cur}" + ats_cur=`eval "echo ${ats_cur}"` +done +exp_cachedir="${ats_cur}" + + +ats_stripped=`echo $exp_cachedir | sed -e "s#^${prefix}##"` +# check if the stripping was successful +if test "x$exp_cachedir" != "x${ats_stripped}"; then +# it was, so strip of any leading slashes + rel_cachedir="`echo ${ats_stripped} | sed -e 's#^/*##'`" +else +# it wasn't so return the original + rel_cachedir="$exp_cachedir" +fi + + + TS_VAR_SUBST="$TS_VAR_SUBST exp_cachedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST rel_cachedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST cachedir" + + + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkgbindir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkgsbindir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkglibdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkglibexecdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkgsysconfdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkgdatadir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkglocalstatedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkgruntimedir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkglogdir" + + + + TS_VAR_SUBST="$TS_VAR_SUBST pkgcachedir" + + + + +# ----------------------------------------------------------------------------- +# 3. CHECK FOR PROGRAMS + +# Compiler selection: +# +# Implementation note (toc) +# 1) Get default compiler settings (case statement.) +# 2) Check for over-rides of default compiler. +# 3) Set standard CFLAGS, SHARED_CFLAGS, etc. +# 4) (in first kludge mode block...) obtain any further CFLAG-type additions. +# 5) Test compilers with all flags set. + +# AC_PROG can sometimes mangle CFLAGS etc. +# in particular, on Linux they insert -g -O2, here we preserve any user CFLAGS + +#CC=gcc +#CXX=g++ + +REAL_CFLAGS="${CFLAGS}" +REAL_CXXFLAGS="${CXXFLAGS}" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +# Check for ccache (if explicitly enabled) +if test "x$enable_ccache" = "xyes"; then + # Extract the first word of "ccache", so it can be a program name with args. +set dummy ccache; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CCACHE+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CCACHE"; then + ac_cv_prog_CCACHE="$CCACHE" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CCACHE="ccache" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CCACHE=$ac_cv_prog_CCACHE +if test -n "$CCACHE"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CCACHE" >&5 +$as_echo "$CCACHE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x${CCACHE}" = "xccache"; then + CC="$CCACHE $CC" + CXX="$CCACHE $CXX" + fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# By default we simply use the C compiler to build assembly code. + +test "${CCAS+set}" = set || CCAS=$CC +test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS + + + +depcc="$CCAS" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CCAS_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CCAS_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CCAS_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CCAS_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; } +CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then + am__fastdepCCAS_TRUE= + am__fastdepCCAS_FALSE='#' +else + am__fastdepCCAS_TRUE='#' + am__fastdepCCAS_FALSE= +fi + + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4' +macro_revision='1.3293' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + lt_prog_compiler_pic='-Xcompiler -fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +esac + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +# Extract the first word of "rm", so it can be a program name with args. +set dummy rm; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RM"; then + ac_cv_prog_RM="$RM" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RM="rm" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RM=$ac_cv_prog_RM +if test -n "$RM"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 +$as_echo "$RM" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "cpp", so it can be a program name with args. +set dummy cpp; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ASCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ASCPP"; then + ac_cv_prog_ASCPP="$ASCPP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ASCPP="cpp" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ASCPP=$ac_cv_prog_ASCPP +if test -n "$ASCPP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ASCPP" >&5 +$as_echo "$ASCPP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="ar" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 +$as_echo_n "checking for library containing strerror... " >&6; } +if ${ac_cv_search_strerror+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strerror (); +int +main () +{ +return strerror (); + ; + return 0; +} +_ACEOF +for ac_lib in '' cposix; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_strerror=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_strerror+:} false; then : + break +fi +done +if ${ac_cv_search_strerror+:} false; then : + +else + ac_cv_search_strerror=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 +$as_echo "$ac_cv_search_strerror" >&6; } +ac_res=$ac_cv_search_strerror +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LEX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +$as_echo "$LEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { yyless (input () != 0); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ { ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 +$as_echo_n "checking lex output file root... " >&6; } +if ${ac_cv_prog_lex_root+:} false; then : + $as_echo_n "(cached) " >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +$as_echo "$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 +$as_echo_n "checking lex library... " >&6; } +if ${ac_cv_lib_lex+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_lex=$ac_lib +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +$as_echo "$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +$as_echo_n "checking whether yytext is a pointer... " >&6; } +if ${ac_cv_prog_lex_yytext_pointer+:} false; then : + $as_echo_n "(cached) " >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_prog_lex_yytext_pointer=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +if test "x$enable_wccp" = "xyes"; then : + + for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + + + + +fi + +# Extract the first word of "doxygen", so it can be a program name with args. +set dummy doxygen; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_DOXYGEN+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $DOXYGEN in + [\\/]* | ?:[\\/]*) + ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_DOXYGEN="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +DOXYGEN=$ac_cv_path_DOXYGEN +if test -n "$DOXYGEN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 +$as_echo "$DOXYGEN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # needed for Doxygen +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PERL+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_PERL" && ac_cv_path_PERL="not found" + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +$as_echo "$PERL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test "x$PERL" = "xnot found"; then : + as_fn_error $? "check for perl failed. Have you installed perl?" "$LINENO" 5 + +fi + + + +CFLAGS="${REAL_CFLAGS}" +CXXFLAGS="${REAL_CXXFLAGS}" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking checking whether to auto-set compile optimizing flags" >&5 +$as_echo_n "checking checking whether to auto-set compile optimizing flags... " >&6; } +has_optimizer_flags=`$as_echo "$CFLAGS $CXXFLAGS" | ${AWK} '/-x?O.?/{print "no"}'` +if test "x${has_optimizer_flags}" = "xno"; then : + optimizing_flags='' +else + + has_optimizer_flags='yes' + optimizing_flags='-O3' + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${has_optimizer_flags} ${optimizing_flags}" >&5 +$as_echo "${has_optimizer_flags} ${optimizing_flags}" >&6; } + +base_cc=`basename $CC` +# These are shortcuts used in combination for the compiler options below +case $host_os in + linux*) + if test "x${base_cc}" = "xicc"; then + # -Wall goes crazy, so turned these specific checks off for now: + # + # 111 is "statement is unrecahable" + # 279 is "controlling expression is constant", triggered by our asserts + # 383 is "value copied to temporary, reference to temporary used" + # 444 is "destructor for base class is not virtual" + # 522 is "function "xyz" redeclared "inline" after being called + # 873 is "has no corresponding operator delete". ToDo: we should fix. + # 981 is "operands are evaluated in unspecified order" + # 1418 is "external function definition with no prior declaration" + # 1419 is "external declaration in primary source file" + # 1572 is "floating-point equality and inequality comparisons are unreliable" + # 1720 is "operator new" has no corresponding member operator delete" + # 2256 is "non-pointer conversion from "int" to "unsigned char" " + # 2259 is "non-pointer conversion from "int" to "unsigned char" " + # + # TODO: We should try to eliminate more of these -wd exclusions. + common_opt="-pipe -Wall -wd111 -wd279 -wd383 -wd522 -wd444 -wd873 -wd981 -wd1418 -wd1419 -wd1572 -wd1720 -wd2256 -wd2259" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimization_flags -axsse4.2 -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + else # gcc + # This is useful for finding odd conversions + # common_opt="-pipe -Wall -Werror -Wconversion -Wno-sign-conversion" + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + fi + ;; + darwin*) + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I/opt/local/include\"" + CPPFLAGS="-I/opt/local/include" + else + ats_addto_bugger="-I/opt/local/include" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L/opt/local/lib\"" + LDFLAGS="-L/opt/local/lib" + else + ats_addto_bugger="-L/opt/local/lib" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + ;; + freebsd*|kfreebsd*) + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L/usr/local/lib\"" + LDFLAGS="-L/usr/local/lib" + else + ats_addto_bugger="-L/usr/local/lib" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + ;; + solaris*) + if test "x${base_cc}" = "xcc"; then + common_opt="-mt -m64 -D__WORDSIZE=64" # FIXME: arch should be detected + debug_opt="-g $common_opt" + release_opt="-g $common_opt $optimizing_flags" + cxx_opt="-library=stlport4" + cxx_dbg="+w2" + cxx_rel="-erroff" + +$as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX="-library=Crun" + fi + else # gcc + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + fi + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L/lib\"" + LDFLAGS="-L/lib" + else + ats_addto_bugger="-L/lib" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L/usr/local/lib\"" + LDFLAGS="-L/usr/local/lib" + else + ats_addto_bugger="-L/usr/local/lib" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + ;; + *) + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + ;; +esac + +cc_oflag_opt=$release_opt +cc_oflag_dbg=$debug_opt +cxx_oflag_opt="$release_opt $cxx_opt $cxx_rel" +cxx_oflag_dbg="$debug_opt $cxx_opt $cxx_dbg" + +SHARED_CFLAGS=-fPIC +SHARED_LDFLAGS=-shared +SHARED_CXXFLAGS=-fPIC +SHARED_CXXLINKFLAGS=-shared + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void*" >&5 +$as_echo_n "checking size of void*... " >&6; } +if ${ac_cv_sizeof_voidp+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void*))" "ac_cv_sizeof_voidp" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_voidp" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (void*) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_voidp=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_voidp" >&5 +$as_echo "$ac_cv_sizeof_voidp" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_VOIDP $ac_cv_sizeof_voidp +_ACEOF + + +if test "x$ac_cv_sizeof_voidp" == "x"; then + as_fn_error $? "Cannot determine size of void*" "$LINENO" 5 +fi + + + +# Checks for TCP defer accept +case $host_os in + linux*) + defer_accept=45 + ;; + *) + defer_accept=1 + ;; +esac + + + +# +# Here are all the extra linux-specific C(XX)FLAGS additions and +# so forth. +# TODO cpu architecture settings separate from operating system settings +# +cpu_architecture="" +# GCC: add a default march if there is not one set +if test "x${GCC}" = "xyes"; then + if test "${ac_cv_sizeof_voidp}" = "4"; then + case "$host_cpu" in + i?86* | k5-8* | pentium* | athlon) + cpu_architecture="-march=i586" + ;; + *sparc*) + cpu_architecture="-mv8" + ;; + esac + else + case "$host_cpu" in + x86_64 | amd64) + # XXX: Any need for 64-bit arch flags? + # cpu_architecture="-march=native" + ;; + *sparc*) + cpu_architecture="-march=ultrasparc" + ;; + esac + fi + # TODO: Add support for other compilers + # +fi + +# Overrride detected architecture with the user suplied one +# + +# Check whether --with-architecture was given. +if test "${with_architecture+set}" = set; then : + withval=$with_architecture; + if test "x$withval" != "xyes" && test "x$withval" != "xno"; then + case "$withval" in + -*) + # TODO: In case we are cross compiling some of the provided flags + # should be added to the LDFLAGS + cpu_architecture="$withval" + ;; + *) + cpu_architecture="-march=$withval" + ;; + esac + elif test "x$withval" = "x"; then + as_fn_error $? "--with-architecture requires an param" "$LINENO" 5 + fi + +fi + + +if test "x$cpu_architecture" != "x"; then + + if test "x$CFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CFLAGS to \"$cpu_architecture\"" + CFLAGS="$cpu_architecture" + else + ats_addto_bugger="$cpu_architecture" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CFLAGS" + CFLAGS="$CFLAGS $i" + fi + done + fi + + + if test "x$CXXFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CXXFLAGS to \"$cpu_architecture\"" + CXXFLAGS="$cpu_architecture" + else + ats_addto_bugger="$cpu_architecture" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CXXFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CXXFLAGS" + CXXFLAGS="$CXXFLAGS $i" + fi + done + fi + +fi + +# 64-bit LFS support +# + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-D_LARGEFILE64_SOURCE=1\"" + CPPFLAGS="-D_LARGEFILE64_SOURCE=1" + else + ats_addto_bugger="-D_LARGEFILE64_SOURCE=1" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + +if test "${ac_cv_sizeof_voidp}" = "8"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-D_COMPILE64BIT_SOURCE=1\"" + CPPFLAGS="-D_COMPILE64BIT_SOURCE=1" + else + ats_addto_bugger="-D_COMPILE64BIT_SOURCE=1" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + +else + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-D_FILE_OFFSET_BITS=64\"" + CPPFLAGS="-D_FILE_OFFSET_BITS=64" + else + ats_addto_bugger="-D_FILE_OFFSET_BITS=64" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + +fi + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-D_GNU_SOURCE\"" + CPPFLAGS="-D_GNU_SOURCE" + else + ats_addto_bugger="-D_GNU_SOURCE" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-D_REENTRANT\"" + CPPFLAGS="-D_REENTRANT" + else + ats_addto_bugger="-D_REENTRANT" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + +case $host_os in + linux*) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=linux + ;; + darwin*) + host_os_def=darwin + ;; + freebsd*) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=freebsd + ;; + kfreebsd*) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=freebsd + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-Dkfreebsd\"" + CPPFLAGS="-Dkfreebsd" + else + ats_addto_bugger="-Dkfreebsd" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + ;; + solaris*) + host_os_def=solaris + ;; + *) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=unknown + ;; +esac + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-D$host_os_def\"" + CPPFLAGS="-D$host_os_def" + else + ats_addto_bugger="-D$host_os_def" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build for host OS: $host_os, arch: $host_cpu, optimization: $host_os_def" >&5 +$as_echo "$as_me: Build for host OS: $host_os, arch: $host_cpu, optimization: $host_os_def" >&6;} + +# +# _Here_ is where we go ahead and add the _optimizations_ to already +# existing CFLAGS/CXXFLAGS if some special values had been set. +# +if test "x${enable_debug}" = "xyes"; then + + if test "x$CFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CFLAGS to \"${cc_oflag_dbg}\"" + CFLAGS="${cc_oflag_dbg}" + else + ats_addto_bugger="${cc_oflag_dbg}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CFLAGS" + CFLAGS="$CFLAGS $i" + fi + done + fi + + + if test "x$CXXFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CXXFLAGS to \"${cxx_oflag_dbg}\"" + CXXFLAGS="${cxx_oflag_dbg}" + else + ats_addto_bugger="${cxx_oflag_dbg}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CXXFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CXXFLAGS" + CXXFLAGS="$CXXFLAGS $i" + fi + done + fi + + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-DDEBUG -D_DEBUG\"" + CPPFLAGS="-DDEBUG -D_DEBUG" + else + ats_addto_bugger="-DDEBUG -D_DEBUG" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + +else + + if test "x$CFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CFLAGS to \"${cc_oflag_opt}\"" + CFLAGS="${cc_oflag_opt}" + else + ats_addto_bugger="${cc_oflag_opt}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CFLAGS" + CFLAGS="$CFLAGS $i" + fi + done + fi + + + if test "x$CXXFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CXXFLAGS to \"${cxx_oflag_opt}\"" + CXXFLAGS="${cxx_oflag_opt}" + else + ats_addto_bugger="${cxx_oflag_opt}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CXXFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CXXFLAGS" + CXXFLAGS="$CXXFLAGS $i" + fi + done + fi + +fi + +# +# Note: These are site-specific macro's that do various tests +# on the selected compilers. There was some tunning +# associated with our not wanting to use GNU for _everything_. +# Note: This macro may set certain parameters when run. +# + + +# ----------------------------------------------------------------------------- +# 4. CHECK FOR LIBRARIES + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for exc_capture_context in -lexc" >&5 +$as_echo_n "checking for exc_capture_context in -lexc... " >&6; } +if ${ac_cv_lib_exc_exc_capture_context+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lexc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char exc_capture_context (); +int +main () +{ +return exc_capture_context (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_exc_exc_capture_context=yes +else + ac_cv_lib_exc_exc_capture_context=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_exc_exc_capture_context" >&5 +$as_echo "$ac_cv_lib_exc_exc_capture_context" >&6; } +if test "x$ac_cv_lib_exc_exc_capture_context" = xyes; then : + LIBEXC="-lexc" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for MLD_demangle_string in -lmld" >&5 +$as_echo_n "checking for MLD_demangle_string in -lmld... " >&6; } +if ${ac_cv_lib_mld_MLD_demangle_string+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lmld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char MLD_demangle_string (); +int +main () +{ +return MLD_demangle_string (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_mld_MLD_demangle_string=yes +else + ac_cv_lib_mld_MLD_demangle_string=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mld_MLD_demangle_string" >&5 +$as_echo "$ac_cv_lib_mld_MLD_demangle_string" >&6; } +if test "x$ac_cv_lib_mld_MLD_demangle_string" = xyes; then : + LIBMLD="-lmld" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + LIBDL="-ldl" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 +$as_echo_n "checking for socket in -lsocket... " >&6; } +if ${ac_cv_lib_socket_socket+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_socket_socket=yes +else + ac_cv_lib_socket_socket=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 +$as_echo "$ac_cv_lib_socket_socket" >&6; } +if test "x$ac_cv_lib_socket_socket" = xyes; then : + LIBSOCKET="-lsocket" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if ${ac_cv_lib_nsl_gethostbyname+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nsl_gethostbyname=yes +else + ac_cv_lib_nsl_gethostbyname=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : + LIBNSL="-lnsl" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_init in -lresolv" >&5 +$as_echo_n "checking for res_init in -lresolv... " >&6; } +if ${ac_cv_lib_resolv_res_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char res_init (); +int +main () +{ +return res_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_resolv_res_init=yes +else + ac_cv_lib_resolv_res_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_init" >&5 +$as_echo "$ac_cv_lib_resolv_res_init" >&6; } +if test "x$ac_cv_lib_resolv_res_init" = xyes; then : + LIBRESOLV="-lresolv" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __putlong in -lresolv" >&5 +$as_echo_n "checking for __putlong in -lresolv... " >&6; } +if ${ac_cv_lib_resolv___putlong+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __putlong (); +int +main () +{ +return __putlong (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_resolv___putlong=yes +else + ac_cv_lib_resolv___putlong=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv___putlong" >&5 +$as_echo "$ac_cv_lib_resolv___putlong" >&6; } +if test "x$ac_cv_lib_resolv___putlong" = xyes; then : + LIBRESOLV="-lresolv" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lpthread" >&5 +$as_echo_n "checking for pthread_exit in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_exit+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_exit (); +int +main () +{ +return pthread_exit (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_exit=yes +else + ac_cv_lib_pthread_pthread_exit=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_exit" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_exit" >&6; } +if test "x$ac_cv_lib_pthread_pthread_exit" = xyes; then : + LIBTHREAD="-lpthread" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + LIBRT="-lrt" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lposix4" >&5 +$as_echo_n "checking for clock_gettime in -lposix4... " >&6; } +if ${ac_cv_lib_posix4_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix4 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_posix4_clock_gettime=yes +else + ac_cv_lib_posix4_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_clock_gettime" >&5 +$as_echo "$ac_cv_lib_posix4_clock_gettime" >&6; } +if test "x$ac_cv_lib_posix4_clock_gettime" = xyes; then : + LIBRT="-lposix4" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv_open in -liconv" >&5 +$as_echo_n "checking for iconv_open in -liconv... " >&6; } +if ${ac_cv_lib_iconv_iconv_open+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-liconv $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char iconv_open (); +int +main () +{ +return iconv_open (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_iconv_iconv_open=yes +else + ac_cv_lib_iconv_iconv_open=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iconv_iconv_open" >&5 +$as_echo "$ac_cv_lib_iconv_iconv_open" >&6; } +if test "x$ac_cv_lib_iconv_iconv_open" = xyes; then : + LIBICONV="-liconv" + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libiconv_open in -liconv" >&5 +$as_echo_n "checking for libiconv_open in -liconv... " >&6; } +if ${ac_cv_lib_iconv_libiconv_open+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-liconv $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char libiconv_open (); +int +main () +{ +return libiconv_open (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_iconv_libiconv_open=yes +else + ac_cv_lib_iconv_libiconv_open=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iconv_libiconv_open" >&5 +$as_echo "$ac_cv_lib_iconv_libiconv_open" >&6; } +if test "x$ac_cv_lib_iconv_libiconv_open" = xyes; then : + LIBICONV="-liconv" + +fi + +# TODO: We have --enable-libev but here we add it unconditionally +# making resulting binaries always linked to libev if present. +# Use a proper --with-libev and fail on --enable-libev and -lev +# is missing. Allow --with-libev=builtin? living in ./srclib/ev ? +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ev_sleep in -lev" >&5 +$as_echo_n "checking for ev_sleep in -lev... " >&6; } +if ${ac_cv_lib_ev_ev_sleep+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lev $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ev_sleep (); +int +main () +{ +return ev_sleep (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ev_ev_sleep=yes +else + ac_cv_lib_ev_ev_sleep=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ev_ev_sleep" >&5 +$as_echo "$ac_cv_lib_ev_ev_sleep" >&6; } +if test "x$ac_cv_lib_ev_ev_sleep" = xyes; then : + LIBEV="-lev" + +fi + + +# +# Check for SSL presence and usability + + enable_crypto=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crypt in -lcrypt" >&5 +$as_echo_n "checking for crypt in -lcrypt... " >&6; } +if ${ac_cv_lib_crypt_crypt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char crypt (); +int +main () +{ +return crypt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypt_crypt=yes +else + ac_cv_lib_crypt_crypt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypt_crypt" >&5 +$as_echo "$ac_cv_lib_crypt_crypt" >&6; } +if test "x$ac_cv_lib_crypt_crypt" = xyes; then : + LIBCRYPT="-lcrypt" + +fi + + + +enable_openssl=no + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + openssl_base_dir="$withval" + if test "$withval" != "no"; then + enable_openssl=yes + case "$withval" in + *":"*) + openssl_include="`echo $withval |sed -e 's/:.*$//'`" + openssl_ldflags="`echo $withval |sed -e 's/^.*://'`" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for OpenSSL includes in $openssl_include libs in $openssl_ldflags " >&5 +$as_echo_n "checking checking for OpenSSL includes in $openssl_include libs in $openssl_ldflags ... " >&6; } + ;; + *) + openssl_include="$withval/include" + openssl_ldflags="$withval/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for OpenSSL includes in $withval" >&5 +$as_echo_n "checking checking for OpenSSL includes in $withval... " >&6; } + ;; + esac + fi + fi + +fi + + +if test "x$openssl_base_dir" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenSSL location" >&5 +$as_echo_n "checking for OpenSSL location... " >&6; } + if ${ats_cv_openssl_dir+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for dir in /usr/local/ssl /usr/pkg /usr/sfw /usr/local /usr; do + if test -d $dir && test -f $dir/include/openssl/x509.h; then + ats_cv_openssl_dir=$dir + break + fi + done + +fi + + openssl_base_dir=$ats_cv_openssl_dir + if test "x$openssl_base_dir" = "x"; then + enable_openssl=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + else + enable_openssl=yes + openssl_include="$openssl_base_dir/include" + openssl_ldflags="$openssl_base_dir/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${openssl_base_dir}" >&5 +$as_echo "${openssl_base_dir}" >&6; } + fi +else + if test -d $openssl_include/openssl && test -d $openssl_ldflags && test -f $openssl_include/openssl/x509.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi +fi + +if test "$enable_openssl" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + openssl_have_headers=0 + openssl_have_libs=0 + if test "$openssl_base_dir" != "/usr"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I${openssl_include}\"" + CPPFLAGS="-I${openssl_include}" + else + ats_addto_bugger="-I${openssl_include}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L${openssl_ldflags}\"" + LDFLAGS="-L${openssl_ldflags}" + else + ats_addto_bugger="-L${openssl_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + + if test "x$LIBTOOL_LINK_FLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBTOOL_LINK_FLAGS to \"-R${openssl_ldflags}\"" + LIBTOOL_LINK_FLAGS="-R${openssl_ldflags}" + else + ats_addto_bugger="-R${openssl_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBTOOL_LINK_FLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBTOOL_LINK_FLAGS" + LIBTOOL_LINK_FLAGS="$LIBTOOL_LINK_FLAGS $i" + fi + done + fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BN_init in -lcrypto" >&5 +$as_echo_n "checking for BN_init in -lcrypto... " >&6; } +if ${ac_cv_lib_crypto_BN_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char BN_init (); +int +main () +{ +return BN_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypto_BN_init=yes +else + ac_cv_lib_crypto_BN_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_BN_init" >&5 +$as_echo "$ac_cv_lib_crypto_BN_init" >&6; } +if test "x$ac_cv_lib_crypto_BN_init" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_accept in -lssl" >&5 +$as_echo_n "checking for SSL_accept in -lssl... " >&6; } +if ${ac_cv_lib_ssl_SSL_accept+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lssl -lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char SSL_accept (); +int +main () +{ +return SSL_accept (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ssl_SSL_accept=yes +else + ac_cv_lib_ssl_SSL_accept=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_accept" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_accept" >&6; } +if test "x$ac_cv_lib_ssl_SSL_accept" = xyes; then : + openssl_have_libs=1 +fi + +fi + + if test "$openssl_have_libs" != "0"; then + for ac_header in openssl/x509.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "openssl/x509.h" "ac_cv_header_openssl_x509_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_x509_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_X509_H 1 +_ACEOF + openssl_have_headers=1 +fi + +done + + fi + if test "$openssl_have_headers" != "0"; then + ac_fn_c_check_decl "$LINENO" "EVP_PKEY_CTX_new" "ac_cv_have_decl_EVP_PKEY_CTX_new" "#include +" +if test "x$ac_cv_have_decl_EVP_PKEY_CTX_new" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_EVP_PKEY_CTX_NEW $ac_have_decl +_ACEOF + + enable_crypto=yes + LIBSSL="-lssl -lcrypto" + + else + enable_openssl=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi + + + +if test "x${enable_crypto}" != "xyes"; then + as_fn_error $? "Need at least one SSL library, --with-openssl is supported" "$LINENO" 5 +fi + +# +# Check for zlib presence and usability + +enable_zlib=no + +# Check whether --with-zlib was given. +if test "${with_zlib+set}" = set; then : + withval=$with_zlib; + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + zlib_base_dir="$withval" + if test "$withval" != "no"; then + enable_zlib=yes + case "$withval" in + *":"*) + zlib_include="`echo $withval |sed -e 's/:.*$//'`" + zlib_ldflags="`echo $withval |sed -e 's/^.*://'`" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for zlib includes in $zlib_include libs in $zlib_ldflags " >&5 +$as_echo_n "checking checking for zlib includes in $zlib_include libs in $zlib_ldflags ... " >&6; } + ;; + *) + zlib_include="$withval/include" + zlib_ldflags="$withval/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for zlib includes in $withval" >&5 +$as_echo_n "checking checking for zlib includes in $withval... " >&6; } + ;; + esac + fi + fi + +fi + + +if test "x$zlib_base_dir" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib location" >&5 +$as_echo_n "checking for zlib location... " >&6; } + if ${ats_cv_zlib_dir+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for dir in /usr/local /usr ; do + if test -d $dir && test -f $dir/include/zlib.h; then + ats_cv_zlib_dir=$dir + break + fi + done + +fi + + zlib_base_dir=$ats_cv_zlib_dir + if test "x$zlib_base_dir" = "x"; then + enable_zlib=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + else + enable_zlib=yes + zlib_include="$zlib_base_dir/include" + zlib_ldflags="$zlib_base_dir/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $zlib_base_dir" >&5 +$as_echo "$zlib_base_dir" >&6; } + fi +else + if test -d $zlib_include && test -d $zlib_ldflags && test -f $zlib_include/zlib.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi +fi + +zlibh=0 +if test "$enable_zlib" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + zlib_have_headers=0 + zlib_have_libs=0 + if test "$zlib_base_dir" != "/usr"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I${zlib_include}\"" + CPPFLAGS="-I${zlib_include}" + else + ats_addto_bugger="-I${zlib_include}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L${zlib_ldflags}\"" + LDFLAGS="-L${zlib_ldflags}" + else + ats_addto_bugger="-L${zlib_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + + if test "x$LIBTOOL_LINK_FLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBTOOL_LINK_FLAGS to \"-rpath ${zlib_ldflags}\"" + LIBTOOL_LINK_FLAGS="-rpath ${zlib_ldflags}" + else + ats_addto_bugger="-rpath ${zlib_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBTOOL_LINK_FLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBTOOL_LINK_FLAGS" + LIBTOOL_LINK_FLAGS="$LIBTOOL_LINK_FLAGS $i" + fi + done + fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compressBound in -lz" >&5 +$as_echo_n "checking for compressBound in -lz... " >&6; } +if ${ac_cv_lib_z_compressBound+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lz $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char compressBound (); +int +main () +{ +return compressBound (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_z_compressBound=yes +else + ac_cv_lib_z_compressBound=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compressBound" >&5 +$as_echo "$ac_cv_lib_z_compressBound" >&6; } +if test "x$ac_cv_lib_z_compressBound" = xyes; then : + zlib_have_libs=1 +fi + + if test "$zlib_have_libs" != "0"; then + +for ac_header in zlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ZLIB_H 1 +_ACEOF + zlib_have_headers=1 +fi + +done + +for tsc_i in zlib.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + fi + if test "$zlib_have_headers" != "0"; then + + if test "x$LIBS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBS to \"-lz\"" + LIBS="-lz" + else + ats_addto_bugger="-lz" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBS" + LIBS="$LIBS $i" + fi + done + fi + + else + enable_zlib=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi + + + +# +# Check for lzma presence and usability + +enable_lzma=no + +# Check whether --with-lzma was given. +if test "${with_lzma+set}" = set; then : + withval=$with_lzma; + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + lzma_base_dir="$withval" + if test "$withval" != "no"; then + enable_lzma=yes + case "$withval" in + *":"*) + lzma_include="`echo $withval |sed -e 's/:.*$//'`" + lzma_ldflags="`echo $withval |sed -e 's/^.*://'`" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for lzma includes in $lzma_include libs in $lzma_ldflags " >&5 +$as_echo_n "checking checking for lzma includes in $lzma_include libs in $lzma_ldflags ... " >&6; } + ;; + *) + lzma_include="$withval/include" + lzma_ldflags="$withval/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for lzma includes in $withval" >&5 +$as_echo_n "checking checking for lzma includes in $withval... " >&6; } + ;; + esac + fi + fi + +fi + + +if test "x$lzma_base_dir" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzma location" >&5 +$as_echo_n "checking for lzma location... " >&6; } + if ${ats_cv_lzma_dir+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for dir in /usr/local /usr ; do + if test -d $dir && test -f $dir/include/lzma.h; then + ats_cv_lzma_dir=$dir + break + fi + done + +fi + + lzma_base_dir=$ats_cv_lzma_dir + if test "x$lzma_base_dir" = "x"; then + enable_lzma=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + else + enable_lzma=yes + lzma_include="$lzma_base_dir/include" + lzma_ldflags="$lzma_base_dir/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lzma_base_dir" >&5 +$as_echo "$lzma_base_dir" >&6; } + fi +else + if test -d $lzma_include && test -d $lzma_ldflags && test -f $lzma_include/lzma.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi +fi + +lzmah=0 +if test "$enable_lzma" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + lzma_have_headers=0 + lzma_have_libs=0 + if test "$lzma_base_dir" != "/usr"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I${lzma_include}\"" + CPPFLAGS="-I${lzma_include}" + else + ats_addto_bugger="-I${lzma_include}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L${lzma_ldflags}\"" + LDFLAGS="-L${lzma_ldflags}" + else + ats_addto_bugger="-L${lzma_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + + if test "x$LIBTOOL_LINK_FLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBTOOL_LINK_FLAGS to \"-R${lzma_ldflags}\"" + LIBTOOL_LINK_FLAGS="-R${lzma_ldflags}" + else + ats_addto_bugger="-R${lzma_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBTOOL_LINK_FLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBTOOL_LINK_FLAGS" + LIBTOOL_LINK_FLAGS="$LIBTOOL_LINK_FLAGS $i" + fi + done + fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzma_code in -llzma" >&5 +$as_echo_n "checking for lzma_code in -llzma... " >&6; } +if ${ac_cv_lib_lzma_lzma_code+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-llzma $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char lzma_code (); +int +main () +{ +return lzma_code (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_lzma_lzma_code=yes +else + ac_cv_lib_lzma_lzma_code=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_code" >&5 +$as_echo "$ac_cv_lib_lzma_lzma_code" >&6; } +if test "x$ac_cv_lib_lzma_lzma_code" = xyes; then : + lzma_have_libs=1 +fi + + if test "$lzma_have_libs" != "0"; then + +for ac_header in lzma.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" +if test "x$ac_cv_header_lzma_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LZMA_H 1 +_ACEOF + lzma_have_headers=1 +fi + +done + +for tsc_i in lzma.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + fi + if test "$lzma_have_headers" != "0"; then + + if test "x$LIBS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBS to \"-llzma\"" + LIBS="-llzma" + else + ats_addto_bugger="-llzma" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBS" + LIBS="$LIBS $i" + fi + done + fi + + else + enable_lzma=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi + + + +# +# Tcl macros provided by m4/tcl.m4 +# +# this will error out if tclConfig.sh is not found + + # + # Ok, lets find the tcl configuration + # First, look for one uninstalled. + # the alternative search directory is invoked by --with-tcl + # + + if test x"${no_tcl}" = x ; then + # we reset no_tcl in case something fails here + no_tcl=true + +# Check whether --with-tcl was given. +if test "${with_tcl+set}" = set; then : + withval=$with_tcl; with_tclconfig="${withval}" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5 +$as_echo_n "checking for Tcl configuration... " >&6; } + if ${ac_cv_c_tclconfig+:} false; then : + $as_echo_n "(cached) " >&6 +else + + + # First check to see if --with-tcl was specified. + if test x"${with_tclconfig}" != x ; then + case "${with_tclconfig}" in + */tclConfig.sh ) + if test -f "${with_tclconfig}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&5 +$as_echo "$as_me: WARNING: --with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself" >&2;} + with_tclconfig="`echo "${with_tclconfig}" | sed 's!/tclConfig\.sh$!!'`" + fi ;; + esac + if test -f "${with_tclconfig}/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd "${with_tclconfig}"; pwd)`" + else + as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5 + fi + fi + + # then check for a private Tcl installation + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ../tcl \ + `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \ + ../../tcl \ + `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \ + ../../../tcl \ + `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + + # on Darwin, check in Framework installation locations + if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ + `ls -d /Library/Frameworks 2>/dev/null` \ + `ls -d /Network/Library/Frameworks 2>/dev/null` \ + `ls -d /System/Library/Frameworks 2>/dev/null` \ + ; do + if test -f "$i/Tcl.framework/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" + break + fi + done + fi + + # check in a few common install locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in `ls -d ${libdir} 2>/dev/null` \ + `ls -d ${exec_prefix}/lib 2>/dev/null` \ + `ls -dr ${exec_prefix}/lib/tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ${exec_prefix}/lib/tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ${exec_prefix}/lib/tcl[8-9].[0-9]* 2>/dev/null` \ + `ls -d ${prefix}/lib 2>/dev/null` \ + `ls -dr ${prefix}/lib/tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ${prefix}/lib/tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ${prefix}/lib/tcl[8-9].[0-9]* 2>/dev/null` \ + `ls -d /usr/local/lib 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr /usr/local/lib/tcl[8-9].[0-9]* 2>/dev/null` \ + `ls -d /usr/lib64 2>/dev/null` \ + `ls -dr /usr/lib64/tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr /usr/lib64/tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr /usr/lib64/tcl[8-9].[0-9]* 2>/dev/null` \ + `ls -d /usr/contrib/lib 2>/dev/null` \ + `ls -dr /usr/contrib/lib/tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr /usr/contrib/lib/tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr /usr/contrib/lib/tcl[8-9].[0-9]* 2>/dev/null` \ + `ls -d /usr/lib 2>/dev/null` \ + `ls -dr /usr/lib/tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr /usr/lib/tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr /usr/lib/tcl[8-9].[0-9]* 2>/dev/null` \ + ; do + if test -f "$i/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i; pwd)`" + break + fi + done + fi + + # check in a few other private locations + if test x"${ac_cv_c_tclconfig}" = x ; then + for i in \ + ${srcdir}/../tcl \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \ + `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null` ; do + if test -f "$i/unix/tclConfig.sh" ; then + ac_cv_c_tclconfig="`(cd $i/unix; pwd)`" + break + fi + done + fi + +fi + + + if test x"${ac_cv_c_tclconfig}" = x ; then + TCL_BIN_DIR="# no Tcl configs found" + as_fn_error $? "Can't find Tcl configuration, install the TCL dev package" "$LINENO" 5 + else + no_tcl= + TCL_BIN_DIR="${ac_cv_c_tclconfig}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found ${TCL_BIN_DIR}/tclConfig.sh" >&5 +$as_echo "found ${TCL_BIN_DIR}/tclConfig.sh" >&6; } + fi + fi + + +# if tclConfig.sh loads properly, assume libraries are there and working + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for existence of ${TCL_BIN_DIR}/tclConfig.sh" >&5 +$as_echo_n "checking for existence of ${TCL_BIN_DIR}/tclConfig.sh... " >&6; } + + if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: loading" >&5 +$as_echo "loading" >&6; } + . "${TCL_BIN_DIR}/tclConfig.sh" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: could not find ${TCL_BIN_DIR}/tclConfig.sh" >&5 +$as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; } + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" + eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" + + # If the TCL_BIN_DIR is the build directory (not the install directory), + # then set the common variable name to the value of the build variables. + # For example, the variable TCL_LIB_SPEC will be set to the value + # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC + # instead of TCL_BUILD_LIB_SPEC since it will work with both an + # installed and uninstalled version of Tcl. + if test -f "${TCL_BIN_DIR}/Makefile" ; then + TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}" + TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}" + TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}" + elif test "`uname -s`" = "Darwin"; then + # If Tcl was built as a framework, attempt to use the libraries + # from the framework at the given location so that linking works + # against Tcl.framework installed in an arbitary location. + case ${TCL_DEFS} in + *TCL_FRAMEWORK*) + if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then + for i in "`cd "${TCL_BIN_DIR}"; pwd`" \ + "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do + if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then + TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}" + break + fi + done + fi + if test -f "${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}"; then + TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" + TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" + fi + ;; + esac + fi + + # eval is required to do the TCL_DBGX substitution + eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" + eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" + eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" + eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" + + + + + + + + + + + + + + + +# expect tclConfig.sh to populate TCL_LIB_FLAG and TCL_INCLUDE_SPEC +case $host_os in + darwin*) + TCL_LIB_SPEC="-ltcl" # OSX fails to populate this variable + ;; + *) + ;; +esac +LIBTCL=$TCL_LIB_SPEC + + +case $host_os in + freebsd*|kfreebsd*) + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I/usr/local/include\"" + CPPFLAGS="-I/usr/local/include" + else + ats_addto_bugger="-I/usr/local/include" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + ;; + solaris*) + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I/usr/local/include\"" + CPPFLAGS="-I/usr/local/include" + else + ats_addto_bugger="-I/usr/local/include" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + ;; +esac + +if test "x${TCL_INCLUDE_SPEC}" != "x-I/usr/include"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"$TCL_INCLUDE_SPEC\"" + CPPFLAGS="$TCL_INCLUDE_SPEC" + else + ats_addto_bugger="$TCL_INCLUDE_SPEC" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + +fi + +# +# Check for XML parser +# + + enable_xml=no + + +enable_expat=no + +# Check whether --with-expat was given. +if test "${with_expat+set}" = set; then : + withval=$with_expat; + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + expat_base_dir="$withval" + if test "$withval" != "no"; then + enable_expat=yes + case "$withval" in + *":"*) + expat_include="`echo $withval |sed -e 's/:.*$//'`" + expat_ldflags="`echo $withval |sed -e 's/^.*://'`" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for Expat includes in $expat_include libs in $expat_ldflags " >&5 +$as_echo_n "checking checking for Expat includes in $expat_include libs in $expat_ldflags ... " >&6; } + ;; + *) + expat_include="$withval/include" + expat_ldflags="$withval/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for Expat includes in $withval" >&5 +$as_echo_n "checking checking for Expat includes in $withval... " >&6; } + ;; + esac + fi + fi + +fi + + +if test "x$expat_base_dir" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Expat location" >&5 +$as_echo_n "checking for Expat location... " >&6; } + if ${ats_cv_expat_dir+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for dir in /usr/local /usr; do + if test -d $dir && test -f $dir/include/expat.h; then + ats_cv_expat_dir=$dir + break + fi + done + +fi + + expat_base_dir=$ats_cv_expat_dir + if test "x$expat_base_dir" = "x"; then + enable_expat=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + else + enable_expat=yes + expat_include="$expat_base_dir/include" + expat_ldflags="$expat_base_dir/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${expat_base_dir}" >&5 +$as_echo "${expat_base_dir}" >&6; } + fi +else + if test -d $expat_include && test -d $expat_ldflags && test -f $expat_include/expat.h; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi +fi + +expath=0 +if test "$enable_expat" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + expat_have_headers=0 + expat_have_libs=0 + if test "$expat_base_dir" != "/usr"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I${expat_include}\"" + CPPFLAGS="-I${expat_include}" + else + ats_addto_bugger="-I${expat_include}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L${expat_ldflags}\"" + LDFLAGS="-L${expat_ldflags}" + else + ats_addto_bugger="-L${expat_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + + if test "x$LIBTOOL_LINK_FLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBTOOL_LINK_FLAGS to \"-R${expat_ldflags}\"" + LIBTOOL_LINK_FLAGS="-R${expat_ldflags}" + else + ats_addto_bugger="-R${expat_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBTOOL_LINK_FLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBTOOL_LINK_FLAGS" + LIBTOOL_LINK_FLAGS="$LIBTOOL_LINK_FLAGS $i" + fi + done + fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XML_SetUserData in -lexpat" >&5 +$as_echo_n "checking for XML_SetUserData in -lexpat... " >&6; } +if ${ac_cv_lib_expat_XML_SetUserData+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lexpat $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XML_SetUserData (); +int +main () +{ +return XML_SetUserData (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_expat_XML_SetUserData=yes +else + ac_cv_lib_expat_XML_SetUserData=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_expat_XML_SetUserData" >&5 +$as_echo "$ac_cv_lib_expat_XML_SetUserData" >&6; } +if test "x$ac_cv_lib_expat_XML_SetUserData" = xyes; then : + expat_have_libs=1 +fi + + if test "$expat_have_libs" != "0"; then + +for ac_header in expat.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "expat.h" "ac_cv_header_expat_h" "$ac_includes_default" +if test "x$ac_cv_header_expat_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXPAT_H 1 +_ACEOF + expat_have_headers=1 +fi + +done + +for tsc_i in expat.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + fi + if test "$expat_have_headers" != "0"; then + enable_xml=yes + + LIBEXPAT="-lexpat" + + +$as_echo "#define HAVE_LIBEXPAT 1" >>confdefs.h + + else + enable_expat=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi + + + +if test "x${enable_xml}" != "xyes"; then + as_fn_error $? "Need at least one XML library, --with-expat is supported" "$LINENO" 5 +fi + + +for ac_func in clock_gettime kqueue epoll_ctl posix_memalign posix_fadvise lrand48_r srand48_r port_create +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for tsc_j in clock_gettime kqueue epoll_ctl posix_memalign posix_fadvise lrand48_r srand48_r port_create +do + tsc_3="has_$tsc_j" + if eval "test \"`echo '$ac_cv_func_'$tsc_j`\" = yes"; then + eval "$tsc_3=1" + else + eval "$tsc_3=0" + fi +done + + +for ac_func in strndup strlcpy strlcat +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for tsc_j in strndup strlcpy strlcat +do + tsc_3="has_$tsc_j" + if eval "test \"`echo '$ac_cv_func_'$tsc_j`\" = yes"; then + eval "$tsc_3=1" + else + eval "$tsc_3=0" + fi +done + + + + + + + + + + + +# Check for eventfd() and sys/eventfd.h (both must exist ...) + +for ac_header in sys/eventfd.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/eventfd.h" "ac_cv_header_sys_eventfd_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_eventfd_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_EVENTFD_H 1 +_ACEOF + has_eventfd=1 +else + has_eventfd=0 +fi + +done + +for tsc_i in sys/eventfd.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + +if test "x${has_eventfd}" = "xyes"; then + if test "x$enable_eventfd" = "xyes"; then : + +for ac_func in eventfd +do : + ac_fn_c_check_func "$LINENO" "eventfd" "ac_cv_func_eventfd" +if test "x$ac_cv_func_eventfd" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EVENTFD 1 +_ACEOF + +fi +done + +for tsc_j in eventfd +do + tsc_3="has_$tsc_j" + if eval "test \"`echo '$ac_cv_func_'$tsc_j`\" = yes"; then + eval "$tsc_3=1" + else + eval "$tsc_3=0" + fi +done + + +fi +fi + + +# +# Check for pcre library +# + +enable_pcre=no + +# Check whether --with-pcre was given. +if test "${with_pcre+set}" = set; then : + withval=$with_pcre; + if test "x$withval" != "xyes" && test "x$withval" != "x"; then + pcre_base_dir="$withval" + if test "$withval" != "no"; then + enable_pcre=yes + case "$withval" in + *":"*) + pcre_include="`echo $withval |sed -e 's/:.*$//'`" + pcre_ldflags="`echo $withval |sed -e 's/^.*://'`" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for pcre includes in $pcre_include libs in $pcre_ldflags " >&5 +$as_echo_n "checking checking for pcre includes in $pcre_include libs in $pcre_ldflags ... " >&6; } + ;; + *) + pcre_include="$withval/include" + pcre_ldflags="$withval/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking checking for pcre includes in $withval" >&5 +$as_echo_n "checking checking for pcre includes in $withval... " >&6; } + ;; + esac + fi + fi + +fi + + +if test "x$pcre_base_dir" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre location" >&5 +$as_echo_n "checking for pcre location... " >&6; } + if ${ats_cv_pcre_dir+:} false; then : + $as_echo_n "(cached) " >&6 +else + + for dir in /usr/local /usr ; do + if test -d $dir && ( test -f $dir/include/pcre.h || test -f $dir/include/pcre/pcre.h ); then + ats_cv_pcre_dir=$dir + break + fi + done + +fi + + pcre_base_dir=$ats_cv_pcre_dir + if test "x$pcre_base_dir" = "x"; then + enable_pcre=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + else + enable_pcre=yes + pcre_include="$pcre_base_dir/include" + pcre_ldflags="$pcre_base_dir/lib" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pcre_base_dir" >&5 +$as_echo "$pcre_base_dir" >&6; } + fi +else + if test -d $pcre_include && test -d $pcre_ldflags && ( test -f $pcre_include/pcre.h || test -f $pcre_include/pcre/pcre.h ); then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + fi +fi + +pcreh=0 +pcre_pcreh=0 +if test "$enable_pcre" != "no"; then + saved_ldflags=$LDFLAGS + saved_cppflags=$CPPFLAGS + pcre_have_headers=0 + pcre_have_libs=0 + if test "$pcre_base_dir" != "/usr"; then + + if test "x$CPPFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting CPPFLAGS to \"-I${pcre_include}\"" + CPPFLAGS="-I${pcre_include}" + else + ats_addto_bugger="-I${pcre_include}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $CPPFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to CPPFLAGS" + CPPFLAGS="$CPPFLAGS $i" + fi + done + fi + + + if test "x$LDFLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LDFLAGS to \"-L${pcre_ldflags}\"" + LDFLAGS="-L${pcre_ldflags}" + else + ats_addto_bugger="-L${pcre_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LDFLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LDFLAGS" + LDFLAGS="$LDFLAGS $i" + fi + done + fi + + + if test "x$LIBTOOL_LINK_FLAGS" = "x"; then + test "x$verbose" = "xyes" && echo " setting LIBTOOL_LINK_FLAGS to \"-R${pcre_ldflags}\"" + LIBTOOL_LINK_FLAGS="-R${pcre_ldflags}" + else + ats_addto_bugger="-R${pcre_ldflags}" + for i in $ats_addto_bugger; do + ats_addto_duplicate="0" + for j in $LIBTOOL_LINK_FLAGS; do + if test "x$i" = "x$j"; then + ats_addto_duplicate="1" + break + fi + done + if test $ats_addto_duplicate = "0"; then + test "x$verbose" = "xyes" && echo " adding \"$i\" to LIBTOOL_LINK_FLAGS" + LIBTOOL_LINK_FLAGS="$LIBTOOL_LINK_FLAGS $i" + fi + done + fi + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_exec in -lpcre" >&5 +$as_echo_n "checking for pcre_exec in -lpcre... " >&6; } +if ${ac_cv_lib_pcre_pcre_exec+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpcre $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pcre_exec (); +int +main () +{ +return pcre_exec (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pcre_pcre_exec=yes +else + ac_cv_lib_pcre_pcre_exec=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_exec" >&5 +$as_echo "$ac_cv_lib_pcre_pcre_exec" >&6; } +if test "x$ac_cv_lib_pcre_pcre_exec" = xyes; then : + pcre_have_libs=1 +fi + + if test "$pcre_have_libs" != "0"; then + +for ac_header in pcre.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default" +if test "x$ac_cv_header_pcre_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PCRE_H 1 +_ACEOF + pcre_have_headers=1 +fi + +done + +for tsc_i in pcre.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + +for ac_header in pcre/pcre.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "pcre/pcre.h" "ac_cv_header_pcre_pcre_h" "$ac_includes_default" +if test "x$ac_cv_header_pcre_pcre_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PCRE_PCRE_H 1 +_ACEOF + pcre_have_headers=1 +fi + +done + +for tsc_i in pcre/pcre.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + fi + if test "$pcre_have_headers" != "0"; then + +$as_echo "#define HAVE_LIBPCRE 1" >>confdefs.h + + LIBPCRE=-lpcre + + else + enable_pcre=no + CPPFLAGS=$saved_cppflags + LDFLAGS=$saved_ldflags + fi +fi + + + +if test "x${enable_pcre}" != "xyes"; then + as_fn_error $? "Cannot find pcre library. Configure --with-pcre=DIR" "$LINENO" 5 +fi + +has_backtrace=0 +# Check for backtrace() support + +for ac_header in execinfo.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default" +if test "x$ac_cv_header_execinfo_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_EXECINFO_H 1 +_ACEOF + has_backtrace=1 +fi + +done + +for tsc_i in execinfo.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + +if test "${has_backtrace}" = "1"; then + # FreeBSD requires '/usr/ports/devel/libexecinfo' for gdb style backtrace() support + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for backtrace in -lexecinfo" >&5 +$as_echo_n "checking for backtrace in -lexecinfo... " >&6; } +if ${ac_cv_lib_execinfo_backtrace+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lexecinfo $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char backtrace (); +int +main () +{ +return backtrace (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_execinfo_backtrace=yes +else + ac_cv_lib_execinfo_backtrace=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_execinfo_backtrace" >&5 +$as_echo "$ac_cv_lib_execinfo_backtrace" >&6; } +if test "x$ac_cv_lib_execinfo_backtrace" = xyes; then : + have_backtrace_lib=yes + LIBEXECINFO="-lexecinfo" + +fi + + if test "x${have_backtrace_lib}" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Using backtrace library '-lexecinfo'" >&5 +$as_echo "$as_me: Using backtrace library '-lexecinfo'" >&6;} + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: No backtrace() support found" >&5 +$as_echo "$as_me: WARNING: No backtrace() support found" >&2;} +fi + + + +use_libev=0 +use_epoll=0 +use_kqueue=0 +use_port=0 +if test "x$enable_libev" = "xyes"; then + use_libev=1 + have_good_poller=1 +elif test "$ac_cv_func_epoll_ctl" = "yes"; then + use_epoll=1 + have_good_poller=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: Using epoll event interface" >&5 +$as_echo "$as_me: Using epoll event interface" >&6;} +elif test "$ac_cv_func_kqueue" = "yes"; then + use_kqueue=1 + have_good_poller=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: Using kqueue event interface" >&5 +$as_echo "$as_me: Using kqueue event interface" >&6;} +elif test "$ac_cv_func_port_create" = "yes"; then + use_port=1 + have_good_poller=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: Using port event interface" >&5 +$as_echo "$as_me: Using port event interface" >&6;} +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "No suitable polling interface found +See \`config.log' for more details" "$LINENO" 5; } +fi + + + + + +has_profiler=0 +if test "x${with_profiler}" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ProfilerStart in -lprofiler" >&5 +$as_echo_n "checking for ProfilerStart in -lprofiler... " >&6; } +if ${ac_cv_lib_profiler_ProfilerStart+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lprofiler $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ProfilerStart (); +int +main () +{ +return ProfilerStart (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_profiler_ProfilerStart=yes +else + ac_cv_lib_profiler_ProfilerStart=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_profiler_ProfilerStart" >&5 +$as_echo "$ac_cv_lib_profiler_ProfilerStart" >&6; } +if test "x$ac_cv_lib_profiler_ProfilerStart" = xyes; then : + LIBPROFILER="-lprofiler" + + has_profiler=1 + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "check for profiler failed. Have you installed google-perftools-devel? +See \`config.log' for more details" "$LINENO" 5; } +fi + +fi + + +has_demangle=0 +# For SunPro 5.2 - we need the demangle symbol for +# ink_stack_trace.cc in lib/ts. Because this +# library is part of the SunPro distribution, we need +# check with the C++ compiler since we might be using +# SunPro CC for the C++ compiler and gcc for the C compiler +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cplus_demangle in -ldemangle" >&5 +$as_echo_n "checking for cplus_demangle in -ldemangle... " >&6; } +if ${ac_cv_lib_demangle_cplus_demangle+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldemangle $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char cplus_demangle (); +int +main () +{ +return cplus_demangle (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + ac_cv_lib_demangle_cplus_demangle=yes +else + ac_cv_lib_demangle_cplus_demangle=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_demangle_cplus_demangle" >&5 +$as_echo "$ac_cv_lib_demangle_cplus_demangle" >&6; } +if test "x$ac_cv_lib_demangle_cplus_demangle" = xyes; then : + LIBDEMANGLE="-ldemangle" + has_demangle=1 + + +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +need_union_semun=0 +# It's stupid, but not all platforms have union semun, even those that need it. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for union semun in sys/sem.h" >&5 +$as_echo_n "checking for union semun in sys/sem.h... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include + +int +main () +{ + +union semun arg; +semctl(0, 0, 0, arg); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + union_semun=yes +msg=yes +else + +need_union_semun="1" +msg=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $msg" >&5 +$as_echo "$msg" >&6; } + + + +# Check for POSIX capabilities library. +# If we don't find it, disable checking for header. +use_posix_cap=0 +if test "x$enable_posix_cap" = "xyes"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cap_set_proc in -lcap" >&5 +$as_echo_n "checking for cap_set_proc in -lcap... " >&6; } +if ${ac_cv_lib_cap_cap_set_proc+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcap $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char cap_set_proc (); +int +main () +{ +return cap_set_proc (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_cap_cap_set_proc=yes +else + ac_cv_lib_cap_cap_set_proc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cap_cap_set_proc" >&5 +$as_echo "$ac_cv_lib_cap_cap_set_proc" >&6; } +if test "x$ac_cv_lib_cap_cap_set_proc" = xyes; then : + LIBCAP="-lcap" + + use_posix_cap=1 + +else + enable_posix_cap=no + +fi + + +fi + +# ----------------------------------------------------------------------------- +# 5. CHECK FOR HEADER FILES + + +for ac_header in sys/epoll.h \ + sys/event.h \ + machine/endian.h \ + endian.h \ + sys/sysinfo.h \ + sys/sysctl.h \ + sys/systeminfo.h \ + netinet/in.h \ + netinet/in_systm.h \ + netinet/tcp.h \ + sys/ioctl.h \ + sys/byteorder.h \ + sys/sockio.h \ + sys/prctl.h \ + arpa/inet.h \ + arpa/nameser.h \ + arpa/nameser_compat.h \ + execinfo.h \ + netdb.h \ + ctype.h \ + siginfo.h \ + malloc.h \ + wait.h \ + float.h \ + libgen.h \ + values.h \ + alloca.h \ + cpio.h \ + stropts.h \ + sys/mount.h \ + sys/param.h \ + sys/sysmacros.h \ + math.h \ + stdint.h \ + net/ppp_defs.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for tsc_i in sys/epoll.h \ + sys/event.h \ + machine/endian.h \ + endian.h \ + sys/sysinfo.h \ + sys/sysctl.h \ + sys/systeminfo.h \ + netinet/in.h \ + netinet/in_systm.h \ + netinet/tcp.h \ + sys/ioctl.h \ + sys/byteorder.h \ + sys/sockio.h \ + sys/prctl.h \ + arpa/inet.h \ + arpa/nameser.h \ + arpa/nameser_compat.h \ + execinfo.h \ + netdb.h \ + ctype.h \ + siginfo.h \ + malloc.h \ + wait.h \ + float.h \ + libgen.h \ + values.h \ + alloca.h \ + cpio.h \ + stropts.h \ + sys/mount.h \ + sys/param.h \ + sys/sysmacros.h \ + math.h \ + stdint.h \ + net/ppp_defs.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in netinet/ip.h +do : + ac_fn_c_check_header_compile "$LINENO" "netinet/ip.h" "ac_cv_header_netinet_ip_h" "#ifdef HAVE_SYS_TYPES_H + #include + #endif + #ifdef HAVE_NETINET_IN_H + #include + #endif + +" +if test "x$ac_cv_header_netinet_ip_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETINET_IP_H 1 +_ACEOF + +fi + +done + +for tsc_i in netinet/ip.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + + +for ac_header in netinet/ip_icmp.h +do : + ac_fn_c_check_header_compile "$LINENO" "netinet/ip_icmp.h" "ac_cv_header_netinet_ip_icmp_h" "#ifdef HAVE_SYS_TYPES_H + #include + #endif + #ifdef HAVE_NETINET_IN_H + #include + #endif + #ifdef HAVE_NETINET_IP_H + #include + #endif + #ifdef HAVE_NETINET_IN_SYSTM_H + #include + #endif + +" +if test "x$ac_cv_header_netinet_ip_icmp_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETINET_IP_ICMP_H 1 +_ACEOF + +fi + +done + +for tsc_i in netinet/ip_icmp.h +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + + + + + +if test "x${with_profiler}" = "xyes"; then + +for ac_header in google/profiler.h \ + +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for tsc_i in google/profiler.h \ + +do + ac_safe=`echo "$tsc_i" | sed 'y%./+-%__p_%'` + tsc_2=`echo "$tsc_i" | sed -e 's%/%_%g' -e 's/\.//g' -e 's/-//g'` + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + eval "$tsc_2=1" + else + eval "$tsc_2=0" + fi +done + +fi + +if test "x${enable_posix_cap}" = "xyes"; then + for ac_header in sys/capability.h +do : + ac_fn_c_check_header_compile "$LINENO" "sys/capability.h" "ac_cv_header_sys_capability_h" " + +" +if test "x$ac_cv_header_sys_capability_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_CAPABILITY_H 1 +_ACEOF + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "POSIX capabilities header not found. Try --disable-posix-cap +See \`config.log' for more details" "$LINENO" 5; } +fi + +done + +fi + +# +# Configure sockopt value for TPROXY. Look at the enable flag. +# Value 'no' means user forced disable, don't check anything else. +# 'auto' means user didn't say, so silently enable/disable +# based on success. +# A numeric value means enable, don't check, use that value. +# Anything else means user forced, fail if value not found +# in header file. +# We can't just include linux/in.h because it's incompatible with +# netinet/in.h. +# Verify the file exists (is readable), scan for the value we need, +# if found export the value and enable use of the value. +# +ip_transparent=0 +use_tproxy=0 +tproxy_header=/usr/include/linux/in.h +tproxy_usage_enable=" + --enable-tproxy Enable the feature and validate." +tproxy_usage_default=" + --enable-tproxy=force Enable using default sockopt value, no validation." +tproxy_usage_numeric=" + --enable-tproxy=X where X is numeric + Enable, use X for sockopt value, no validation." +tproxy_usage_disable=" + --disable-tproxy Disable feature, no validation." +proxy_usage="$tproxy_usage_enable$tproxy_usage_default$tproxy_usage_numeric$tproxy_usage_disable" + +if test "x$enable_tproxy" != "xno"; then : + + if test "x${enable_posix_cap}" != "xyes"; then : + + if test "x$enable_tproxy" = xauto; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "TPROXY feature requires POSIX capabilities. +See \`config.log' for more details" "$LINENO" 5; } + +fi + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TPROXY sockopt IP_TRANSPARENT" >&5 +$as_echo_n "checking for TPROXY sockopt IP_TRANSPARENT... " >&6; } + case "$enable_tproxy" in + [0-9][0-9]*) + ip_transparent=$enable_tproxy + use_tproxy=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: forced to $ip_transparent" >&5 +$as_echo "forced to $ip_transparent" >&6; } + ;; + force) + ip_transparent=19 + use_tproxy=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: forced to $ip_transparent" >&5 +$as_echo "forced to $ip_transparent" >&6; } + ;; + yes|auto) + if test -r $tproxy_header; then : + + ip_transparent=`$AWK "/^#define[ \t]+IP_TRANSPARENT[ \t]+[0-9]+/{print \\$3}" $tproxy_header` + if test "x$ip_transparent" != "x"; then : + + use_tproxy=1 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: set to $ip_transparent" >&5 +$as_echo "set to $ip_transparent" >&6; } + +else + + ip_transparent=0 + if test "x$enable_tproxy" = xauto; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "tproxy feature enabled but the sockopt value was not found in $tproxy_header. Try one of$tproxy_usage_default$tproxy_usage_numeric$tproxy_usage_disable +See \`config.log' for more details" "$LINENO" 5; } + +fi + +fi + +else + + if test "x$enable_tproxy" = xauto; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "tproxy feature enabled but the header file $tproxy_header was not readable. Try one of$tproxy_usage_default$tproxy_usage_numeric$tproxy_usage_disable +See \`config.log' for more details" "$LINENO" 5; } + +fi + +fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Invalid argument to feature tproxy.$tproxy_usage +See \`config.log' for more details" "$LINENO" 5; } + ;; + esac + +fi + +fi + + + + + +default_loopback_iface="" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for loopback network interface" >&5 +$as_echo_n "checking for loopback network interface... " >&6; } +case $host_os in + linux*) + default_loopback_iface=lo + ;; +darwin* | freebsd* | solaris*) + default_loopback_iface=lo0 + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $default_loopback_iface" >&5 +$as_echo "$default_loopback_iface" >&6; } + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking style of gethostbyname_r routine" >&5 +$as_echo_n "checking style of gethostbyname_r routine... " >&6; } +if ${ac_cv_gethostbyname_r_style+:} false; then : + $as_echo_n "(cached) " >&6 +else + ats_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $CFLAGS_WARN" + if test "$ac_cv_c_compiler_gnu" = "yes"; then + CFLAGS="$CFLAGS -Werror" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include "confdefs.h" + + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + + int main(int argc, const char *const *argv) { + +int tmp = gethostbyname_r((const char *) 0, (struct hostent *) 0, + (char *) 0, 0, (struct hostent **) 0, &tmp); +/* use tmp to suppress the warning */ +tmp=0; + + return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_gethostbyname_r_style=glibc2 +else + ac_cv_gethostbyname_r_style=none +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ats_save_CFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gethostbyname_r_style" >&5 +$as_echo "$ac_cv_gethostbyname_r_style" >&6; } + +if test "$ac_cv_gethostbyname_r_style" = "glibc2"; then + gethostbyname_r_glibc2=1 + +$as_echo "#define GETHOSTBYNAME_R_GLIBC2 1" >>confdefs.h + +else + gethostbyname_r_glibc2=0 +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking 3rd argument to the gethostbyname_r routines" >&5 +$as_echo_n "checking 3rd argument to the gethostbyname_r routines... " >&6; } +if ${ac_cv_gethostbyname_r_arg+:} false; then : + $as_echo_n "(cached) " >&6 +else + ats_save_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS $CFLAGS_WARN" + if test "$ac_cv_c_compiler_gnu" = "yes"; then + CFLAGS="$CFLAGS -Werror" + fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include "confdefs.h" + + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + + int main(int argc, const char *const *argv) { + +int tmp = gethostbyname_r((const char *) 0, (struct hostent *) 0, + (struct hostent_data *) 0); +/* use tmp to suppress the warning */ +tmp=0; + + return 0; } +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_gethostbyname_r_arg=hostent_data +else + ac_cv_gethostbyname_r_arg=char +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS=$ats_save_CFLAGS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_gethostbyname_r_arg" >&5 +$as_echo "$ac_cv_gethostbyname_r_arg" >&6; } + +if test "$ac_cv_gethostbyname_r_arg" = "hostent_data"; then + gethostbyname_r_hostent_data=1 + +$as_echo "#define GETHOSTBYNAME_R_HOSTENT_DATA 1" >>confdefs.h + +else + gethostbyname_r_hostent_data=0 +fi + + + + +# +# use modular IOCORE +# +iocore_include_dirs="-I\$(top_srcdir)/iocore/eventsystem \ +-I\$(top_srcdir)/iocore/net \ +-I\$(top_srcdir)/iocore/aio \ +-I\$(top_srcdir)/iocore/hostdb \ +-I\$(top_srcdir)/iocore/cache \ +-I\$(top_srcdir)/iocore/cluster \ +-I\$(top_srcdir)/iocore/utils \ +-I\$(top_srcdir)/iocore/dns" + +if test "x$enable_libev" = "xyes"; then + iocore_include_dirs="${iocore_include_dirs} -I\$(top_srcdir)/libev" +fi + +# Testing Framework suffix generation hack +TFW_PACKAGE_SUFFIX=$os_type + +MGMT_DEFS="$MGMT_DEFS -DMGMT_USE_SYSLOG" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using CC=$CC" >&5 +$as_echo "$as_me: Build using CC=$CC" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using CXX=$CXX" >&5 +$as_echo "$as_me: Build using CXX=$CXX" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using CPP=$CPP" >&5 +$as_echo "$as_me: Build using CPP=$CPP" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using CFLAGS=$CFLAGS" >&5 +$as_echo "$as_me: Build using CFLAGS=$CFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using SHARED_CFLAGS=$SHARED_CFLAGS" >&5 +$as_echo "$as_me: Build using SHARED_CFLAGS=$SHARED_CFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using CXXFLAGS=$CXXFLAGS" >&5 +$as_echo "$as_me: Build using CXXFLAGS=$CXXFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using SHARED_CXXFLAGS=$SHARED_CXXFLAGS" >&5 +$as_echo "$as_me: Build using SHARED_CXXFLAGS=$SHARED_CXXFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using SHARED_CXXLINKFLAGS=$SHARED_LINKCXXFLAGS" >&5 +$as_echo "$as_me: Build using SHARED_CXXLINKFLAGS=$SHARED_LINKCXXFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using CPPFLAGS=$CPPFLAGS" >&5 +$as_echo "$as_me: Build using CPPFLAGS=$CPPFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using LDFLAGS=$LDFLAGS" >&5 +$as_echo "$as_me: Build using LDFLAGS=$LDFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using SHARED_LDFLAGS=$SHARED_LDFLAGS" >&5 +$as_echo "$as_me: Build using SHARED_LDFLAGS=$SHARED_LDFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using EXTRA_CC_LDFLAGS=$EXTRA_CC_LDFLAGS" >&5 +$as_echo "$as_me: Build using EXTRA_CC_LDFLAGS=$EXTRA_CC_LDFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using EXTRA_CXX_LDFLAGS=$EXTRA_CXX_LDFLAGS" >&5 +$as_echo "$as_me: Build using EXTRA_CXX_LDFLAGS=$EXTRA_CXX_LDFLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using LIBTOOL_LINK_FLAGS=$LIBTOOL_LINK_FLAGS" >&5 +$as_echo "$as_me: Build using LIBTOOL_LINK_FLAGS=$LIBTOOL_LINK_FLAGS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using MGMT_DEFS=$MGMT_DEFS" >&5 +$as_echo "$as_me: Build using MGMT_DEFS=$MGMT_DEFS" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Build using API_DEFS=$API_DEFS" >&5 +$as_echo "$as_me: Build using API_DEFS=$API_DEFS" >&6;} + + + + + + + + + + + + + + + + + + + +# ----------------------------------------------------------------------------- +# 6. OUTPUT FILES + +ac_config_files="$ac_config_files lib/ts/ink_config.h proxy/api/ts/ts.h" + +ac_config_files="$ac_config_files tools/tsxs" + +ac_config_files="$ac_config_files doc/Doxyfile" + +ac_config_files="$ac_config_files doc/Makefile" + +ac_config_files="$ac_config_files rc/Makefile" + +ac_config_files="$ac_config_files rc/trafficserver" + +ac_config_files="$ac_config_files rc/trafficserver.xml" + +ac_config_files="$ac_config_files rc/trafficserver.conf" + +ac_config_files="$ac_config_files iocore/aio/Makefile" + +ac_config_files="$ac_config_files iocore/cache/Makefile" + +ac_config_files="$ac_config_files iocore/cluster/Makefile" + +ac_config_files="$ac_config_files iocore/dns/Makefile" + +ac_config_files="$ac_config_files iocore/eventsystem/Makefile" + +ac_config_files="$ac_config_files iocore/hostdb/Makefile" + +ac_config_files="$ac_config_files iocore/Makefile" + +ac_config_files="$ac_config_files iocore/net/Makefile" + +ac_config_files="$ac_config_files iocore/utils/Makefile" + +ac_config_files="$ac_config_files lib/Makefile" + +ac_config_files="$ac_config_files lib/ts/Makefile" + +ac_config_files="$ac_config_files lib/records/Makefile" + +ac_config_files="$ac_config_files lib/tsconfig/Makefile" + +ac_config_files="$ac_config_files Makefile" + +ac_config_files="$ac_config_files proxy/config/body_factory/default/Makefile" + +ac_config_files="$ac_config_files proxy/config/body_factory/Makefile" + +ac_config_files="$ac_config_files proxy/config/records.config.default proxy/config/storage.config.default" + +ac_config_files="$ac_config_files proxy/config/Makefile" + +ac_config_files="$ac_config_files proxy/congest/Makefile" + +ac_config_files="$ac_config_files proxy/hdrs/Makefile" + +ac_config_files="$ac_config_files proxy/http/Makefile" + +ac_config_files="$ac_config_files proxy/http/remap/Makefile" + +ac_config_files="$ac_config_files proxy/logging/Makefile" + +ac_config_files="$ac_config_files proxy/Makefile" + +ac_config_files="$ac_config_files mgmt/api/Makefile" + +ac_config_files="$ac_config_files mgmt/api/remote/Makefile" + +ac_config_files="$ac_config_files mgmt/api/include/Makefile" + +ac_config_files="$ac_config_files mgmt/cli/Makefile" + +ac_config_files="$ac_config_files mgmt/cluster/Makefile" + +ac_config_files="$ac_config_files mgmt/Makefile" + +ac_config_files="$ac_config_files mgmt/preparse/Makefile" + +ac_config_files="$ac_config_files mgmt/stats/Makefile" + +ac_config_files="$ac_config_files mgmt/tools/Makefile" + +ac_config_files="$ac_config_files mgmt/utils/Makefile" + +ac_config_files="$ac_config_files mgmt/web2/Makefile" + +ac_config_files="$ac_config_files proxy/stats/Makefile" + +ac_config_files="$ac_config_files lib/wccp/Makefile" + +ac_config_files="$ac_config_files proxy/api/ts/Makefile" + +# Traffic Cop +ac_config_files="$ac_config_files cop/Makefile" + +# production plugins +ac_config_files="$ac_config_files plugins/Makefile" + +ac_config_files="$ac_config_files plugins/conf_remap/Makefile" + +# various tools +ac_config_files="$ac_config_files tools/Makefile" + +# example plugins +ac_config_files="$ac_config_files example/Makefile" + +ac_config_files="$ac_config_files example/add-header/Makefile" + +ac_config_files="$ac_config_files example/append-transform/Makefile" + +ac_config_files="$ac_config_files example/basic-auth/Makefile" + +ac_config_files="$ac_config_files example/blacklist-0/Makefile" + +ac_config_files="$ac_config_files example/blacklist-1/Makefile" + +ac_config_files="$ac_config_files example/bnull-transform/Makefile" + +ac_config_files="$ac_config_files example/cache_scan/Makefile" + +ac_config_files="$ac_config_files example/file-1/Makefile" + +ac_config_files="$ac_config_files example/gzip-transform/Makefile" + +ac_config_files="$ac_config_files example/hello/Makefile" + +ac_config_files="$ac_config_files example/null-transform/Makefile" + +ac_config_files="$ac_config_files example/output-header/Makefile" + +ac_config_files="$ac_config_files example/prefetch/Makefile" + +ac_config_files="$ac_config_files example/protocol/Makefile" + +ac_config_files="$ac_config_files example/redirect-1/Makefile" + +ac_config_files="$ac_config_files example/query_remap/Makefile" + +ac_config_files="$ac_config_files example/remap/Makefile" + +ac_config_files="$ac_config_files example/replace-header/Makefile" + +ac_config_files="$ac_config_files example/response-header-1/Makefile" + +ac_config_files="$ac_config_files example/server-transform/Makefile" + +ac_config_files="$ac_config_files example/session-1/Makefile" + +ac_config_files="$ac_config_files example/thread-1/Makefile" + +ac_config_files="$ac_config_files example/thread-pool/Makefile" + +# example app w/ standalone iocore +ac_config_files="$ac_config_files example/app-template/Makefile example/app-template/records.config" + + +# ----------------------------------------------------------------------------- +# 7. autoheader TEMPLATES + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${BUILD_TESTS_TRUE}" && test -z "${BUILD_TESTS_FALSE}"; then + as_fn_error $? "conditional \"BUILD_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${STANDALONE_IOCORE_TRUE}" && test -z "${STANDALONE_IOCORE_FALSE}"; then + as_fn_error $? "conditional \"STANDALONE_IOCORE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${STATIC_LIBTS_TRUE}" && test -z "${STATIC_LIBTS_FALSE}"; then + as_fn_error $? "conditional \"STATIC_LIBTS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${BUILD_WCCP_TRUE}" && test -z "${BUILD_WCCP_FALSE}"; then + as_fn_error $? "conditional \"BUILD_WCCP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCCAS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by Apache Traffic Server $as_me 3.0.5, which was +generated by GNU Autoconf 2.68. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to . +Apache Traffic Server home page: ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +Apache Traffic Server config.status 3.0.5 +configured by $0, generated by GNU Autoconf 2.68, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "lib/ts/ink_autoconf.h") CONFIG_HEADERS="$CONFIG_HEADERS lib/ts/ink_autoconf.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "lib/ts/ink_config.h") CONFIG_FILES="$CONFIG_FILES lib/ts/ink_config.h" ;; + "proxy/api/ts/ts.h") CONFIG_FILES="$CONFIG_FILES proxy/api/ts/ts.h" ;; + "tools/tsxs") CONFIG_FILES="$CONFIG_FILES tools/tsxs" ;; + "doc/Doxyfile") CONFIG_FILES="$CONFIG_FILES doc/Doxyfile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "rc/Makefile") CONFIG_FILES="$CONFIG_FILES rc/Makefile" ;; + "rc/trafficserver") CONFIG_FILES="$CONFIG_FILES rc/trafficserver" ;; + "rc/trafficserver.xml") CONFIG_FILES="$CONFIG_FILES rc/trafficserver.xml" ;; + "rc/trafficserver.conf") CONFIG_FILES="$CONFIG_FILES rc/trafficserver.conf" ;; + "iocore/aio/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/aio/Makefile" ;; + "iocore/cache/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/cache/Makefile" ;; + "iocore/cluster/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/cluster/Makefile" ;; + "iocore/dns/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/dns/Makefile" ;; + "iocore/eventsystem/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/eventsystem/Makefile" ;; + "iocore/hostdb/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/hostdb/Makefile" ;; + "iocore/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/Makefile" ;; + "iocore/net/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/net/Makefile" ;; + "iocore/utils/Makefile") CONFIG_FILES="$CONFIG_FILES iocore/utils/Makefile" ;; + "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; + "lib/ts/Makefile") CONFIG_FILES="$CONFIG_FILES lib/ts/Makefile" ;; + "lib/records/Makefile") CONFIG_FILES="$CONFIG_FILES lib/records/Makefile" ;; + "lib/tsconfig/Makefile") CONFIG_FILES="$CONFIG_FILES lib/tsconfig/Makefile" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "proxy/config/body_factory/default/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/config/body_factory/default/Makefile" ;; + "proxy/config/body_factory/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/config/body_factory/Makefile" ;; + "proxy/config/records.config.default") CONFIG_FILES="$CONFIG_FILES proxy/config/records.config.default" ;; + "proxy/config/storage.config.default") CONFIG_FILES="$CONFIG_FILES proxy/config/storage.config.default" ;; + "proxy/config/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/config/Makefile" ;; + "proxy/congest/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/congest/Makefile" ;; + "proxy/hdrs/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/hdrs/Makefile" ;; + "proxy/http/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/http/Makefile" ;; + "proxy/http/remap/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/http/remap/Makefile" ;; + "proxy/logging/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/logging/Makefile" ;; + "proxy/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/Makefile" ;; + "mgmt/api/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/api/Makefile" ;; + "mgmt/api/remote/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/api/remote/Makefile" ;; + "mgmt/api/include/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/api/include/Makefile" ;; + "mgmt/cli/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/cli/Makefile" ;; + "mgmt/cluster/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/cluster/Makefile" ;; + "mgmt/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/Makefile" ;; + "mgmt/preparse/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/preparse/Makefile" ;; + "mgmt/stats/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/stats/Makefile" ;; + "mgmt/tools/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/tools/Makefile" ;; + "mgmt/utils/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/utils/Makefile" ;; + "mgmt/web2/Makefile") CONFIG_FILES="$CONFIG_FILES mgmt/web2/Makefile" ;; + "proxy/stats/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/stats/Makefile" ;; + "lib/wccp/Makefile") CONFIG_FILES="$CONFIG_FILES lib/wccp/Makefile" ;; + "proxy/api/ts/Makefile") CONFIG_FILES="$CONFIG_FILES proxy/api/ts/Makefile" ;; + "cop/Makefile") CONFIG_FILES="$CONFIG_FILES cop/Makefile" ;; + "plugins/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/Makefile" ;; + "plugins/conf_remap/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/conf_remap/Makefile" ;; + "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; + "example/Makefile") CONFIG_FILES="$CONFIG_FILES example/Makefile" ;; + "example/add-header/Makefile") CONFIG_FILES="$CONFIG_FILES example/add-header/Makefile" ;; + "example/append-transform/Makefile") CONFIG_FILES="$CONFIG_FILES example/append-transform/Makefile" ;; + "example/basic-auth/Makefile") CONFIG_FILES="$CONFIG_FILES example/basic-auth/Makefile" ;; + "example/blacklist-0/Makefile") CONFIG_FILES="$CONFIG_FILES example/blacklist-0/Makefile" ;; + "example/blacklist-1/Makefile") CONFIG_FILES="$CONFIG_FILES example/blacklist-1/Makefile" ;; + "example/bnull-transform/Makefile") CONFIG_FILES="$CONFIG_FILES example/bnull-transform/Makefile" ;; + "example/cache_scan/Makefile") CONFIG_FILES="$CONFIG_FILES example/cache_scan/Makefile" ;; + "example/file-1/Makefile") CONFIG_FILES="$CONFIG_FILES example/file-1/Makefile" ;; + "example/gzip-transform/Makefile") CONFIG_FILES="$CONFIG_FILES example/gzip-transform/Makefile" ;; + "example/hello/Makefile") CONFIG_FILES="$CONFIG_FILES example/hello/Makefile" ;; + "example/null-transform/Makefile") CONFIG_FILES="$CONFIG_FILES example/null-transform/Makefile" ;; + "example/output-header/Makefile") CONFIG_FILES="$CONFIG_FILES example/output-header/Makefile" ;; + "example/prefetch/Makefile") CONFIG_FILES="$CONFIG_FILES example/prefetch/Makefile" ;; + "example/protocol/Makefile") CONFIG_FILES="$CONFIG_FILES example/protocol/Makefile" ;; + "example/redirect-1/Makefile") CONFIG_FILES="$CONFIG_FILES example/redirect-1/Makefile" ;; + "example/query_remap/Makefile") CONFIG_FILES="$CONFIG_FILES example/query_remap/Makefile" ;; + "example/remap/Makefile") CONFIG_FILES="$CONFIG_FILES example/remap/Makefile" ;; + "example/replace-header/Makefile") CONFIG_FILES="$CONFIG_FILES example/replace-header/Makefile" ;; + "example/response-header-1/Makefile") CONFIG_FILES="$CONFIG_FILES example/response-header-1/Makefile" ;; + "example/server-transform/Makefile") CONFIG_FILES="$CONFIG_FILES example/server-transform/Makefile" ;; + "example/session-1/Makefile") CONFIG_FILES="$CONFIG_FILES example/session-1/Makefile" ;; + "example/thread-1/Makefile") CONFIG_FILES="$CONFIG_FILES example/thread-1/Makefile" ;; + "example/thread-pool/Makefile") CONFIG_FILES="$CONFIG_FILES example/thread-pool/Makefile" ;; + "example/app-template/Makefile") CONFIG_FILES="$CONFIG_FILES example/app-template/Makefile" ;; + "example/app-template/records.config") CONFIG_FILES="$CONFIG_FILES example/app-template/records.config" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010 Free Software Foundation, +# Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000..f913b21a --- /dev/null +++ b/configure.ac @@ -0,0 +1,1276 @@ +# Process this file with `autoreconf -i` to create a 'configure' file. + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Table of Contents +# 1. INITIALIZATION +# 2. SITE CONFIGURATION +# 3. CHECK FOR PROGRAMS +# 4. CHECK FOR LIBRARIES +# 5. CHECK FOR HEADERS +# 6. OUTPUT FILES +# 7. autoheader TEMPLATES + +# ----------------------------------------------------------------------------- +# 1. INITIALIZATION + +# These first two version numbers are updated automatically on each release. +# Version number is calculated as MAJOR * 1000000 + MINOR * 1000 + MICRO +# Version string is in the form of MAJOR.MINOR.MICRO[sufix] +# +m4_define([TS_VERSION_S],[3.0.5]) +m4_define([TS_VERSION_N],[3000005]) + +AC_INIT([Apache Traffic Server], TS_VERSION_S(), [dev@trafficserver.apache.org], [trafficserver],[http://trafficserver.apache.org]) +AC_PREREQ([2.59]) +AC_CONFIG_AUX_DIR([build/aux]) +AC_CONFIG_SRCDIR([proxy/Main.cc]) +AC_CONFIG_MACRO_DIR([build]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign no-installinfo no-installman 1.9.2]) +AM_CONFIG_HEADER([lib/ts/ink_autoconf.h]) + +# Not sure this is needed, and seems to break with some versions of automake +#LT_INIT([dlopen]) + +# Libtool versioning uses different conventions on different +# platforms. At least on FreeBSD, libtool uses an overly complex +# convention that attempts to solve problems that most people just +# don't have and which just causes confusion for most end users. +# +TS_VERSION_MAJOR=$((TS_VERSION_N() / 1000000 )) +TS_VERSION_MINOR=$(((TS_VERSION_N() / 1000) % 1000 )) +TS_VERSION_MICRO=$((TS_VERSION_N() % 1000 )) +TS_LIBTOOL_MAJOR=`echo $((${TS_VERSION_MAJOR} + ${TS_VERSION_MINOR}))` +TS_LIBTOOL_VERSION=$TS_LIBTOOL_MAJOR:$TS_VERSION_MICRO:$TS_VERSION_MINOR +TS_VERSION_STRING=TS_VERSION_S() +TS_VERSION_NUMBER=TS_VERSION_N() + +# +# Substitute the above version numbers into the various files below. +# +AC_SUBST(TS_LIBTOOL_VERSION) +AC_SUBST(TS_VERSION_STRING) +AC_SUBST(TS_VERSION_NUMBER) +AC_SUBST(TS_VERSION_MAJOR) +AC_SUBST(TS_VERSION_MINOR) +AC_SUBST(TS_VERSION_MICRO) + +dnl Hard-coded top of ink_autoconf.h: +AH_TOP([ +#ifndef _ink_autoconf_h +#define _ink_autoconf_h +]) + +dnl Hard-coded inclusion at the tail end of ink_autoconf.h: +AH_BOTTOM([ + +#endif /* _ink_autoconf_h */ +]) + +# +# Generate ./config.nice for reproducing runs of configure +# +TS_CONFIG_NICE([config.nice]) + +# XXX we can't just use AC_PREFIX_DEFAULT because that isn't subbed in +# by configure until it is too late. Is that how it should be or not? +# Something seems broken here. +AC_PREFIX_DEFAULT([/usr/local/trafficserver]) + +# Get the layout here, so we can pass the required variables to Trafficserver +TS_ENABLE_LAYOUT(TrafficServer, [cachedir]) + +# Reparse the configure arguments so we can override the layout. +TS_PARSE_ARGUMENTS + +# +# Host detection +# +AC_CANONICAL_HOST +HOST_GUESS="$host" +AC_SUBST(HOST_GUESS) + +# +# Build environment +# +build_person="`id -nu`" +build_group="`id -ng`" +build_machine="`uname -n`" +AC_SUBST([build_machine]) +AC_SUBST([build_person]) +AC_SUBST([build_group]) + +AC_ARG_WITH([user], + [AS_HELP_STRING([--with-user],[specify the system user [default: nobody]])], + [ + with_user="$withval" + ],[ + with_user="nobody" + ] +) + +default_group="`id -ng $with_user`" +AC_ARG_WITH([group], + [AS_HELP_STRING([--with-group],[specify the system group [default: nobody]])], + [ + with_group="$withval" + ],[ + with_group=${default_group:-nobody} + ] +) +AC_SUBST([pkgsysuser],[$with_user]) +AC_SUBST([pkgsysgroup],[$with_group]) + +# ----------------------------------------------------------------------------- +# 2. SITE CONFIGURATION + +# +# Debug +# + +AC_MSG_CHECKING([whether to enable debugging]) +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug],[turn on debugging])], + [], + [enable_debug=no] +) +AC_MSG_RESULT([$enable_debug]) + +# +# Fast SDK APIs, this disables the parameter checks (assert) +# on all APIs. +# + +AC_MSG_CHECKING([whether to enable fast SDK APIs]) +AC_ARG_ENABLE([fast-sdk], + [AS_HELP_STRING([--enable-fast-sdk],[enable fast SDK APIs (no input parameter sanity checks)])], + [], + [enable_fast_sdk=no] +) +AC_MSG_RESULT([$enable_fast_sdk]) +TS_ARG_ENABLE_VAR([use], [fast-sdk]) +AC_SUBST(use_fast_sdk) + +# +# Diags +# + +AC_MSG_CHECKING([whether to enable diags]) +AC_ARG_ENABLE([diags], + [AS_HELP_STRING([--disable-diags],[turn off diags])], + [], + [enable_diags=yes] +) +AC_MSG_RESULT([$enable_diags]) +TS_ARG_ENABLE_VAR([use], [diags]) +AC_SUBST(use_diags) + +# +# Build regression tests? +# + +AC_MSG_CHECKING([whether to enable regression tests]) +AC_ARG_ENABLE([tests], + [AS_HELP_STRING([--disable-tests],[turn off regression tests])], + [], + [enable_tests=yes] +) +AC_MSG_RESULT([$enable_tests]) +TS_ARG_ENABLE_VAR([has], [tests]) +AC_SUBST(has_tests) +AM_CONDITIONAL([BUILD_TESTS], [test 0 -ne $has_tests]) + +# +# Purify +# +AC_MSG_CHECKING([whether to enable purify]) +AC_ARG_ENABLE([purify], + [AS_HELP_STRING([--enable-purify],[enable support for Purify])], + [], + [enable_purify=no] +) +AC_MSG_RESULT([$enable_purify]) +TS_ARG_ENABLE_VAR([has], [purify]) +AC_SUBST(has_purify) + +# +# libev +# + +AC_MSG_CHECKING([whether to use libev even if not required]) +AC_ARG_ENABLE([libev], + [AS_HELP_STRING([--enable-libev],[use libev even if not required])], + [], + [enable_libev=no] +) +AC_MSG_RESULT([$enable_libev]) + +# +# Micro +# +AC_MSG_CHECKING([whether to enable micro-TS]) +AC_ARG_ENABLE([micro], + [AS_HELP_STRING([--enable-micro],[enable micro-TS build [default: no]])], + [], + [enable_micro=no] +) +AC_MSG_RESULT([$enable_micro]) +AS_IF([test "x$enable_micro" = "xyes"], [is_micro_build=1], [is_micro_build=0]) +AC_SUBST(is_micro_build) + +# +# Standalone iocore +# +AC_MSG_CHECKING([whether to build a standalone iocore]) +AC_ARG_ENABLE([standalone-iocore], + [AS_HELP_STRING([--enable-standalone-iocore],[build just standalone iocore])], + [], + [enable_standalone_iocore=no] +) +AC_MSG_RESULT([$enable_standalone_iocore]) +TS_ARG_ENABLE_VAR([has],[standalone-iocore]) +AC_SUBST(has_standalone_iocore) +AS_IF([test 0 -ne $has_standalone_iocore], + [AC_SUBST([IOCORE_MODULARIZED_DEFS],[""]) + AC_SUBST([ink_with_modules_def],["-DREC_BUILD_STAND_ALONE"]) + AC_SUBST([ink_with_modules_local],[""]) + AC_SUBST([ink_with_modules_process],[""]) + ], + [AC_SUBST([ink_with_modules_def],["-DREC_BUILD_MGMT"]) + AC_SUBST([ink_with_modules_local],["-DLOCAL_MANAGER"]) + AC_SUBST([ink_with_modules_process],["-DPROCESS_MANAGER"]) + ] +) +AM_CONDITIONAL([STANDALONE_IOCORE], [test 0 -ne $has_standalone_iocore]) + +# +# Force some static linkage (for testing / development only) +# +AC_MSG_CHECKING([whether to build some static libts (dev only)]) +AC_ARG_ENABLE([static-libts], + [AS_HELP_STRING([--enable-static-libts],[build some static libts (dev only)])], + [], + [enable_static_libts=no] +) +AC_MSG_RESULT([$enable_static_libts]) +TS_ARG_ENABLE_VAR([has],[static-libts]) +AM_CONDITIONAL([STATIC_LIBTS], [test 0 -ne $has_static_libts]) + +# +# Remote Coverity Prevent commit +# +AC_MSG_CHECKING([whether to commit cov defects to remote host]) +AC_ARG_ENABLE([remote-cov-commit], + [AS_HELP_STRING([--enable-remote-cov-commit[=HOST]], [commit cov defects to remote host [HOST=localhost]])], + [], + [enable_remote_cov_commit=localhost] +) +AC_MSG_RESULT([$enable_remote_cov_commit]) +AC_SUBST([enable_remote_cov_commit]) + +# +# API +# +AC_MSG_CHECKING([whether to enable API and plugin support]) +AC_ARG_ENABLE([api], + [AS_HELP_STRING([--disable-api],[do not enable API and plugin support])], + [], + [enable_api=yes] +) +AC_MSG_RESULT([$enable_api]) +AS_IF([test "x$enable_api" = "xyes"], [has_inkapi=1], [has_inkapi=0]) +AC_SUBST(has_inkapi) + +# +# WCCP +# +AC_MSG_CHECKING([whether to enable WCCP v2 support]) +AC_ARG_ENABLE([wccp], + [AS_HELP_STRING([--enable-wccp],[enable WCCP v2])], + [], + [enable_wccp=no] +) +AC_MSG_RESULT([$enable_wccp]) +TS_ARG_ENABLE_VAR([has],[wccp]) +AC_SUBST(has_wccp) +AM_CONDITIONAL([BUILD_WCCP], [test 0 -ne $has_wccp]) + +# Google profiler +AC_MSG_CHECKING([whether to enable profiler]) +AC_ARG_WITH([profiler], + [AS_HELP_STRING([--with-profiler],[enable support for profiler [default=no]])], + [with_profiler=$withval], + [with_profiler=no] +) +AC_MSG_RESULT([$with_profiler]) + +# +# use eventfd() or pipes +# Found that ec2 is using an older kernel causing eventfd errors. +# Disable eventfd when using ATS on EC2 Fedora. +# +AC_MSG_CHECKING([whether to enable eventfd()]) +AC_ARG_ENABLE([eventfd], + [AS_HELP_STRING([--disable-eventfd],[turn off eventfd and use pipes])], + [], + [enable_eventfd="yes"] +) +AC_MSG_RESULT([$enable_eventfd]) + +# +# use POSIX capabilities instead of user ID switching. +# +AC_MSG_CHECKING([whether to use POSIX capabilities]) +AC_ARG_ENABLE([posix-cap], + [AS_HELP_STRING([--disable-posix-cap],[Use user id switching instead of POSIX capabilities])], + [], + [enable_posix_cap="yes"] +) +AC_MSG_RESULT([$enable_posix_cap]) + +# +# Enble ccache explicitly (it's disabled by default, because of build problems in some cases) +# +AC_MSG_CHECKING([whether to enable ccache]) +AC_ARG_ENABLE([ccache], + [AS_HELP_STRING([--enable-ccache],[Enable ccache (can cause bad builds)])], + [], + [enable_ccache="no"] +) +AC_MSG_RESULT([$enable_ccache]) + +# +# Use TPROXY for connection transparency. +# +AC_MSG_CHECKING([whether to enable TPROXY based transparency]) +AC_ARG_ENABLE([tproxy], + [AS_HELP_STRING([--enable-tproxy[[=ARG]]], + [Use TPROXY to enable connection transparency. + 'auto' or omitted for local system default, + 'no' to disable, + 'force' to use built in default, + number to use as IP_TRANSPARENT sockopt. + [default=auto] + ]) + ], + [], + [enable_tproxy="auto"] +) +AC_MSG_RESULT([$enable_tproxy]) + +# +# Configure how many stats to allocate for plugins. Default is 512. +# +AC_ARG_WITH([max-api-stats], + [AS_HELP_STRING([--with-max-api-stats],[max number of plugin stats [default=512]])], + [max_api_stats=$withval], + [max_api_stats=512] +) +AC_SUBST(max_api_stats) + +# +# Installation directories +# For each var the following is evaluated +# foo Standard variable eg. ${prefix}/foo +# rel_foo Relative to prefix eg. foo +# +TS_SUBST_LAYOUT_PATH([prefix]) +TS_SUBST_LAYOUT_PATH([exec_prefix]) +TS_SUBST_LAYOUT_PATH([bindir]) +TS_SUBST_LAYOUT_PATH([sbindir]) +TS_SUBST_LAYOUT_PATH([libdir]) +TS_SUBST_LAYOUT_PATH([libexecdir]) +TS_SUBST_LAYOUT_PATH([infodir]) +TS_SUBST_LAYOUT_PATH([mandir]) +TS_SUBST_LAYOUT_PATH([sysconfdir]) +TS_SUBST_LAYOUT_PATH([datadir]) +TS_SUBST_LAYOUT_PATH([installbuilddir]) +TS_SUBST_LAYOUT_PATH([includedir]) +TS_SUBST_LAYOUT_PATH([localstatedir]) +TS_SUBST_LAYOUT_PATH([runtimedir]) +TS_SUBST_LAYOUT_PATH([logdir]) +TS_SUBST_LAYOUT_PATH([cachedir]) + +TS_SUBST([pkgbindir]) +TS_SUBST([pkgsbindir]) +TS_SUBST([pkglibdir]) +TS_SUBST([pkglibexecdir]) +TS_SUBST([pkgsysconfdir]) +TS_SUBST([pkgdatadir]) +TS_SUBST([pkglocalstatedir]) +TS_SUBST([pkgruntimedir]) +TS_SUBST([pkglogdir]) +TS_SUBST([pkgcachedir]) + + +# ----------------------------------------------------------------------------- +# 3. CHECK FOR PROGRAMS + +# Compiler selection: +# +# Implementation note (toc) +# 1) Get default compiler settings (case statement.) +# 2) Check for over-rides of default compiler. +# 3) Set standard CFLAGS, SHARED_CFLAGS, etc. +# 4) (in first kludge mode block...) obtain any further CFLAG-type additions. +# 5) Test compilers with all flags set. + +# AC_PROG can sometimes mangle CFLAGS etc. +# in particular, on Linux they insert -g -O2, here we preserve any user CFLAGS + +#CC=gcc +#CXX=g++ + +REAL_CFLAGS="${CFLAGS}" +REAL_CXXFLAGS="${CXXFLAGS}" + +AC_PROG_CC +AC_PROG_CXX + +# Check for ccache (if explicitly enabled) +if test "x$enable_ccache" = "xyes"; then + AC_CHECK_PROG([CCACHE],[ccache],[ccache],[]) + if test "x${CCACHE}" = "xccache"; then + CC="$CCACHE $CC" + CXX="$CCACHE $CXX" + fi +fi + +dnl AC_PROG_SED is only avaliable in recent autoconf versions. +dnl Use AC_CHECK_PROG instead if AC_PROG_SED is not present. +ifdef([AC_PROG_SED], + [AC_PROG_SED], + [AC_CHECK_PROG(SED, sed, sed)]) + +AC_PROG_CPP +AC_PROG_CXXCPP +AM_PROG_AS +AC_PROG_AWK +AC_PROG_LN_S +AC_PROG_INSTALL +AC_PROG_LIBTOOL +AC_CHECK_PROG(RM, rm, rm) +AC_CHECK_PROG(ASCPP, cpp, cpp) +AC_CHECK_TOOL(AR, ar, ar) +AC_ISC_POSIX +AS_IF([test "x$enable_wccp" = "xyes"], + [ + AC_PROG_YACC + AC_PROG_LEX + ] +) + +AC_PATH_PROG([DOXYGEN], [doxygen]) # needed for Doxygen +AC_PATH_PROG([PERL],[perl],[not found]) +AS_IF([test "x$PERL" = "xnot found"], + [AC_MSG_ERROR([check for perl failed. Have you installed perl?])] +) +AC_ARG_VAR([DOXYGEN], [full path of Doxygen executable]) +AC_ARG_VAR([PERL], [full path of Perl executable]) + +CFLAGS="${REAL_CFLAGS}" +CXXFLAGS="${REAL_CXXFLAGS}" + +AC_MSG_CHECKING([checking whether to auto-set compile optimizing flags]) +has_optimizer_flags=`$as_echo "$CFLAGS $CXXFLAGS" | ${AWK} '/-x?O.?/{print "no"}'` +AS_IF([test "x${has_optimizer_flags}" = "xno"], + [ optimizing_flags='' ], + [ + has_optimizer_flags='yes' + optimizing_flags='-O3' + ] +) +AC_MSG_RESULT([${has_optimizer_flags} ${optimizing_flags}]) + +base_cc=`basename $CC` +# These are shortcuts used in combination for the compiler options below +case $host_os in + linux*) + if test "x${base_cc}" = "xicc"; then + # -Wall goes crazy, so turned these specific checks off for now: + # + # 111 is "statement is unrecahable" + # 279 is "controlling expression is constant", triggered by our asserts + # 383 is "value copied to temporary, reference to temporary used" + # 444 is "destructor for base class is not virtual" + # 522 is "function "xyz" redeclared "inline" after being called + # 873 is "has no corresponding operator delete". ToDo: we should fix. + # 981 is "operands are evaluated in unspecified order" + # 1418 is "external function definition with no prior declaration" + # 1419 is "external declaration in primary source file" + # 1572 is "floating-point equality and inequality comparisons are unreliable" + # 1720 is "operator new" has no corresponding member operator delete" + # 2256 is "non-pointer conversion from "int" to "unsigned char" " + # 2259 is "non-pointer conversion from "int" to "unsigned char" " + # + # TODO: We should try to eliminate more of these -wd exclusions. + common_opt="-pipe -Wall -wd111 -wd279 -wd383 -wd522 -wd444 -wd873 -wd981 -wd1418 -wd1419 -wd1572 -wd1720 -wd2256 -wd2259" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimization_flags -axsse4.2 -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + else # gcc + # This is useful for finding odd conversions + # common_opt="-pipe -Wall -Werror -Wconversion -Wno-sign-conversion" + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + fi + ;; + darwin*) + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + TS_ADDTO(CPPFLAGS, [-I/opt/local/include]) + TS_ADDTO(LDFLAGS, [-L/opt/local/lib]) + ;; + freebsd*|kfreebsd*) + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + TS_ADDTO(LDFLAGS, [-L/usr/local/lib]) + ;; + solaris*) + if test "x${base_cc}" = "xcc"; then + common_opt="-mt -m64 -D__WORDSIZE=64" # FIXME: arch should be detected + debug_opt="-g $common_opt" + release_opt="-g $common_opt $optimizing_flags" + cxx_opt="-library=stlport4" + cxx_dbg="+w2" + cxx_rel="-erroff" + AC_DEFINE([_POSIX_PTHREAD_SEMANTICS],1, + [posix thread semantics] + ) + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX="-library=Crun" + fi + else # gcc + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + fi + TS_ADDTO(LDFLAGS, [-L/lib]) + TS_ADDTO(LDFLAGS, [-L/usr/local/lib]) + ;; + *) + common_opt="-pipe -Wall -Werror" + debug_opt="-ggdb3 $common_opt" + release_opt="-g $common_opt $optimizing_flags -feliminate-unused-debug-symbols -fno-strict-aliasing" + cxx_opt="-Wno-invalid-offsetof" + ;; +esac + +cc_oflag_opt=$release_opt +cc_oflag_dbg=$debug_opt +cxx_oflag_opt="$release_opt $cxx_opt $cxx_rel" +cxx_oflag_dbg="$debug_opt $cxx_opt $cxx_dbg" + +SHARED_CFLAGS=-fPIC +SHARED_LDFLAGS=-shared +SHARED_CXXFLAGS=-fPIC +SHARED_CXXLINKFLAGS=-shared + +dnl Checks for pointer size +AC_CHECK_SIZEOF(void*, 4) +if test "x$ac_cv_sizeof_voidp" == "x"; then + AC_ERROR([Cannot determine size of void*]) +fi +AC_SUBST(ac_cv_sizeof_voidp) + + +# Checks for TCP defer accept +case $host_os in + linux*) + defer_accept=45 + ;; + *) + defer_accept=1 + ;; +esac +AC_SUBST(defer_accept) + + +# +# Here are all the extra linux-specific C(XX)FLAGS additions and +# so forth. +# TODO cpu architecture settings separate from operating system settings +# +cpu_architecture="" +# GCC: add a default march if there is not one set +if test "x${GCC}" = "xyes"; then + if test "${ac_cv_sizeof_voidp}" = "4"; then + case "$host_cpu" in + i?86* | k[5-8]* | pentium* | athlon) + cpu_architecture="-march=i586" + ;; + *sparc*) + cpu_architecture="-mv8" + ;; + esac + else + case "$host_cpu" in + x86_64 | amd64) + # XXX: Any need for 64-bit arch flags? + # cpu_architecture="-march=native" + ;; + *sparc*) + cpu_architecture="-march=ultrasparc" + ;; + esac + fi + # TODO: Add support for other compilers + # +fi + +# Overrride detected architecture with the user suplied one +# +AC_ARG_WITH(architecture, [AC_HELP_STRING([--with-architecture=ARCH],[use a specific CPU architecture])], +[ + if test "x$withval" != "xyes" && test "x$withval" != "xno"; then + case "$withval" in + -*) + # TODO: In case we are cross compiling some of the provided flags + # should be added to the LDFLAGS + cpu_architecture="$withval" + ;; + *) + cpu_architecture="-march=$withval" + ;; + esac + elif test "x$withval" = "x"; then + AC_MSG_ERROR([--with-architecture requires an param]) + fi +]) + +if test "x$cpu_architecture" != "x"; then + TS_ADDTO(CFLAGS, [$cpu_architecture]) + TS_ADDTO(CXXFLAGS, [$cpu_architecture]) +fi + +# 64-bit LFS support +# +TS_ADDTO(CPPFLAGS, [-D_LARGEFILE64_SOURCE=1]) +if test "${ac_cv_sizeof_voidp}" = "8"; then + TS_ADDTO(CPPFLAGS, [-D_COMPILE64BIT_SOURCE=1]) +else + TS_ADDTO(CPPFLAGS, [-D_FILE_OFFSET_BITS=64]) +fi +TS_ADDTO(CPPFLAGS, [-D_GNU_SOURCE]) +TS_ADDTO(CPPFLAGS, [-D_REENTRANT]) + +case $host_os in + linux*) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=linux + ;; + darwin*) + host_os_def=darwin + ;; + freebsd*) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=freebsd + ;; + kfreebsd*) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=freebsd + TS_ADDTO(CPPFLAGS, [-Dkfreebsd]) + ;; + solaris*) + host_os_def=solaris + ;; + *) + EXTRA_CXX_LDFLAGS="-rdynamic" + host_os_def=unknown + ;; +esac +TS_ADDTO(CPPFLAGS, [-D$host_os_def]) + +AC_MSG_NOTICE([Build for host OS: $host_os, arch: $host_cpu, optimization: $host_os_def]) + +# +# _Here_ is where we go ahead and add the _optimizations_ to already +# existing CFLAGS/CXXFLAGS if some special values had been set. +# +if test "x${enable_debug}" = "xyes"; then + TS_ADDTO(CFLAGS, [${cc_oflag_dbg}]) + TS_ADDTO(CXXFLAGS, [${cxx_oflag_dbg}]) + TS_ADDTO(CPPFLAGS, [-DDEBUG -D_DEBUG]) +else + TS_ADDTO(CFLAGS, [${cc_oflag_opt}]) + TS_ADDTO(CXXFLAGS, [${cxx_oflag_opt}]) +fi + +# +# Note: These are site-specific macro's that do various tests +# on the selected compilers. There was some tunning +# associated with our not wanting to use GNU for _everything_. +# Note: This macro may set certain parameters when run. +# + + +# ----------------------------------------------------------------------------- +# 4. CHECK FOR LIBRARIES + +AC_CHECK_LIB([exc],[exc_capture_context],[AC_SUBST([LIBEXC],["-lexc"])]) +AC_CHECK_LIB([mld],[MLD_demangle_string],[AC_SUBST([LIBMLD],["-lmld"])]) +AC_CHECK_LIB([dl],[dlopen],[AC_SUBST([LIBDL],["-ldl"])]) +AC_CHECK_LIB([socket],[socket],[AC_SUBST([LIBSOCKET],["-lsocket"])]) +AC_CHECK_LIB([nsl],[gethostbyname],[AC_SUBST([LIBNSL],["-lnsl"])]) +AC_CHECK_LIB([resolv],[res_init],[AC_SUBST([LIBRESOLV],["-lresolv"])]) +AC_CHECK_LIB([resolv],[__putlong],[AC_SUBST([LIBRESOLV],["-lresolv"])]) +AC_CHECK_LIB([pthread],[pthread_exit],[AC_SUBST([LIBTHREAD],["-lpthread"])]) +AC_CHECK_LIB([rt],[clock_gettime],[AC_SUBST([LIBRT],["-lrt"])]) +AC_CHECK_LIB([posix4],[clock_gettime],[AC_SUBST([LIBRT],["-lposix4"])]) +AC_CHECK_LIB([iconv],[iconv_open],[AC_SUBST([LIBICONV],["-liconv"])]) +AC_CHECK_LIB([iconv],[libiconv_open],[AC_SUBST([LIBICONV],["-liconv"])]) +# TODO: We have --enable-libev but here we add it unconditionally +# making resulting binaries always linked to libev if present. +# Use a proper --with-libev and fail on --enable-libev and -lev +# is missing. Allow --with-libev=builtin? living in ./srclib/ev ? +# +AC_CHECK_LIB([ev],[ev_sleep],[AC_SUBST([LIBEV],["-lev"])]) + +# +# Check for SSL presence and usability +TS_CHECK_CRYPTO +if test "x${enable_crypto}" != "xyes"; then + AC_MSG_ERROR([Need at least one SSL library, --with-openssl is supported]) +fi + +# +# Check for zlib presence and usability +TS_CHECK_ZLIB + +# +# Check for lzma presence and usability +TS_CHECK_LZMA + +# +# Tcl macros provided by m4/tcl.m4 +# +# this will error out if tclConfig.sh is not found +SC_PATH_TCLCONFIG + +# if tclConfig.sh loads properly, assume libraries are there and working +SC_LOAD_TCLCONFIG + +# expect tclConfig.sh to populate TCL_LIB_FLAG and TCL_INCLUDE_SPEC +case $host_os in + darwin*) + TCL_LIB_SPEC="-ltcl" # OSX fails to populate this variable + ;; + *) + ;; +esac +AC_SUBST([LIBTCL],[$TCL_LIB_SPEC]) + +case $host_os in + freebsd*|kfreebsd*) + TS_ADDTO(CPPFLAGS, [-I/usr/local/include]) + ;; + solaris*) + TS_ADDTO(CPPFLAGS, [-I/usr/local/include]) + ;; +esac + +if test "x${TCL_INCLUDE_SPEC}" != "x-I/usr/include"; then + TS_ADDTO(CPPFLAGS, [$TCL_INCLUDE_SPEC]) +fi + +# +# Check for XML parser +# +TS_CHECK_XML +if test "x${enable_xml}" != "xyes"; then + AC_MSG_ERROR([Need at least one XML library, --with-expat is supported]) +fi + +TS_FLAG_FUNCS([clock_gettime kqueue epoll_ctl posix_memalign posix_fadvise lrand48_r srand48_r port_create]) +TS_FLAG_FUNCS([strndup strlcpy strlcat]) + +AC_SUBST(has_clock_gettime) +AC_SUBST(has_posix_memalign) +AC_SUBST(has_posix_fadvise) +AC_SUBST(has_lrand48_r) +AC_SUBST(has_srand48_r) +AC_SUBST(has_strndup) +AC_SUBST(has_strlcpy) +AC_SUBST(has_strlcat) + +# Check for eventfd() and sys/eventfd.h (both must exist ...) +TS_FLAG_HEADERS([sys/eventfd.h], [has_eventfd=1], [has_eventfd=0], []) +if test "x${has_eventfd}" = "xyes"; then + AS_IF([test "x$enable_eventfd" = "xyes"], + [TS_FLAG_FUNCS([eventfd])] + ) +fi +AC_SUBST(has_eventfd) + +# +# Check for pcre library +# +TS_CHECK_PCRE +if test "x${enable_pcre}" != "xyes"; then + AC_MSG_ERROR([Cannot find pcre library. Configure --with-pcre=DIR]) +fi + +has_backtrace=0 +# Check for backtrace() support +TS_FLAG_HEADERS([execinfo.h], [has_backtrace=1],[]) +if test "${has_backtrace}" = "1"; then + # FreeBSD requires '/usr/ports/devel/libexecinfo' for gdb style backtrace() support + AC_CHECK_LIB([execinfo], [backtrace], [have_backtrace_lib=yes + AC_SUBST([LIBEXECINFO],["-lexecinfo"])]) + if test "x${have_backtrace_lib}" = "xyes"; then + AC_MSG_NOTICE([Using backtrace library '-lexecinfo']) + fi +else + AC_MSG_WARN([No backtrace() support found]) +fi +AC_SUBST(execinfoh) +AC_SUBST(has_backtrace) + +use_libev=0 +use_epoll=0 +use_kqueue=0 +use_port=0 +if test "x$enable_libev" = "xyes"; then + use_libev=1 + have_good_poller=1 +elif test "$ac_cv_func_epoll_ctl" = "yes"; then + use_epoll=1 + have_good_poller=1 + AC_MSG_NOTICE([Using epoll event interface]) +elif test "$ac_cv_func_kqueue" = "yes"; then + use_kqueue=1 + have_good_poller=1 + AC_MSG_NOTICE([Using kqueue event interface]) +elif test "$ac_cv_func_port_create" = "yes"; then + use_port=1 + have_good_poller=1 + AC_MSG_NOTICE([Using port event interface]) +else + AC_MSG_FAILURE([No suitable polling interface found]) +fi +AC_SUBST(use_libev) +AC_SUBST(use_epoll) +AC_SUBST(use_kqueue) +AC_SUBST(use_port) + +has_profiler=0 +if test "x${with_profiler}" = "xyes"; then + AC_CHECK_LIB([profiler], [ProfilerStart], + [AC_SUBST([LIBPROFILER], ["-lprofiler"]) + has_profiler=1 + ], + [AC_MSG_FAILURE([check for profiler failed. Have you installed google-perftools-devel?])], + ) +fi +AC_SUBST(has_profiler) + +has_demangle=0 +# For SunPro 5.2 - we need the demangle symbol for +# ink_stack_trace.cc in lib/ts. Because this +# library is part of the SunPro distribution, we need +# check with the C++ compiler since we might be using +# SunPro CC for the C++ compiler and gcc for the C compiler +AC_LANG_PUSH([C++]) +AC_CHECK_LIB([demangle],[cplus_demangle], + [LIBDEMANGLE="-ldemangle" + has_demangle=1 + ] +) +AC_SUBST([LIBDEMANGLE]) +AC_LANG_POP +AC_SUBST(has_demangle) + +need_union_semun=0 +# It's stupid, but not all platforms have union semun, even those that need it. +AC_MSG_CHECKING(for union semun in sys/sem.h) +AC_TRY_COMPILE([ +#include +#include +#include +],[ +union semun arg; +semctl(0, 0, 0, arg); +], [union_semun=yes] +msg=yes, [ +need_union_semun="1" +msg=no ] ) +AC_MSG_RESULT([$msg]) + +AC_SUBST(need_union_semun) + +# Check for POSIX capabilities library. +# If we don't find it, disable checking for header. +use_posix_cap=0 +AS_IF([test "x$enable_posix_cap" = "xyes"], + AC_CHECK_LIB([cap],[cap_set_proc], + [AC_SUBST([LIBCAP], ["-lcap"]) + use_posix_cap=1 + ], + [enable_posix_cap=no] + ) +) +AC_SUBST(use_posix_cap) +# ----------------------------------------------------------------------------- +# 5. CHECK FOR HEADER FILES + +TS_FLAG_HEADERS([sys/epoll.h \ + sys/event.h \ + machine/endian.h \ + endian.h \ + sys/sysinfo.h \ + sys/sysctl.h \ + sys/systeminfo.h \ + netinet/in.h \ + netinet/in_systm.h \ + netinet/tcp.h \ + sys/ioctl.h \ + sys/byteorder.h \ + sys/sockio.h \ + sys/prctl.h \ + arpa/inet.h \ + arpa/nameser.h \ + arpa/nameser_compat.h \ + execinfo.h \ + netdb.h \ + ctype.h \ + siginfo.h \ + malloc.h \ + wait.h \ + float.h \ + libgen.h \ + values.h \ + alloca.h \ + cpio.h \ + stropts.h \ + sys/mount.h \ + sys/param.h \ + sys/sysmacros.h \ + math.h \ + stdint.h \ + net/ppp_defs.h]) + +AC_SUBST(sys_epollh) +AC_SUBST(sys_eventh) +AC_SUBST(machine_endianh) +AC_SUBST(endianh) +AC_SUBST(netinet_inh) +AC_SUBST(netinet_in_systmh) +AC_SUBST(netinet_tcph) +AC_SUBST(sys_ioctlh) +AC_SUBST(sys_byteorderh) +AC_SUBST(sys_sockioh) +AC_SUBST(sys_sysctlh) +AC_SUBST(sys_sysinfoh) +AC_SUBST(sys_systeminfoh) +AC_SUBST(arpa_ineth) +AC_SUBST(arpa_nameserh) +AC_SUBST(arpa_nameser_compath) +AC_SUBST(execinfoh) +AC_SUBST(netdbh) +AC_SUBST(ctypeh) + +AC_SUBST(siginfoh) +AC_SUBST(malloch) +AC_SUBST(waith) +AC_SUBST(floath) +AC_SUBST(libgenh) +AC_SUBST(valuesh) +AC_SUBST(allocah) +AC_SUBST(cpioh) +AC_SUBST(stroptsh) +AC_SUBST(sys_mounth) +AC_SUBST(sys_paramh) +AC_SUBST(sys_sysmacrosh) +AC_SUBST(mathh) +AC_SUBST(net_ppp_defsh) + +TS_FLAG_HEADERS([netinet/ip.h], [], [], + [[#ifdef HAVE_SYS_TYPES_H + #include + #endif + #ifdef HAVE_NETINET_IN_H + #include + #endif + ]]) + +TS_FLAG_HEADERS([netinet/ip_icmp.h], [], [], + [[#ifdef HAVE_SYS_TYPES_H + #include + #endif + #ifdef HAVE_NETINET_IN_H + #include + #endif + #ifdef HAVE_NETINET_IP_H + #include + #endif + #ifdef HAVE_NETINET_IN_SYSTM_H + #include + #endif + ]]) + +AC_SUBST(netinet_iph) +AC_SUBST(netinet_ip_icmph) + +if test "x${with_profiler}" = "xyes"; then +TS_FLAG_HEADERS([google/profiler.h \ + ], [], []) +fi + +if test "x${enable_posix_cap}" = "xyes"; then + AC_CHECK_HEADERS([sys/capability.h], + [], + [AC_MSG_FAILURE([POSIX capabilities header not found. Try --disable-posix-cap])], + [] + ) +fi + +# +# Configure sockopt value for TPROXY. Look at the enable flag. +# Value 'no' means user forced disable, don't check anything else. +# 'auto' means user didn't say, so silently enable/disable +# based on success. +# A numeric value means enable, don't check, use that value. +# Anything else means user forced, fail if value not found +# in header file. +# We can't just include linux/in.h because it's incompatible with +# netinet/in.h. +# Verify the file exists (is readable), scan for the value we need, +# if found export the value and enable use of the value. +# +ip_transparent=0 +use_tproxy=0 +tproxy_header=/usr/include/linux/in.h +tproxy_usage_enable=" + --enable-tproxy Enable the feature and validate." +tproxy_usage_default=" + --enable-tproxy=force Enable using default sockopt value, no validation." +tproxy_usage_numeric=" + --enable-tproxy=X where X is numeric + Enable, use X for sockopt value, no validation." +tproxy_usage_disable=" + --disable-tproxy Disable feature, no validation." +proxy_usage="$tproxy_usage_enable$tproxy_usage_default$tproxy_usage_numeric$tproxy_usage_disable" + +AS_IF([test "x$enable_tproxy" != "xno"], [ + AS_IF([test "x${enable_posix_cap}" != "xyes"], [ + AS_IF([test "x$enable_tproxy" = xauto], [ + AC_MSG_RESULT([no]) + ],[ + AC_MSG_FAILURE([TPROXY feature requires POSIX capabilities.]) + ]) + ],[ + AC_MSG_CHECKING([for TPROXY sockopt IP_TRANSPARENT]) + case "$enable_tproxy" in + [[0-9][0-9]*]) + ip_transparent=$enable_tproxy + use_tproxy=1 + AC_MSG_RESULT([forced to $ip_transparent]) + ;; + force) + ip_transparent=19 + use_tproxy=1 + AC_MSG_RESULT([forced to $ip_transparent]) + ;; + yes|auto) + AS_IF([test -r $tproxy_header], [ + ip_transparent=`$AWK "/^#define[ \t]+IP_TRANSPARENT[ \t]+[0-9]+/{print \\$3}" $tproxy_header` + AS_IF([test "x$ip_transparent" != "x"], [ + use_tproxy=1 + AC_MSG_RESULT([set to $ip_transparent]) + ],[ + ip_transparent=0 + AS_IF([test "x$enable_tproxy" = xauto], [ + AC_MSG_RESULT([no]) + ],[ + AC_MSG_RESULT([failed]) + AC_MSG_FAILURE([tproxy feature enabled but the sockopt value was not found in $tproxy_header. Try one of$tproxy_usage_default$tproxy_usage_numeric$tproxy_usage_disable]) + ]) + ]) + ],[ + AS_IF([test "x$enable_tproxy" = xauto], [ + AC_MSG_RESULT([no]) + ],[ + AC_MSG_RESULT([failed]) + AC_MSG_FAILURE([tproxy feature enabled but the header file $tproxy_header was not readable. Try one of$tproxy_usage_default$tproxy_usage_numeric$tproxy_usage_disable]) + ]) + ]) + ;; + *) + AC_MSG_RESULT([failed]) + AC_MSG_FAILURE([Invalid argument to feature tproxy.$tproxy_usage]) + ;; + esac + ]) +]) + +AC_SUBST(use_tproxy) +AC_SUBST(ip_transparent) + +TS_CHECK_LOOPBACK_IFACE +TS_CHECK_GETHOSTBYNAME_R_STYLE + +# +# use modular IOCORE +# +iocore_include_dirs="-I\$(top_srcdir)/iocore/eventsystem \ +-I\$(top_srcdir)/iocore/net \ +-I\$(top_srcdir)/iocore/aio \ +-I\$(top_srcdir)/iocore/hostdb \ +-I\$(top_srcdir)/iocore/cache \ +-I\$(top_srcdir)/iocore/cluster \ +-I\$(top_srcdir)/iocore/utils \ +-I\$(top_srcdir)/iocore/dns" + +if test "x$enable_libev" = "xyes"; then + iocore_include_dirs="${iocore_include_dirs} -I\$(top_srcdir)/libev" +fi + +# Testing Framework suffix generation hack +TFW_PACKAGE_SUFFIX=$os_type + +MGMT_DEFS="$MGMT_DEFS -DMGMT_USE_SYSLOG" + +AC_MSG_NOTICE([Build using CC=$CC]) +AC_MSG_NOTICE([Build using CXX=$CXX]) +AC_MSG_NOTICE([Build using CPP=$CPP]) +AC_MSG_NOTICE([Build using CFLAGS=$CFLAGS]) +AC_MSG_NOTICE([Build using SHARED_CFLAGS=$SHARED_CFLAGS]) +AC_MSG_NOTICE([Build using CXXFLAGS=$CXXFLAGS]) +AC_MSG_NOTICE([Build using SHARED_CXXFLAGS=$SHARED_CXXFLAGS]) +AC_MSG_NOTICE([Build using SHARED_CXXLINKFLAGS=$SHARED_LINKCXXFLAGS]) +AC_MSG_NOTICE([Build using CPPFLAGS=$CPPFLAGS]) +AC_MSG_NOTICE([Build using LDFLAGS=$LDFLAGS]) +AC_MSG_NOTICE([Build using SHARED_LDFLAGS=$SHARED_LDFLAGS]) +AC_MSG_NOTICE([Build using EXTRA_CC_LDFLAGS=$EXTRA_CC_LDFLAGS]) +AC_MSG_NOTICE([Build using EXTRA_CXX_LDFLAGS=$EXTRA_CXX_LDFLAGS]) +AC_MSG_NOTICE([Build using LIBTOOL_LINK_FLAGS=$LIBTOOL_LINK_FLAGS]) +AC_MSG_NOTICE([Build using MGMT_DEFS=$MGMT_DEFS]) +AC_MSG_NOTICE([Build using API_DEFS=$API_DEFS]) + +AC_SUBST([API_DEFS]) +AC_SUBST([CC]) +AC_SUBST([CFLAGS]) +AC_SUBST([CXX]) +AC_SUBST([CXXFLAGS]) +AC_SUBST([EXPAT_LDFLAGS]) +AC_SUBST([EXTRA_CC_LDFLAGS]) +AC_SUBST([EXTRA_CXX_LDFLAGS]) +AC_SUBST([LIBTOOL_LINK_FLAGS]) +AC_SUBST([iocore_include_dirs]) +AC_SUBST([LDFLAGS]) +AC_SUBST([MGMT_DEFS]) +AC_SUBST([SHARED_CFLAGS]) +AC_SUBST([SHARED_CXXFLAGS]) +AC_SUBST([SHARED_CXXLINKFLAGS]) +AC_SUBST([SHARED_LDFLAGS]) +AC_SUBST([TFW_PACKAGE_SUFFIX]) + +# ----------------------------------------------------------------------------- +# 6. OUTPUT FILES + +AC_CONFIG_FILES([lib/ts/ink_config.h proxy/api/ts/ts.h]) +AC_CONFIG_FILES([tools/tsxs]) +AC_CONFIG_FILES([doc/Doxyfile]) +AC_CONFIG_FILES([doc/Makefile]) +AC_CONFIG_FILES([rc/Makefile]) +AC_CONFIG_FILES([rc/trafficserver]) +AC_CONFIG_FILES([rc/trafficserver.xml]) +AC_CONFIG_FILES([rc/trafficserver.conf]) +AC_CONFIG_FILES([iocore/aio/Makefile]) +AC_CONFIG_FILES([iocore/cache/Makefile]) +AC_CONFIG_FILES([iocore/cluster/Makefile]) +AC_CONFIG_FILES([iocore/dns/Makefile]) +AC_CONFIG_FILES([iocore/eventsystem/Makefile]) +AC_CONFIG_FILES([iocore/hostdb/Makefile]) +AC_CONFIG_FILES([iocore/Makefile]) +AC_CONFIG_FILES([iocore/net/Makefile]) +AC_CONFIG_FILES([iocore/utils/Makefile]) +AC_CONFIG_FILES([lib/Makefile]) +AC_CONFIG_FILES([lib/ts/Makefile]) +AC_CONFIG_FILES([lib/records/Makefile]) +AC_CONFIG_FILES([lib/tsconfig/Makefile]) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([proxy/config/body_factory/default/Makefile]) +AC_CONFIG_FILES([proxy/config/body_factory/Makefile]) +AC_CONFIG_FILES([proxy/config/records.config.default proxy/config/storage.config.default]) +AC_CONFIG_FILES([proxy/config/Makefile]) +AC_CONFIG_FILES([proxy/congest/Makefile]) +AC_CONFIG_FILES([proxy/hdrs/Makefile]) +AC_CONFIG_FILES([proxy/http/Makefile]) +AC_CONFIG_FILES([proxy/http/remap/Makefile]) +AC_CONFIG_FILES([proxy/logging/Makefile]) +AC_CONFIG_FILES([proxy/Makefile]) +AC_CONFIG_FILES([mgmt/api/Makefile]) +AC_CONFIG_FILES([mgmt/api/remote/Makefile]) +AC_CONFIG_FILES([mgmt/api/include/Makefile]) +AC_CONFIG_FILES([mgmt/cli/Makefile]) +AC_CONFIG_FILES([mgmt/cluster/Makefile]) +AC_CONFIG_FILES([mgmt/Makefile]) +AC_CONFIG_FILES([mgmt/preparse/Makefile]) +AC_CONFIG_FILES([mgmt/stats/Makefile]) +AC_CONFIG_FILES([mgmt/tools/Makefile]) +AC_CONFIG_FILES([mgmt/utils/Makefile]) +AC_CONFIG_FILES([mgmt/web2/Makefile]) +AC_CONFIG_FILES([proxy/stats/Makefile]) +AC_CONFIG_FILES([lib/wccp/Makefile]) +AC_CONFIG_FILES([proxy/api/ts/Makefile]) +# Traffic Cop +AC_CONFIG_FILES([cop/Makefile]) +# production plugins +AC_CONFIG_FILES([plugins/Makefile]) +AC_CONFIG_FILES([plugins/conf_remap/Makefile]) +# various tools +AC_CONFIG_FILES([tools/Makefile]) +# example plugins +AC_CONFIG_FILES([example/Makefile]) +AC_CONFIG_FILES([example/add-header/Makefile]) +AC_CONFIG_FILES([example/append-transform/Makefile]) +AC_CONFIG_FILES([example/basic-auth/Makefile]) +AC_CONFIG_FILES([example/blacklist-0/Makefile]) +AC_CONFIG_FILES([example/blacklist-1/Makefile]) +AC_CONFIG_FILES([example/bnull-transform/Makefile]) +AC_CONFIG_FILES([example/cache_scan/Makefile]) +AC_CONFIG_FILES([example/file-1/Makefile]) +AC_CONFIG_FILES([example/gzip-transform/Makefile]) +AC_CONFIG_FILES([example/hello/Makefile]) +AC_CONFIG_FILES([example/null-transform/Makefile]) +AC_CONFIG_FILES([example/output-header/Makefile]) +AC_CONFIG_FILES([example/prefetch/Makefile]) +AC_CONFIG_FILES([example/protocol/Makefile]) +AC_CONFIG_FILES([example/redirect-1/Makefile]) +AC_CONFIG_FILES([example/query_remap/Makefile]) +AC_CONFIG_FILES([example/remap/Makefile]) +AC_CONFIG_FILES([example/replace-header/Makefile]) +AC_CONFIG_FILES([example/response-header-1/Makefile]) +AC_CONFIG_FILES([example/server-transform/Makefile]) +AC_CONFIG_FILES([example/session-1/Makefile]) +AC_CONFIG_FILES([example/thread-1/Makefile]) +AC_CONFIG_FILES([example/thread-pool/Makefile]) +# example app w/ standalone iocore +AC_CONFIG_FILES([example/app-template/Makefile example/app-template/records.config]) + +# ----------------------------------------------------------------------------- +# 7. autoheader TEMPLATES + +AC_OUTPUT diff --git a/contrib/install_trafficserver.sh b/contrib/install_trafficserver.sh new file mode 100644 index 00000000..d7e0ad7c --- /dev/null +++ b/contrib/install_trafficserver.sh @@ -0,0 +1,401 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# Quick Build/Test for TrafficServer +# Tested on Ubuntu Karmic 9.10, EC2 Friendly with official Canonical AMIs +# Author: Jason Giedymin +# Desc: The intent with this script is to unify a single build script with +# standard options for testing. +# +# Version Information: +# v0.1.1a - Added Debug +# v1.0.0 - Stable Release +# v1.0.1 - Added sqlite dev lib. +# v1.0.2 - EC2 Note about ephemeral storage +# - Create ephemeral storage by mimicking on non EC2 systems. +# v1.0.3 - Added fedora to list of supported distros +# v1.0.4 - Added fedora EC2 compatibility +# - Added EC2 detection, option + +# It's safe to use this in a non-ec2 environment. This directory will be +# created if it doesn't exist. If your running this on EC2, it's best not +# to change this location as this is the ephemeral drive setup by Amazon. +# For non-ec2 environments, you may change this to any location you +# desire. +EC2_EPHEMERAL=/mnt +PROJECT=trafficserver + +BRANCH=traffic/trunk +SVN_LOC=traffic-trunk.svn +SVN_HOME=http://svn.apache.org/repos/asf/incubator + +FALSE=0 +TRUE=1 +DEBUG=$FALSE +USING_EC2=$FALSE +BUILD_HOME=/usr/local +PREFIX=--prefix=$BUILD_HOME +BUILD_OPTIONS="$PREFIX" +BUILD_OPTIONS_DEBUG="--with-user=root --with-group=root --enable-debug" +BUILD_OPTIONS_FC8_EC2="--disable-eventfd" +CONFIGURE_OPTIONS="" +FULL_BUILD_PATH=$EC2_EPHEMERAL/$PROJECT/$SVN_LOC + +SUSE="suse" +FEDORA="fedora" +REDHAT="redhat" # also exists on Fedora +UBUNTU="ubuntu" +DEBIAN="debian" # also exists on Ubuntu +SLACKWARE="slackware" + + +function killAll() { + killall traffic_cop + killall traffic_manager + killall traffic_server +} + +function updateInstall() { + if [ "$DISTRIB_ID" = "$UBUNTU" ]; then + apt-get update + apt-get install -y g++ autoconf \ + make \ + libtool \ + libssl-dev \ + tcl-dev \ + libexpat1-dev \ + libpcre3-dev \ + curl + apt-get install -y subversion git git-svn + elif [ "$DISTRIB_ID" = "$FEDORA" ]; then + yum update + yum upgrade + + # Chose not to use kernel version here as FC8 xen needs more than just eventfd work + if [ $USING_EC2 = $TRUE ]; then + yum -y install subversion \ + git \ + autoconf \ + automake \ + libtool \ + gcc-c++ \ + glibc-devel \ + openssl-devel \ + tcl-devel \ + expat-devel \ + db4-devel \ + pcre \ + pcre-devel + elif [ $USING_EC2 = $FALSE ]; then + yum -y install subversion \ + git \ + autoconf \ + automake \ + libtool \ + gcc-c++ \ + glibc-devel \ + openssl-devel \ + tcl-devel \ + expat-devel \ + pcre \ + pcre-devel + fi + fi +} + +function cleanUp() { + if [ -e $EC2_EPHEMERAL/$PROJECT ]; then + rm -R $EC2_EPHEMERAL/$PROJECT + fi + + if [ ! -d $EC2_EPHEMERAL ]; then + mkdir -p $EC2_EPHEMERAL + cd $EC2_EPHEMERAL + fi +} + +function svnCheckout() { + #----------------SVN Only------------------------------ + svn checkout $SVN_HOME/$PROJECT/$BRANCH $FULL_BUILD_PATH + cd $FULL_BUILD_PATH + #------------------------------------------------------ +} + +#This is just for some dev/testing, and still in the 'works' +function dev() { + #----------------Git Only------------------------------ + git clone git://git.apache.org/trafficserver.git + cd $EC2_EPHEMERAL/$trafficserver + + #swtich to dev build + git checkout -b remotes/origin/dev + #------------------------------------------------------ +} + +function handleGroups() { + + # maybe someday some extra security can be put in around here + # and yeah, force add the group + if [ "$DISTRIB_ID" = "$UBUNTU" ]; then + addgroup nobody + elif [ "$DISTRIB_ID" = "$FEDORA" ]; then + groupadd nobody + fi +} + +function getConfigureOptions() { + configureOptions="$BUILD_OPTIONS" + + if [ $DEBUG = $TRUE ]; then + configureOptions="$configureOptions $BUILD_OPTIONS_DEBUG" + fi + + if [ $USING_EC2 = $TRUE ]; then + if [ "$DISTRIB_ID" = "$FEDORA" ]; then + configureOptions="$configureOptions $BUILD_OPTIONS_FC8_EC2" + fi + fi + + CONFIGURE_OPTIONS=$configureOptions +} + +function rebuild() { + # remake, clean, uninstall first + + if [ ! -d $FULL_BUILD_PATH ]; then + echo "Can't find $FULL_BUILD_PATH, cannot continue!"; + exit 1; + fi + + handleGroups + + cd $FULL_BUILD_PATH + autoreconf -i --force + ./configure $CONFIGURE_OPTIONS + + make clean + + # Here is where things are dumb. We don't check for + # successful builds yet. Thats in the next release. + # This is why I call it dumb. + make + make uninstall + make install +} + +function postMods() { + # Flag verbose on, we like verbose + if [ -e /etc/default/rcS ]; then + sed -i 's/VERBOSE=no/VERBOSE=yes/g' /etc/default/rcS + fi + + # Link the script for init purposes, makes things nice + if [ -e $BUILD_HOME/bin/trafficserver ]; then + ln -s -f $BUILD_HOME/bin/trafficserver /etc/init.d/trafficserver + fi +} + +function freshBuild() { + clear + echo "Starting TrafficServer Install (dumb) process..." + + killAll + updateInstall + cleanUp + svnCheckout + rebuild + postMods + + echo; + echo "TrafficServer Install (dumb) process complete." +} + +function forceBuild() { + clear + echo "Starting Build Only..." + + killAll + updateInstall + rebuild + postMods + + echo "Build complete." +} + +function flipDebug() { + if [ $DEBUG = $TRUE ]; then + DEBUG=$FALSE + elif [ $DEBUG = $FALSE ]; then + DEBUG=$TRUE + fi + + getConfigureOptions; +} + +function flipEC2() { + if [ $USING_EC2 = $TRUE ]; then + USING_EC2=$FALSE + elif [ $USING_EC2 = $FALSE ]; then + USING_EC2=$TRUE + fi + + getConfigureOptions; +} + +# Crude but it works without complex regex, and some people remove ec2/ami tools for security... +function detectEC2() { + if [ -e /etc/ec2_version ]; then #UBUNTU + USING_EC2=$TRUE + elif [ -e /etc/ec2/release-notes ]; then #FEDORA + USING_EC2=$TRUE + fi +} + +function askUser() { +usage; +echo; + +usageLine; + +read -p "" RESPONSE + +if [ "$RESPONSE" = "freshBuild" ]; then + $RESPONSE; + exit 0; +elif [ "$RESPONSE" = "forceBuild" ]; then + $RESPONSE; + exit 0; +elif [ "$RESPONSE" = "flipDebug" ]; then + $RESPONSE; + askUser; +elif [ "$RESPONSE" = "flipEC2" ]; then + $RESPONSE; + askUser; +elif [ "$RESPONSE" = "EXIT" ]; then + echo "Exiting NOW!" + exit 0; +else + #usageLine; + askUser; + return 1; +fi + +} + +function usage() { + clear + echo; + echo 'This script is used for doing quick builds & Tests for TrafficServer.'; + echo; + displayInfo; + echo; + echo "Commands:"; + echo 'freshBuild: Checkout from svn, build and install.'; + echo 'forceBuild: Do a build from previous checked out source.'; + echo 'flipDebug: Flip the current debug mode.'; + echo 'flipEC2: Flip the current EC2 mode.'; + echo 'EXIT: Exit now!'; + echo; +} + +function displayInfo() { + #Would like to make these editable in the next release. + + echo "-----------------------------------------------------------------------" + echo " Current Options " + echo "-----------------------------------------------------------------------" + echo " OS: $DISTRIB_ID" + + if [ $DEBUG = $TRUE ]; then + echo " Debug Mode: ON" + else + echo " Debug Mode: OFF" + fi + + if [ $USING_EC2 = $TRUE ]; then + echo " EC2 Mode: ON" + else + echo " EC2 Mode: OFF" + fi + + echo " Source checkout: $EC2_EPHEMERAL/$PROJECT" + echo " Branch: $BRANCH" + echo " SVN Server: $SVN_HOME" + echo " Configure Options: $CONFIGURE_OPTIONS" + echo " Full Build Path: $FULL_BUILD_PATH" + echo "-----------------------------------------------------------------------" +} + +function usageLine() { + echo; + echo "You can access the menu by calling this script or by command line." + echo "Menu usage and choices are: {freshBuild|forceBuild|flipDebug|flipEC2|EXIT}." + echo "Command line usage choices are: {freshBuild|forceBuild|freshDebugBuild|EXIT}." + echo; + echo "Notes:" + echo " - the command line has a strict debug build option." + echo " - when using the command line build, EC2 detection is automatic." + echo; +} + +#------------Main------------ + +if [ $UID != 0 ] ; then + echo "Must have root permissions to execute." + exit 1 +fi + +if [ -e /etc/SuSE-release ]; then + DISTRIB_ID=$SUSE +elif [ -e /etc/fedora-release ]; then + DISTRIB_ID=$FEDORA +elif [ -e /etc/redhat-release ]; then + DISTRIB_ID=$REDHAT # also exists on Fedora +elif [ -e /etc/lsb-release ]; then + DISTRIB_ID=$UBUNTU +elif [ -e /etc/debian-version ]; then + DISTRIB_ID=$DEBIAN # also exists on Ubuntu +elif [ -e /etc/slackware-version ]; then + DISTRIB_ID=$SLACKWARE +fi + +detectEC2; +getConfigureOptions; +displayInfo; + +case "$1" in + freshBuild) + $1; + ;; + forceBuild) + $1; + ;; + freshDebugBuild) + $DEBUG=$TRUE + freshBuild; + ;; + EXIT) + echo 'Exiting...'; + exit 0; + ;; + *) + askUser; + ;; +esac + +exit 0; diff --git a/contrib/perl/AdminClient/Changes b/contrib/perl/AdminClient/Changes new file mode 100644 index 00000000..4b586268 --- /dev/null +++ b/contrib/perl/AdminClient/Changes @@ -0,0 +1,12 @@ +Revision history for Perl extension Apache::TS::AdminClient. + +0.01 Thu Aug 12 21:25:52 2010 + - version 0.01; created by h2xs 1.23 with options '-AX Apache::TS::AdminClient' + Jira ticket: https://issues.apache.org/jira/browse/TS-418 + Changes: This includes some minor code refactoring. Major changes are the addition of pod + and package files, like Makefile.pl, so this module will go to the proper location upon install. + + +0.00 Feb 23 2007 + - original version + diff --git a/contrib/perl/AdminClient/MANIFEST b/contrib/perl/AdminClient/MANIFEST new file mode 100644 index 00000000..247ae716 --- /dev/null +++ b/contrib/perl/AdminClient/MANIFEST @@ -0,0 +1,6 @@ +Changes +Makefile.PL +MANIFEST +README +t/Apache-TS-AdminClient.t +lib/Apache/TS/AdminClient.pm diff --git a/contrib/perl/AdminClient/Makefile.PL b/contrib/perl/AdminClient/Makefile.PL new file mode 100644 index 00000000..1c13f59e --- /dev/null +++ b/contrib/perl/AdminClient/Makefile.PL @@ -0,0 +1,28 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 5.006; +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + NAME => 'Apache::TS::AdminClient', + VERSION_FROM => 'lib/Apache/TS/AdminClient.pm', # finds $VERSION + PREREQ_PM => {}, # e.g., Module::Name => 1.1 + ($] >= 5.005 ? ## Add these new keywords supported since 5.005 + (ABSTRACT_FROM => 'lib/Apache/TS/AdminClient.pm', # retrieve abstract from module + AUTHOR => 'Traffic Server Dev Team ') : ()), +); diff --git a/contrib/perl/AdminClient/README b/contrib/perl/AdminClient/README new file mode 100644 index 00000000..15075697 --- /dev/null +++ b/contrib/perl/AdminClient/README @@ -0,0 +1,48 @@ +Apache-TS-AdminClient version 0.01 +================================== + +Apache::TS::AdminClient - a perl interface to the statistics and configuration settings +stored within Apache Traffic Server. + +INSTALLATION +================================== + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES +================================== +IO::Socket::UNIX +IO::Select +Carp; + +Additionally this module requires that Apache Traffic Server is +running on localhost so it has something to talk to. + +COPYRIGHT AND LICENSE +================================== + +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +HISTORY +================================== +See 'Changes' for historic updates and revision numbers + diff --git a/contrib/perl/AdminClient/lib/Apache/TS/AdminClient.pm b/contrib/perl/AdminClient/lib/Apache/TS/AdminClient.pm new file mode 100644 index 00000000..c60517b4 --- /dev/null +++ b/contrib/perl/AdminClient/lib/Apache/TS/AdminClient.pm @@ -0,0 +1,765 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +package Apache::TS::AdminClient; + +use warnings; +use strict; + +require 5.006; + +use Carp; +use IO::Socket::UNIX; +use IO::Select; +our $VERSION = "0.01"; + +use constant { + TS_FILE_READ => 0, + TS_FILE_WRITE => 1, + TS_RECORD_SET => 2, + TS_RECORD_GET => 3, + TS_PROXY_STATE_GET => 4, + TS_PROXY_STATE_SET => 5, + TS_RECONFIGURE => 6, + TS_RESTART => 7, + TS_BOUNCE => 8, + TS_EVENT_RESOLVE => 9, + TS_EVENT_GET_MLT => 10, + TS_EVENT_ACTIVE => 11, + TS_EVENT_REG_CALLBACK => 12, + TS_EVENT_UNREG_CALLBACK => 13, + TS_EVENT_NOTIFY => 14, + TS_SNAPSHOT_TAKE => 15, + TS_SNAPSHOT_RESTORE => 16, + TS_SNAPSHOT_REMOVE => 17, + TS_SNAPSHOT_GET_MLT => 18, + TS_DIAGS => 19, + TS_STATS_RESET => 20, + TS_ENCRYPT_TO_FILE => 21 +}; + +# We treat both REC_INT and REC_COUNTER the same here +use constant { + TS_REC_INT => 0, + TS_REC_COUNTER => 0, + TS_REC_FLOAT => 2, + TS_REC_STRING => 3 +}; + +use constant { + TS_ERR_OKAY => 0, + TS_ERR_READ_FILE => 1, + TS_ERR_WRITE_FILE => 2, + TS_ERR_PARSE_CONFIG_RULE => 3, + TS_ERR_INVALID_CONFIG_RULE => 4, + TS_ERR_NET_ESTABLISH => 5, + TS_ERR_NET_READ => 6, + TS_ERR_NET_WRITE => 7, + TS_ERR_NET_EOF => 8, + TS_ERR_NET_TIMEOUT => 9, + TS_ERR_SYS_CALL => 10, + TS_ERR_PARAMS => 11, + TS_ERR_FAIL => 12 +}; + +# +# Constructor +# +sub new { + my ( $class, %args ) = @_; + my $self = {}; + + $self->{_socket_path} = $args{socket_path} || _find_socket(); + $self->{_socket} = undef; + croak +"Unable to locate socket, please pass socket_pass with the management api socket location to Apache::TS::AdminClient" + if ( !$self->{_socket_path} ); + if ( ( !-r $self->{_socket_path} ) + or ( !-w $self->{_socket_path} ) + or ( !-S $self->{_socket_path} ) ) + { + croak "Unable to open $self->{_socket_path} for reads or writes"; + + # see croak in "sub open_socket()" for other source of carp errors + } + + $self->{_select} = IO::Select->new(); + bless $self, $class; + + $self->open_socket(); + + return $self; +} + +sub _find_socket { + my @sockets_def = ( + '/usr/local/var/trafficserver/mgmtapisocket', + '/var/trafficserver/mgmtapisocket' + ); + foreach my $socket (@sockets_def) { + return $socket if ( -S $socket ); + } + return undef; +} + +# +# Destructor +# +sub DESTROY { + my $self = shift; + return $self->close_socket(); +} + +# +# Open the socket (Unix domain) +# +sub open_socket { + my $self = shift; + my %args = @_; + + if ( defined( $self->{_socket} ) ) { + if ( $args{force} || $args{reopen} ) { + $self->close_socket(); + } + else { + return undef; + } + } + + $self->{_socket} = IO::Socket::UNIX->new( + Type => SOCK_STREAM, + Peer => $self->{_socket_path} + ) or croak("Error opening socket - $@"); + + return undef unless defined( $self->{_socket} ); + $self->{_select}->add( $self->{_socket} ); + + return $self; +} + +sub close_socket { + my $self = shift; + + # if socket doesn't exist, return as there's nothing to do. + return unless defined( $self->{_socket} ); + + # gracefully close socket. + $self->{_select}->remove( $self->{_socket} ); + $self->{_socket}->close(); + $self->{_socket} = undef; + + return $self; +} + +# +# Get (read) a stat out of the local manager. Note that the assumption is +# that you are calling this with an existing stats "name". +# +sub get_stat { + my ( $self, $stat ) = @_; + my $res = ""; + my $max_read_attempts = 25; + + return undef unless defined( $self->{_socket} ); + return undef unless $self->{_select}->can_write(10); + +# This is a total hack for now, we need to wrap this into the proper mgmt API library. + $self->{_socket} + ->print( pack( "sla*", TS_RECORD_GET, length($stat) ), $stat ); + + while ( $res eq "" ) { + return undef if ( $max_read_attempts-- < 0 ); + return undef unless $self->{_select}->can_read(10); + + my $status = $self->{_socket}->sysread( $res, 1024 ); + return undef unless defined($status) || ( $status == 0 ); + + } + my @resp = unpack( "sls", $res ); + return undef unless ( scalar(@resp) == 3 ); + + if ( $resp[0] == TS_ERR_OKAY ) { + if ( $resp[2] < TS_REC_FLOAT ) { + @resp = unpack( "slsl", $res ); + return undef unless ( scalar(@resp) == 4 ); + return int( $resp[3] ); + } + elsif ( $resp[2] == TS_REC_FLOAT ) { + @resp = unpack( "slsf", $res ); + return undef unless ( scalar(@resp) == 4 ); + return $resp[3]; + } + elsif ( $resp[2] == TS_REC_STRING ) { + @resp = unpack( "slsa*", $res ); + return undef unless ( scalar(@resp) == 4 ); + return $resp[3]; + } + } + + return undef; +} + +1; + +__END__ + +#-=-=-=-=-=-=-=-= Give us some POD please =-=-=-=-=-=-=-=- + +=head1 NAME: + +Apache::TS::AdminClient - a perl interface to the statistics and configuration settings stored within Apache Traffic Server. + +=head1 SYNOPSIS + + #!/usr/bin/perl + use Apache::TS::AdminClient; + + my $cli = Apache::TS::AdminClient->new(%input); + my $string = $cli->get_stat("proxy.config.product_company"); + print "$string\n"; + + +=head1 DESCRIPTION: + +AdminClient opens a TCP connection to a unix domain socket on local disk. When the connection is established, +AdminClient will write requests to the socket and wait for Apache Traffic Server to return a response. Valid +request strings can be found in RecordsConfig.cc which is included with Apache Traffic Server source. +A list of valid request strings are included with this documentation, but this included list may not be complete +as future releases of Apache Traffic Server may include new request strings or remove existing ones. + +=head1 OPTIONS + +=head2 socket_path + +When the object is created for this module, it assumes the 'Unix Domain Socket' is at the default location of +B<'/usr/local/var/trafficserver/cli'> This can be changed when creating the object by setting B<'socket_path'>. For example: + + my $cli = AdminClient->new(socket_path=> "/dev/null"); + +would make the module look for the 'Unix Domain Socket' at /dev/null. Of course this isn't a realistic example, but can be used when +modified appropiately. + +=head2 traffic_line + +There is a command line tool included with Apache Traffic Server called traffic_line which overlaps with this module. traffic_line +can be used to read and write statistics or config settings that this module can. Hence if you don't want to write a perl one-liner to +get to this information, traffic_line is your tool. + +=head1 List of Request Strings + +The Apache Traffic Server Administration Manual will explain what these strings represent. (http://trafficserver.apache.org/docs/) + + proxy.config.accept_threads + proxy.config.task_threads + proxy.config.admin.admin_user + proxy.config.admin.autoconf.localhost_only + proxy.config.admin.autoconf.pac_filename + proxy.config.admin.autoconf_port + proxy.config.admin.autoconf.doc_root + proxy.config.admin.autoconf.wpad_filename + proxy.config.admin.cli_path + proxy.config.admin.number_config_bak + proxy.config.admin.user_id + proxy.config.alarm.abs_path + proxy.config.alarm.bin + proxy.config.alarm_email + proxy.config.alarm.script_runtime + proxy.config.bandwidth_mgmt.filename + proxy.config.bin_path + proxy.config.body_factory.enable_customizations + proxy.config.body_factory.enable_logging + proxy.config.body_factory.response_suppression_mode + proxy.config.body_factory.template_sets_dir + proxy.config.cache.agg_write_backlog + proxy.config.cache.aio_sleep_time + proxy.config.cache.alt_rewrite_max_size + proxy.config.cache.check_disk_idle + proxy.config.cache.control.filename + proxy.config.cache.dir.sync_frequency + proxy.config.cache.enable_checksum + proxy.config.cache.enable_read_while_writer + proxy.config.cache.hostdb.disable_reverse_lookup + proxy.config.cache.hostdb.sync_frequency + proxy.config.cache.hosting_filename + proxy.config.cache.ip_allow.filename + proxy.config.cache.limits.http.max_alts + proxy.config.cache.max_agg_delay + proxy.config.cache.max_disk_errors + proxy.config.cache.max_doc_size + proxy.config.cache.min_average_object_size + proxy.config.cache.volume_filename + proxy.config.cache.permit.pinning + proxy.config.cache.ram_cache_cutoff + proxy.config.cache.ram_cache.size + proxy.config.cache.select_alternate + proxy.config.cache.storage_filename + proxy.config.cache.threads_per_disk + proxy.config.cache.url_hash_method + proxy.config.cache.vary_on_user_agent + proxy.config.cache.mutex_retry_delay + proxy.config.cli_binary + proxy.config.cluster.cluster_configuration + proxy.config.cluster.cluster_load_clear_duration + proxy.config.cluster.cluster_load_exceed_duration + proxy.config.cluster.cluster_port + proxy.config.cluster.delta_thresh + proxy.config.cluster.enable_monitor + proxy.config.cluster.ethernet_interface + proxy.config.cluster.load_compute_interval_msecs + proxy.config.cluster.load_monitor_enabled + proxy.config.cluster.log_bogus_mc_msgs + proxy.config.cluster.mc_group_addr + proxy.config.cluster.mcport + proxy.config.cluster.mc_ttl + proxy.config.cluster.monitor_interval_secs + proxy.config.cluster.msecs_per_ping_response_bucket + proxy.config.cluster.peer_timeout + proxy.config.cluster.periodic_timer_interval_msecs + proxy.config.cluster.ping_history_buf_length + proxy.config.cluster.ping_latency_threshold_msecs + proxy.config.cluster.ping_response_buckets + proxy.config.cluster.ping_send_interval_msecs + proxy.config.cluster.receive_buffer_size + proxy.config.cluster.rpc_cache_cluster + proxy.config.cluster.rsport + proxy.config.cluster.send_buffer_size + proxy.config.cluster.sock_option_flag + proxy.config.cluster.startup_timeout + proxy.config.config_dir + proxy.config.cop.core_signal + proxy.config.cop.linux_min_memfree_kb + proxy.config.cop.linux_min_swapfree_kb + proxy.config.cop_name + proxy.config.core_limit + proxy.config.diags.action.enabled + proxy.config.diags.action.tags + proxy.config.diags.debug.enabled + proxy.config.diags.debug.tags + proxy.config.diags.output.alert + proxy.config.diags.output.debug + proxy.config.diags.output.diag + proxy.config.diags.output.emergency + proxy.config.diags.output.error + proxy.config.diags.output.fatal + proxy.config.diags.output.note + proxy.config.diags.output.status + proxy.config.diags.output.warning + proxy.config.diags.show_location + proxy.config.dns.failover_number + proxy.config.dns.failover_period + proxy.config.dns.lookup_timeout + proxy.config.dns.max_dns_in_flight + proxy.config.dns.nameservers + proxy.config.dns.resolv_conf + proxy.config.dns.retries + proxy.config.dns.round_robin_nameservers + proxy.config.dns.search_default_domains + proxy.config.dns.splitDNS.enabled + proxy.config.dns.splitdns.filename + proxy.config.dns.url_expansions + proxy.config.dump_mem_info_frequency + proxy.config.env_prep + proxy.config.exec_thread.autoconfig + proxy.config.exec_thread.autoconfig.scale + proxy.config.exec_thread.limit + proxy.config.header.parse.no_host_url_redirect + proxy.config.history_info_enabled + proxy.config.hostdb + proxy.config.hostdb.cluster + proxy.config.hostdb.cluster.round_robin + proxy.config.hostdb.fail.timeout + proxy.config.hostdb.filename + proxy.config.hostdb.lookup_timeout + proxy.config.hostdb.migrate_on_demand + proxy.config.hostdb.re_dns_on_reload + proxy.config.hostdb.serve_stale_for + proxy.config.hostdb.size + proxy.config.hostdb.storage_path + proxy.config.hostdb.storage_size + proxy.config.hostdb.strict_round_robin + proxy.config.hostdb.timeout + proxy.config.hostdb.ttl_mode + proxy.config.hostdb.verify_after + proxy.config.http.accept_encoding_filter_enabled + proxy.config.http.accept_encoding_filter.filename + proxy.config.http.accept_no_activity_timeout + proxy.config.http.anonymize_insert_client_ip + proxy.config.http.anonymize_other_header_list + proxy.config.http.anonymize_remove_client_ip + proxy.config.http.anonymize_remove_cookie + proxy.config.http.anonymize_remove_from + proxy.config.http.anonymize_remove_referer + proxy.config.http.anonymize_remove_user_agent + proxy.config.http.append_xforwards_header + proxy.config.http.avoid_content_spoofing + proxy.config.http.background_fill_active_timeout + proxy.config.http.background_fill_completed_threshold + proxy.config.http.cache.cache_responses_to_cookies + proxy.config.http.cache.cache_urls_that_look_dynamic + proxy.config.http.cache.enable_default_vary_headers + proxy.config.http.cache.fuzz.min_time + proxy.config.http.cache.fuzz.probability + proxy.config.http.cache.fuzz.time + proxy.config.http.cache.guaranteed_max_lifetime + proxy.config.http.cache.guaranteed_min_lifetime + proxy.config.http.cache.heuristic_lm_factor + proxy.config.http.cache.heuristic_max_lifetime + proxy.config.http.cache.heuristic_min_lifetime + proxy.config.http.cache.http + proxy.config.http.cache.ignore_accept_charset_mismatch + proxy.config.http.cache.ignore_accept_encoding_mismatch + proxy.config.http.cache.ignore_accept_language_mismatch + proxy.config.http.cache.ignore_accept_mismatch + proxy.config.http.cache.ignore_authentication + proxy.config.http.cache.ignore_client_cc_max_age + proxy.config.http.cache.ignore_client_no_cache + proxy.config.http.cache.ignore_server_no_cache + proxy.config.http.cache.ims_on_client_no_cache + proxy.config.http.cache.max_open_read_retries + proxy.config.http.cache.max_open_write_retries + proxy.config.http.cache.max_stale_age + proxy.config.http.cache.open_read_retry_time + proxy.config.http.cache.range.lookup + proxy.config.http.cache.required_headers + proxy.config.http.cache.vary_default_images + proxy.config.http.cache.vary_default_other + proxy.config.http.cache.vary_default_text + proxy.config.http.cache.when_to_add_no_cache_to_msie_requests + proxy.config.http.cache.when_to_revalidate + proxy.config.http.chunking_enabled + proxy.config.http.congestion_control.default.client_wait_interval + proxy.config.http.congestion_control.default.congestion_scheme + proxy.config.http.congestion_control.default.dead_os_conn_retries + proxy.config.http.congestion_control.default.dead_os_conn_timeout + proxy.config.http.congestion_control.default.error_page + proxy.config.http.congestion_control.default.fail_window + proxy.config.http.congestion_control.default.live_os_conn_retries + proxy.config.http.congestion_control.default.live_os_conn_timeout + proxy.config.http.congestion_control.default.max_connection + proxy.config.http.congestion_control.default.max_connection_failures + proxy.config.http.congestion_control.default.proxy_retry_interval + proxy.config.http.congestion_control.default.wait_interval_alpha + proxy.config.http.congestion_control.enabled + proxy.config.http.congestion_control.filename + proxy.config.http.congestion_control.localtime + proxy.config.http.connect_attempts_max_retries + proxy.config.http.connect_attempts_max_retries_dead_server + proxy.config.http.connect_attempts_rr_retries + proxy.config.http.connect_attempts_timeout + proxy.config.http.connect_ports + proxy.config.http.default_buffer_size + proxy.config.http.default_buffer_water_mark + proxy.config.http.doc_in_cache_skip_dns + proxy.config.http.down_server.abort_threshold + proxy.config.http.down_server.cache_time + proxy.config.http.enabled + proxy.config.http.enable_http_info + proxy.config.http.enable_http_stats + proxy.config.http.enable_url_expandomatic + proxy.config.http.errors.log_error_pages + proxy.config.http.forward.proxy_auth_to_parent + proxy.config.http.global_user_agent_header + proxy.config.http.insert_age_in_response + proxy.config.http.insert_request_via_str + proxy.config.http.insert_response_via_str + proxy.config.http.insert_squid_x_forwarded_for + proxy.config.http.keep_alive_enabled_in + proxy.config.http.keep_alive_enabled_out + proxy.config.http.keep_alive_no_activity_timeout_in + proxy.config.http.keep_alive_no_activity_timeout_out + proxy.config.http.keep_alive_post_out + proxy.config.http.log_spider_codes + proxy.config.http.negative_caching_enabled + proxy.config.http.negative_caching_lifetime + proxy.config.http.negative_revalidating_enabled + proxy.config.http.negative_revalidating_lifetime + proxy.config.http.no_dns_just_forward_to_parent + proxy.config.http.no_origin_server_dns + proxy.config.http.normalize_ae_gzip + proxy.config.http.number_of_redirections + proxy.config.http.origin_max_connections + proxy.config.http.origin_min_keep_alive_connections + proxy.config.http.origin_server_pipeline + proxy.config.http.parent_proxies + proxy.config.http.parent_proxy.connect_attempts_timeout + proxy.config.http.parent_proxy.fail_threshold + proxy.config.http.parent_proxy.file + proxy.config.http.parent_proxy.per_parent_connect_attempts + proxy.config.http.parent_proxy.retry_time + proxy.config.http.parent_proxy_routing_enable + proxy.config.http.parent_proxy.total_connect_attempts + proxy.config.http.post_connect_attempts_timeout + proxy.config.http.post_copy_size + proxy.config.http.push_method_enabled + proxy.config.http.quick_filter.mask + proxy.config.http.record_heartbeat + proxy.config.http.record_tcp_mem_hit + proxy.config.http.redirection_enabled + proxy.config.http.referer_default_redirect + proxy.config.http.referer_filter + proxy.config.http.referer_format_redirect + proxy.config.http.request_header_max_size + proxy.config.http.request_via_str + proxy.config.http.response_header_max_size + proxy.config.http.response_server_enabled + proxy.config.http.response_server_str + proxy.config.http.response_via_str + proxy.config.http.send_http11_requests + proxy.config.http.server_max_connections + proxy.config.http.server_other_ports + proxy.config.http.server_port + proxy.config.http.server_port_attr + proxy.config.http.session_auth_cache_keep_alive_enabled + proxy.config.http.share_server_sessions + proxy.config.http.slow.log.threshold + proxy.config.http.connect_ports + proxy.config.http.transaction_active_timeout_in + proxy.config.http.transaction_active_timeout_out + proxy.config.http.transaction_no_activity_timeout_in + proxy.config.http.transaction_no_activity_timeout_out + proxy.config.http_ui_enabled + proxy.config.http.uncacheable_requests_bypass_parent + proxy.config.http.user_agent_pipeline + proxy.config.http.verbose_via_str + proxy.config.http.wuts_enabled + proxy.config.icp.default_reply_port + proxy.config.icp.enabled + proxy.config.icp.icp_configuration + proxy.config.icp.icp_interface + proxy.config.icp.icp_port + proxy.config.icp.lookup_local + proxy.config.icp.multicast_enabled + proxy.config.icp.query_timeout + proxy.config.icp.reply_to_unknown_peer + proxy.config.icp.stale_icp_enabled + proxy.config.io.max_buffer_size + proxy.config.lm.pserver_timeout_msecs + proxy.config.lm.pserver_timeout_secs + proxy.config.lm.sem_id + proxy.config.local_state_dir + proxy.config.log.ascii_buffer_size + proxy.config.log.auto_delete_rolled_files + proxy.config.log.collation_host + proxy.config.log.collation_host_tagged + proxy.config.log.collation_max_send_buffers + proxy.config.log.collation_port + proxy.config.log.collation_retry_sec + proxy.config.log.collation_secret + proxy.config.log.common_log_enabled + proxy.config.log.common_log_header + proxy.config.log.common_log_is_ascii + proxy.config.log.common_log_name + proxy.config.log.custom_logs_enabled + proxy.config.log.extended2_log_enabled + proxy.config.log.extended2_log_header + proxy.config.log.extended2_log_is_ascii + proxy.config.log.extended2_log_name + proxy.config.log.extended_log_enabled + proxy.config.log.extended_log_header + proxy.config.log.extended_log_is_ascii + proxy.config.log.extended_log_name + proxy.config.log.file_stat_frequency + proxy.config.log.hostname + proxy.config.log.hosts_config_file + proxy.config.log.log_buffer_size + proxy.config.log.logfile_dir + proxy.config.log.logfile_perm + proxy.config.log.logging_enabled + proxy.config.log.max_entries_per_buffer + proxy.config.log.max_line_size + proxy.config.log.max_secs_per_buffer + proxy.config.log.max_space_mb_for_logs + proxy.config.log.max_space_mb_for_orphan_logs + proxy.config.log.max_space_mb_headroom + proxy.config.log.overspill_report_count + proxy.config.log.rolling_enabled + proxy.config.log.rolling_interval_sec + proxy.config.log.rolling_offset_hr + proxy.config.log.rolling_size_mb + proxy.config.log.sampling_frequency + proxy.config.log.search_log_enabled + proxy.config.log.search_log_filters + proxy.config.log.search_rolling_interval_sec + proxy.config.log.search_server_ip_addr + proxy.config.log.search_server_port + proxy.config.log.search_top_sites + proxy.config.log.search_url_filter + proxy.config.log.separate_host_logs + proxy.config.log.separate_icp_logs + proxy.config.log.space_used_frequency + proxy.config.log.squid_log_enabled + proxy.config.log.squid_log_header + proxy.config.log.squid_log_is_ascii + proxy.config.log.squid_log_name + proxy.config.log.xml_config_file + proxy.config.manager_binary + proxy.config.manager_name + proxy.config.net.accept_throttle + proxy.config.net.connections_throttle + proxy.config.net.enable_ink_disk_io + proxy.config.net.ink_aio_write_threads + proxy.config.net.ink_disk_io_watermark + proxy.config.net.listen_backlog + proxy.config.net.max_kqueue_len + proxy.config.net_snapshot_filename + proxy.config.net.sock_mss_in + proxy.config.net.sock_option_flag_in + proxy.config.net.sock_option_flag_out + proxy.config.net.sock_recv_buffer_size_in + proxy.config.net.sock_recv_buffer_size_out + proxy.config.net.sock_send_buffer_size_in + proxy.config.net.sock_send_buffer_size_out + proxy.config.net.defer_accept + proxy.config.net.throttle_enabled + proxy.config.output.logfile + proxy.config.ping.npacks_to_trans + proxy.config.ping.timeout_sec + proxy.config.plugin.extensions_dir + proxy.config.plugin.plugin_dir + proxy.config.plugin.plugin_mgmt_dir + proxy.config.prefetch.child_port + proxy.config.prefetch.config_file + proxy.config.prefetch.default_data_proto + proxy.config.prefetch.default_url_proto + proxy.config.prefetch.keepalive_timeout + proxy.config.prefetch.max_object_size + proxy.config.prefetch.max_recursion + proxy.config.prefetch.prefetch_enabled + proxy.config.prefetch.push_cached_objects + proxy.config.prefetch.redirection + proxy.config.prefetch.url_buffer_size + proxy.config.prefetch.url_buffer_timeout + proxy.config.process_manager.enable_mgmt_port + proxy.config.process_manager.mgmt_port + proxy.config.process_manager.timeout + proxy.config.process_state_dump_mode + proxy.config.product_company + proxy.config.product_name + proxy.config.product_vendor + proxy.config.proxy.authenticate.basic.realm + proxy.config.proxy_binary + proxy.config.proxy_binary_opts + proxy.config.proxy_name + proxy.config.remap.num_remap_threads + proxy.config.remap.use_remap_processor + proxy.config.res_track_memory + proxy.config.reverse_proxy.enabled + proxy.config.reverse_proxy.oldasxbehavior + proxy.config.server_name + proxy.config.snapshot_dir + proxy.config.socks.accept_enabled + proxy.config.socks.accept_port + proxy.config.socks.connection_attempts + proxy.config.socks.default_servers + proxy.config.socks.http_port + proxy.config.socks.per_server_connection_attempts + proxy.config.socks.server_connect_timeout + proxy.config.socks.server_fail_threshold + proxy.config.socks.server_retry_time + proxy.config.socks.server_retry_timeout + proxy.config.socks.socks_config_file + proxy.config.socks.socks_needed + proxy.config.socks.socks_timeout + proxy.config.socks.socks_version + proxy.config.srv_enabled + proxy.config.ssl.accelerator_required + proxy.config.ssl.accelerator.type + proxy.config.ssl.atalla.lib.path + proxy.config.ssl.broadcom.lib.path + proxy.config.ssl.CA.cert.filename + proxy.config.ssl.CA.cert.path + proxy.config.ssl.client.CA.cert.filename + proxy.config.ssl.client.CA.cert.path + proxy.config.ssl.client.cert.filename + proxy.config.ssl.client.certification_level + proxy.config.ssl.client.cert.path + proxy.config.ssl.client.private_key.filename + proxy.config.ssl.client.private_key.path + proxy.config.ssl.client.verify.server + proxy.config.ssl.cswift.lib.path + proxy.config.ssl.enabled + proxy.config.ssl.ncipher.lib.path + proxy.config.ssl.number.threads + proxy.config.ssl.server.cert_chain.filename + proxy.config.ssl.server.cert.filename + proxy.config.ssl.server.cert.path + proxy.config.ssl.server.cipher_suite + proxy.config.ssl.server.honor_cipher_order + proxy.config.ssl.server.multicert.filename + proxy.config.ssl.server_port + proxy.config.ssl.server.private_key.filename + proxy.config.ssl.server.private_key.path + proxy.config.stack_dump_enabled + proxy.config.start_script + proxy.config.stat_collector.interval + proxy.config.stat_collector.port + proxy.config.stats.config_file + proxy.config.stats.snap_file + proxy.config.stats.snap_frequency + proxy.config.syslog_facility + proxy.config.system.mmap_max + proxy.config.temp_dir + proxy.config.thread.default.stacksize + proxy.config.udp.free_cancelled_pkts_sec + proxy.config.udp.periodic_cleanup + proxy.config.udp.send_retries + proxy.config.update.concurrent_updates + proxy.config.update.enabled + proxy.config.update.force + proxy.config.update.max_update_state_machines + proxy.config.update.memory_use_mb + proxy.config.update.retry_count + proxy.config.update.retry_interval + proxy.config.update.update_configuration + proxy.config.url_remap.default_to_server_pac + proxy.config.url_remap.default_to_server_pac_port + proxy.config.url_remap.filename + proxy.config.url_remap.pristine_host_hdr + proxy.config.url_remap.remap_required + proxy.config.user_name + proxy.config.username.cache.enabled + proxy.config.username.cache.filename + proxy.config.username.cache.size + proxy.config.username.cache.storage_path + proxy.config.username.cache.storage_size + proxy.config.vmap.addr_file + proxy.config.vmap.down_up_timeout + proxy.config.vmap.enabled + proxy.config.watch_script + +=head1 LICENSE + + Simple Apache Traffic Server client object, to communicate with the local manager. + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=cut + +#-=-=-=-=-=-=-=-= No more POD for you =-=-=-=-=-=-=-=- diff --git a/contrib/perl/AdminClient/t/Apache-TS-AdminClient.t b/contrib/perl/AdminClient/t/Apache-TS-AdminClient.t new file mode 100644 index 00000000..c5272024 --- /dev/null +++ b/contrib/perl/AdminClient/t/Apache-TS-AdminClient.t @@ -0,0 +1,35 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl Apache-TS-AdminClient.t' + +######################### + +# change 'tests => 1' to 'tests => last_test_to_print'; + + +use Test::More tests => 2; +BEGIN { use_ok('Apache::TS::AdminClient') }; + +######################### + +# Insert your test code below, the Test::More module is use()ed here so read +# its man page ( perldoc Test::More ) for help writing this test script. + +#----- is this right or do we need to use Test::MockObject as well? +our @methods = qw(new DESTROY open_socket close_socket get_stat); +can_ok('Apache::TS::AdminClient', @methods); diff --git a/contrib/perl/ConfigMgmt/examples/forward_proxy.pl b/contrib/perl/ConfigMgmt/examples/forward_proxy.pl new file mode 100755 index 00000000..9cdd79cd --- /dev/null +++ b/contrib/perl/ConfigMgmt/examples/forward_proxy.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +use Apache::TS::Config::Records; + + +############################################################################ +# Simple script, to show some minimum configuration changes typical for +# a forward proxy. +my $fn = $ARGV[0] || "/usr/local/etc/trafficserver/records.config"; +my $recedit = new Apache::TS::Config::Records(file => $fn); + +# Definitely tweak the memory config +$recedit->set(conf => "proxy.config.cache.ram_cache.size", val => "2048M"); + +# These puts the server in forward proxy mode only. +$recedit->set(conf => "proxy.config.url_remap.remap_required", val => "0"); +$recedit->set(conf => "proxy.config.reverse_proxy.enabled", val => "0"); + +# Fine tuning, you might or might not want these +$recedit->set(conf => "proxy.config.http.transaction_active_timeout_in", val => "1800"); +$recedit->set(conf => "proxy.config.dns.dedicated_thread", val => "1"); +$recedit->set(conf => "proxy.config.http.normalize_ae_gzip", val => "1"); + +# Write out the new config file (this won't overwrite your config +$recedit->write(file => "$fn.new"); diff --git a/contrib/perl/ConfigMgmt/lib/Apache/TS/Config.pm b/contrib/perl/ConfigMgmt/lib/Apache/TS/Config.pm new file mode 100644 index 00000000..4e9e7aa6 --- /dev/null +++ b/contrib/perl/ConfigMgmt/lib/Apache/TS/Config.pm @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +package Apache::TS::Config; + +use warnings; +use strict; + +require 5.006; + +use Carp; +require Exporter; + +our @ISA = qw( Exporter ); +our @EXPORT = qw(TS_CONF_UNMODIFIED TS_CONF_MODIFIED TS_CONF_REMOVED); + +our $VERSION = "1.0"; + +# Constants +use constant { + TS_CONF_UNMODIFIED => 0, + TS_CONF_MODIFIED => 1, + TS_CONF_REMOVED => 2 +}; diff --git a/contrib/perl/ConfigMgmt/lib/Apache/TS/Config/Records.pm b/contrib/perl/ConfigMgmt/lib/Apache/TS/Config/Records.pm new file mode 100644 index 00000000..d9b00cd4 --- /dev/null +++ b/contrib/perl/ConfigMgmt/lib/Apache/TS/Config/Records.pm @@ -0,0 +1,216 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +############################################################################ +# This is a simple module to let you read, modify and add to an Apache +# Traffic Server records.config file. The idea is that you would write a +# simple script (like example below) to update a "stock" records.config with +# the changes applicable to your application. This allows you to uprade to +# a newer default config file from a new release, for example. +# +# +# #!/usr/bin/perl +# +# use Apache::TS::Config::Records; +# +# my $recedit = new Apache::TS::Config::Records(file => "/tmp/records.config"); +# $recedit->set(conf => "proxy.config.log.extended_log_enabled", +# val => "123"); +# $recedit->write(file => "/tmp/records.config.new"); +# +############################################################################ + +package Apache::TS::Config::Records; + +use Apache::TS::Config; + +use warnings; +use strict; +require 5.006; + +use Carp; + +our $VERSION = "1.0"; + + +# +# Constructor +# +sub new { + my ($class, %args) = @_; + my $self = {}; + my $fn = $args{file}; + + $fn = $args{filename} unless defined($fn); + $fn = "-" unless defined($fn); + + $self->{_filename} = $fn; # Filename to open when loading and saving + $self->{_configs} = []; # Storage, and to to preserve order + $self->{_lookup} = {}; # For faster lookup, indexes into the above + $self->{_ix} = -1; # Empty + bless $self, $class; + + $self->load() if $self->{_filename}; + + return $self; +} + + +# +# Load a records.config file +# +sub load { + my $self = shift; + my %args = @_; + my $fn = $args{file}; + + $fn = $args{filename} unless defined($fn); + $fn = $self->{_filename} unless defined($fn); + + open(FH, "<$fn") || die "Can't open file $fn for reading"; + while () { + chomp; + my @p = split(/\s+/, $_, 4); + + push(@{$self->{_configs}}, [$_, \@p, TS_CONF_UNMODIFIED]); + + ++($self->{_ix}); + next unless ($#p == 3) && (($p[0] eq "LOCAL") || ($p[0] eq "CONFIG")); + print "Warning! duplicate configuration $p[1]\n" if exists($self->{_lookup}->{$p[1]}); + + $self->{_lookup}->{$p[1]} = $self->{_ix}; + } +} + + +# +# Get an existing configuration line. This is useful for +# detecting that a config exists or not, for example. The +# return value is an anonymous array like +# +# [, [value split into 4 fields, flag if changed] +# +# You probably shouldn't modify this array. +# +sub get { + my $self = shift; + my %args = @_; + my $c = $args{conf}; + + $c = $args{config} unless defined($c); + my $ix = $self->{_lookup}->{$c}; + + return [] unless defined($ix); + return $self->{_configs}->[$ix]; +} + + +# +# Modify one configuration value +# +sub set { + my $self = shift; + my %args = @_; + my $c = $args{conf}; + my $v = $args{val}; + + $c = $args{config} unless defined($c); + $v = $args{value} unless defined($v); + + my $ix = $self->{_lookup}->{$c}; + + if (!defined($ix)) { + my $type = $args{type}; + + $type = "INT" unless defined($type); + $self->append(line => "CONFIG $c $type $v"); + } else { + my $val = $self->{_configs}->[$ix]; + + @{$val->[1]}[3] = $v; + $val->[2] = TS_CONF_MODIFIED; + } +} + + +# +# Remove a configuration from the file. +# +sub remove { + my $self = shift; + my %args = @_; + my $c = $args{conf}; + + $c = $args{config} unless defined($c); + + my $ix = $self->{_lookup}->{$c}; + + $self->{_configs}->[$ix]->[2] = TS_CONF_REMOVED if defined($ix); +} + + +# +# Append anything to the "end" of the configuration. We will assure that +# no duplicated configurations are added. Note that this takes a single +# line. +# +sub append { + my $self = shift; + my %args = @_; + my $line = $args{line}; + + my @p = split(/\s+/, $line, 4); + + # Don't appending duplicated configs + if (($#p == 3) && exists($self->{_lookup}->{$p[1]})) { + print "Warning: duplicate configuration $p[1]\n"; + return; + } + + push(@{$self->{_configs}}, [$line, \@p, TS_CONF_UNMODIFIED]); + ++($self->{_ix}); + $self->{_lookup}->{$p[1]} = $self->{_ix} if ($#p == 3) && (($p[0] eq "LOCAL") || ($p[0] eq "CONFIG")); +} + + +# +# Write the new configuration file to STDOUT, or provided +# +sub write { + my $self = shift; + my %args = @_; + my $fn = $args{file}; + + $fn = $args{filename} unless defined($fn); + $fn = "-" unless defined($fn); + + if ($fn ne "-") { + close(STDOUT); + open(STDOUT, ">$fn") || die "Can't open $fn for writing"; + } + + foreach (@{$self->{_configs}}) { + if ($_->[2] == TS_CONF_UNMODIFIED) { + print $_->[0], "\n"; + } elsif ($_->[2] == TS_CONF_MODIFIED) { + print join(" ", @{$_->[1]}), "\n"; + } else { + # No-op if removed + } + } +} diff --git a/contrib/set_trafficserver.sh b/contrib/set_trafficserver.sh new file mode 100644 index 00000000..3182858d --- /dev/null +++ b/contrib/set_trafficserver.sh @@ -0,0 +1,100 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Basic Dev base settings script. +# Desc: This script is meant for EC2 'like' Instances, however it works +# perfectly for non-ec2 installs. This script is intended as a guide and +# makes use of many of the default settings for Apache Traffic Server. +# There are a few comments which offer help for performance, please +# read them. +# Author: Jason Giedymin +# Version Information: +# v1.0.0 - Initial Release +# v1.0.1 - thread limit set to 1 +# v1.0.2 - VM specific settings, getting ready for auto benchmarking. +# v1.0.3 - Check to force /mnt based cache.db + +REMAP_FILE=/usr/local/etc/trafficserver/remap.config +STORAGE_FILE=/usr/local/etc/trafficserver/storage.config +EC2_CACHE_LOC=/mnt/trafficserver_cache + +# Base settings to use for testing and benchmarking +function recordsConfig() { + startServer + + traffic_line -s proxy.config.reverse_proxy.enabled -v 1 + traffic_line -s proxy.config.exec_thread.autoconfig -v 1 + + # Good default on a dedicated box or SMP VM. + #traffic_line -s proxy.config.exec_thread.autoconfig.scale -v 3.000000 + + # Good for a VM. + traffic_line -s proxy.config.exec_thread.autoconfig.scale -v 1.000000 + + traffic_line -s proxy.config.accept_threads -v 1 + traffic_line -s proxy.config.log.logging_enabled -v 0 + traffic_line -s proxy.config.http.server_port -v 8080 + traffic_line -s proxy.config.url_remap.pristine_host_hdr -v 1 + + # Good for a VM. + traffic_line -s proxy.config.exec_thread.limit -v 1 + + # Good default on a dedicated box or SMP VM. + traffic_line -s proxy.config.exec_thread.limit -v 2 +} + +function sampleRemap() { + echo "Modifying $REMAP_FILE ..." + + #This is purely for testing. Please supply your own ports and hosts. + echo "map http://localhost:8080 http://localhost:80" >> $REMAP_FILE + echo "map https://localhost:8443 http://localhost:443" >> $REMAP_FILE +} + +function ec2Cache() { + echo "Modifying $STORAGE_FILE ..." + + if [ ! -d $EC2_CACHE_LOC ]; then + echo "Creating $EC2_CACHE_LOC and Chown-ing $STORAGE_FILE" + mkdir -p $EC2_CACHE_LOC + chown nobody:nobody $STORAGE_FILE + fi + + sed -i 's/.\/var\/trafficserver 150994944/\/mnt\/trafficserver_cache 1073741824/g' $STORAGE_FILE +} + +function startServer() { + # If installed with the install script, use the init.d file created + if [ -x /etc/init.d/trafficserver ]; then + echo "Starting by forcing a restart of Apache TrafficServer..." + /etc/init.d/trafficserver restart + sleep 3 + fi +} + +function start() { + echo "Modifying configs..." + + sampleRemap + ec2Cache + + recordsConfig + + echo "Complete." +} + +start diff --git a/cop/Makefile.am b/cop/Makefile.am new file mode 100644 index 00000000..153fe11b --- /dev/null +++ b/cop/Makefile.am @@ -0,0 +1,37 @@ +# +# Makefile.am for the Enterprise Management module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/api/include + +MGMT_DEFS = @MGMT_DEFS@ +DEFS += $(MGMT_DEFS) + +bin_PROGRAMS = traffic_cop + +traffic_cop_SOURCES = TrafficCop.cc +traffic_cop_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +traffic_cop_LDADD = \ + $(top_builddir)/mgmt/api/remote/libtsmgmt.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + @LIBTHREAD@ @LIBSOCKET@ @LIBNSL@ @LIBTCL@ @LIBICONV@ @LIBRT@ @LIBDL@ \ + @LIBEXECINFO@ @LIBSSL@ @LIBRESOLV@ diff --git a/cop/Makefile.in b/cop/Makefile.in new file mode 100644 index 00000000..1cf69ccd --- /dev/null +++ b/cop/Makefile.in @@ -0,0 +1,742 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Makefile.am for the Enterprise Management module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = traffic_cop$(EXEEXT) +subdir = cop +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_traffic_cop_OBJECTS = TrafficCop.$(OBJEXT) +traffic_cop_OBJECTS = $(am_traffic_cop_OBJECTS) +traffic_cop_DEPENDENCIES = \ + $(top_builddir)/mgmt/api/remote/libtsmgmt.la \ + $(top_builddir)/lib/ts/libtsutil.la +traffic_cop_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(traffic_cop_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(traffic_cop_SOURCES) +DIST_SOURCES = $(traffic_cop_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ $(MGMT_DEFS) +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/api/include + +traffic_cop_SOURCES = TrafficCop.cc +traffic_cop_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +traffic_cop_LDADD = \ + $(top_builddir)/mgmt/api/remote/libtsmgmt.la \ + $(top_builddir)/lib/ts/libtsutil.la \ + @LIBTHREAD@ @LIBSOCKET@ @LIBNSL@ @LIBTCL@ @LIBICONV@ @LIBRT@ @LIBDL@ \ + @LIBEXECINFO@ @LIBSSL@ @LIBRESOLV@ + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign cop/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign cop/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +traffic_cop$(EXEEXT): $(traffic_cop_OBJECTS) $(traffic_cop_DEPENDENCIES) + @rm -f traffic_cop$(EXEEXT) + $(traffic_cop_LINK) $(traffic_cop_OBJECTS) $(traffic_cop_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrafficCop.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/cop/TrafficCop.cc b/cop/TrafficCop.cc new file mode 100644 index 00000000..84215de8 --- /dev/null +++ b/cop/TrafficCop.cc @@ -0,0 +1,1950 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "I_Layout.h" +#include "I_Version.h" +#include "mgmtapi.h" +#include "ClusterCom.h" + +#if defined(linux) +#include "sys/utsname.h" +#include "ink_killall.h" +#include +#include +#include + +union semun +{ + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ + unsigned short int *array; /* array for GETALL, SETALL */ + struct seminfo *__buf; /* buffer for IPC_INFO */ +}; +#endif // linux check + +// For debugging, turn this on. +// #define TRACE_LOG_COP 1 + +#define OPTIONS_MAX 32 +#define OPTIONS_LEN_MAX 1024 +#define MAX_PROXY_PORTS 48 + +#ifndef WAIT_ANY +#define WAIT_ANY (pid_t) -1 +#endif // !WAIT_ANY + +#define COP_FATAL LOG_ALERT +#define COP_WARNING LOG_ERR +#define COP_DEBUG LOG_DEBUG + +static const char *root_dir; +static const char *runtime_dir; +static const char *config_dir; +static char config_file[PATH_MAX]; + +static char cop_lockfile[PATH_MAX]; +static char manager_lockfile[PATH_MAX]; +static char server_lockfile[PATH_MAX]; + +#if defined(linux) +static bool check_memory_required = false; +#endif +static int check_memory_min_swapfree_kb = 10240; +static int check_memory_min_memfree_kb = 10240; + +static int syslog_facility = LOG_DAEMON; +static char syslog_fac_str[PATH_MAX] = "LOG_DAEMON"; + +static int killsig = SIGKILL; +static int coresig = 0; + +static char admin_user[80]; +static char manager_binary[PATH_MAX] = "traffic_manager"; +static char server_binary[PATH_MAX] = "traffic_server"; +static char manager_options[OPTIONS_LEN_MAX] = ""; + +static char log_file[PATH_MAX] = "traffic.out"; +static char bin_path[PATH_MAX] = "bin"; + +static int autoconf_port = 8083; +static int rs_port = 8088; +static MgmtClusterType cluster_type = NO_CLUSTER; +static int http_backdoor_port = 8084; + +static int manager_failures = 0; +static int server_failures = 0; +static int server_not_found = 0; + + +static const int sleep_time = 10; // 10 sec +static const int manager_timeout = 3 * 60; // 3 min +static const int server_timeout = 3 * 60; // 3 min + +// traffic_manager flap detection +#define MANAGER_FLAP_DETECTION 1 +#if defined(MANAGER_FLAP_DETECTION) +#define MANAGER_MAX_FLAP_COUNT 3 // if flap this many times, give up for a while +#define MANAGER_FLAP_INTERVAL_MSEC 60000 // if x number of flaps happen in this interval, declare flapping +#define MANAGER_FLAP_RETRY_MSEC 60000 // if flapping, don't try to restart until after this retry duration +static bool manager_flapping = false; // is the manager flapping? +static int manager_flap_count = 0; // how many times has the manager flapped? +static ink_hrtime manager_flap_interval_start_time = 0; // first time we attempted to start the manager in past little while) +static ink_hrtime manager_flap_retry_start_time = 0; // first time we attempted to start the manager in past little while) +#endif + +// transient syscall error timeout +#define TRANSIENT_ERROR_WAIT_MS 500 + +static const int kill_timeout = 1 * 60; // 1 min + + +static int child_pid = 0; +static int child_status = 0; +static int sem_id = 11452; + +AppVersionInfo appVersionInfo; +static InkHashTable *configTable = NULL; + + +static void +cop_log(int priority, const char *format, ...) +{ + va_list args; + char buffer[8192]; +#ifdef TRACE_LOG_COP + static FILE *trace_file = NULL; + struct timeval now; + double now_f; +#endif + + va_start(args, format); + +#ifdef TRACE_LOG_COP + if (!trace_file) + trace_file = fopen("/tmp/traffic_cop.trace", "w"); + if (trace_file) { + gettimeofday(&now, NULL); + now_f = now.tv_sec + now.tv_usec / 1000000.0f; + switch (priority) { + case COP_DEBUG: + fprintf(trace_file, "<%.4f> [DEBUG]: ", now_f); + break; + case COP_WARNING: + fprintf(trace_file, "<%.4f> [WARNING]: ", now_f); + break; + case COP_FATAL: + fprintf(trace_file, "<%.4f> [FATAL]: ", now_f); + break; + default: + fprintf(trace_file, "<%.4f> [unknown]: ", now_f); + break; + } + + va_list args_tmp; + va_copy(args_tmp, args); + + vfprintf(trace_file, format, args_tmp); + fflush(trace_file); + + va_end(args_tmp); + } +#endif + + vsprintf(buffer, format, args); + syslog(priority, "%s", buffer); + + va_end(args); +} + +void +chown_file_to_user(const char *file, const char *user) +{ + struct passwd *pwd = NULL; + + if (user && *user) { + if (*user == '#') { + int uid = atoi(user + 1); + if (uid == -1) { + // XXX: Can this call hapen after setuid? + uid = (int)geteuid(); + } + pwd = getpwuid((uid_t)uid); + } + else { + pwd = getpwnam(user); + } + } + if (pwd) { + if (chown(file, pwd->pw_uid, pwd->pw_gid) < 0) { + //cop_log(COP_FATAL, "cop couldn't chown the file: %s\n", file); + } + } else { + cop_log(COP_FATAL, "can't get passwd entry for the admin user\n"); + } +} +static void +sig_child(int signum) +{ + NOWARN_UNUSED(signum); + int pid = 0; + int status = 0; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering sig_child(%d)\n", signum); +#endif + for (;;) { + pid = waitpid(WAIT_ANY, &status, WNOHANG); + + if (pid <= 0) { + break; + } + // TSqa03086 - We can not log the child status signal from + // the signal handler since syslog can deadlock. Record + // the pid and the status in a global for logging + // next time through the event loop. We will occasionally + // lose some information if we get two sig childs in rapid + // succession + child_pid = pid; + child_status = status; + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving sig_child(%d)\n", signum); +#endif +} + +// TODO: Use positive instead negative checks +// This should be #if defined(solaris) +static void +#if !defined(linux) && !defined(freebsd) && !defined(darwin) +sig_fatal(int signum, siginfo_t * t, void *c) +#else +sig_fatal(int signum) +#endif +{ +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering sig_fatal(%d)\n", signum); +#endif +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + if (t) { + if (t->si_code <= 0) { + cop_log(COP_FATAL, "cop received fatal user signal [%d] from" + " pid [%d] uid [%d]\n", signum, t->si_pid, t->si_uid); + } else { + cop_log(COP_FATAL, "cop received fatal kernel signal [%d], " "reason [%d]\n", signum, t->si_code); + } + } else { +#endif + cop_log(COP_FATAL, "cop received fatal signal [%d]\n", signum); +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + } +#endif +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving sig_fatal(%d)\n", signum); +#endif + abort(); +} + +static void +#if !defined(linux) && !defined(freebsd) && !defined(darwin) +sig_alarm_warn(int signum, siginfo_t * t, void *c) +#else +sig_alarm_warn(int signum) +#endif +{ + NOWARN_UNUSED(signum); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering sig_alarm_warn(%d)\n", signum); +#endif + cop_log(COP_WARNING, "unable to kill traffic_server for the last" " %d seconds\n", kill_timeout); + + // Set us up for another alarm + alarm(kill_timeout); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving sig_alarm_warn(%d)\n", signum); +#endif +} + +static void +sig_ignore(int signum) +{ + NOWARN_UNUSED(signum); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering sig_ignore(%d)\n", signum); +#endif + // No code here yet... +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving sig_ignore(%d)\n", signum); +#endif +} + +static void +set_alarm_death() +{ + struct sigaction action; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering set_alarm_death()\n"); +#endif +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + action.sa_handler = NULL; + action.sa_sigaction = sig_fatal; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; +#else + action.sa_handler = sig_fatal; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; +#endif + + sigaction(SIGALRM, &action, NULL); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving set_alarm_death()\n"); +#endif +} + +static void +set_alarm_warn() +{ + struct sigaction action; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering set_alarm_warn()\n"); +#endif +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + action.sa_handler = NULL; + action.sa_sigaction = sig_alarm_warn; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; +#else + action.sa_handler = sig_alarm_warn; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; +#endif + + sigaction(SIGALRM, &action, NULL); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving set_alarm_warn()\n"); +#endif + +} + +static void +process_syslog_config(void) +{ + int new_fac; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering process_syslog_config()\n"); +#endif + new_fac = facility_string_to_int(syslog_fac_str); + + if (new_fac >= 0 && new_fac != syslog_facility) { + closelog(); + openlog("traffic_cop", LOG_PID | LOG_NDELAY | LOG_NOWAIT, new_fac); + syslog_facility = new_fac; + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving process_syslog_config()\n"); +#endif +} + +// Paranoia: wrap the process termination call within alarms +// so that when the killing call doesn't return we +// will still wake up +// FIX THIS: We don't know what to do on NT yet. +static void +safe_kill(const char *lockfile_name, const char *pname, bool group) +{ + Lockfile lockfile(lockfile_name); + chown_file_to_user(lockfile_name, admin_user); + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering safe_kill(%s, %s, %d)\n", lockfile_name, pname, group); +#endif + set_alarm_warn(); + alarm(kill_timeout); + + if (group == true) { + lockfile.KillGroup(killsig, coresig, pname); + } else { + lockfile.Kill(killsig, coresig, pname); + } + chown_file_to_user(lockfile_name, admin_user); + + alarm(0); + set_alarm_death(); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving safe_kill(%s, %s, %d)\n", lockfile_name, pname, group); +#endif +} + + +// ink_hrtime milliseconds() +// +// Returns the result of gettimeofday converted to +// one 64bit int +// +static ink_hrtime +milliseconds(void) +{ + struct timeval curTime; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering milliseconds()\n"); +#endif + ink_gethrtimeofday(&curTime, NULL); + // Make liberal use of casting to ink_hrtime to ensure the + // compiler does not truncate our result +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving milliseconds()\n"); +#endif + return ((ink_hrtime) curTime.tv_sec * 1000) + ((ink_hrtime) curTime.tv_usec / 1000); +} + +static void +millisleep(int ms) +{ + struct timespec ts; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering millisleep(%d)\n", ms); +#endif + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms - ts.tv_sec * 1000) * 1000 * 1000; + nanosleep(&ts, NULL); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving millisleep(%d)\n", ms); +#endif +} + +static bool +transient_error(int error, int wait_ms) +{ +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering transient_error(%d, %d)\n", error, wait_ms); +#endif + + // switch cases originally from UnixNex::accept_error_seriousness() + switch (error) { + case EAGAIN: + case EINTR: + break; + + case ENFILE: + case EMFILE: + case ENOMEM: +#ifdef ENOBUFS + case ENOBUFS: +#endif +#if !defined(freebsd) && !defined(darwin) + case ENOSR: +#endif + if (wait_ms) + millisleep(wait_ms); + break; + + default: +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving transient_error(%d, %d) --> false\n", error, wait_ms); +#endif + return false; + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving transient_error(%d, %d) --> true\n", error, wait_ms); +#endif + return true; +} + +static void +build_config_table(FILE * fp) +{ + int i; + char *p; + char buffer[4096], varname[1024]; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering build_config_table(%d)\n", fp); +#endif + if (configTable != NULL) { + ink_hash_table_destroy_and_free_values(configTable); + } + configTable = ink_hash_table_create(InkHashTableKeyType_String); + + while (!feof(fp)) { + + if (!fgets(buffer, 4096, fp)) { + break; + } + // replace newline with null termination + p = strchr(buffer, '\n'); + if (p) { + *p = '\0'; + } + // skip beginning line spaces + p = buffer; + while (*p != '\0' && isspace(*p)) { + p++; + } + + // skip blank or comment lines + if (*p == '#' || *p == '\0') { + continue; + } + // skip the first word + while (*p != '\0' && !isspace(*p)) { + p++; + } + + while (*p != '\0' && isspace(*p)) { + p++; + } + + for (i = 0; *p != '\0' && !isspace(*p); i++, p++) { + varname[i] = *p; + } + varname[i] = '\0'; + + ink_hash_table_insert(configTable, varname, xstrdup(buffer)); + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving build_config_table(%d)\n", fp); +#endif +} + +static void +read_config_string(const char *str, char *val, size_t val_len, bool miss_ok = false) +{ + InkHashTableValue hval; + char *p, *buf; + + if (!ink_hash_table_lookup(configTable, str, &hval)) { + if (miss_ok) + return; + else + goto ConfigStrFatalError; + } + buf = (char *) hval; + + p = strstr(buf, str); + if (!p) { + goto ConfigStrFatalError; + } + + p += strlen(str); + p = strstr(p, "STRING"); + if (!p) { + goto ConfigStrFatalError; + } + + p += sizeof("STRING") - 1; + while (*p && isspace(*p)) { + p += 1; + } + + ink_strncpy(val, p, val_len); + return; + +ConfigStrFatalError: + cop_log(COP_FATAL, "could not find variable string %s in records.config\n", str); + exit(1); +} + +static void +read_config_int(const char *str, int *val, bool miss_ok = false) +{ + InkHashTableValue hval; + char *p, *buf; + + if (!ink_hash_table_lookup(configTable, str, &hval)) { + if (miss_ok) + return; + else + goto ConfigIntFatalError; + } + buf = (char *) hval; + + p = strstr(buf, str); + if (!p) { + goto ConfigIntFatalError; + } + + p += strlen(str); + p = strstr(p, "INT"); + if (!p) { + goto ConfigIntFatalError; + } + + p += sizeof("INT") - 1; + while (*p && isspace(*p)) { + p += 1; + } + + *val = atoi(p); + return; + +ConfigIntFatalError: + cop_log(COP_FATAL, "could not find variable integer %s in records.config\n", str); + exit(1); +} + + +static void +read_config() +{ + FILE *fp; + struct stat stat_buf; + static time_t last_mod = 0; + char log_dir[PATH_MAX]; + char log_filename[PATH_MAX]; + int tmp_int; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering read_config()\n"); +#endif + // coverity[fs_check_call] + if (stat(config_file, &stat_buf) == -1) { + cop_log(COP_FATAL, "could not stat \"%s\"\n", config_file); + exit(1); + } + + if (stat_buf.st_mtime <= last_mod) { // no change, no need to re-read + return; + } else { + last_mod = stat_buf.st_mtime; + } + + // we stat the file to get the mtime and only open a read if it has changed, so disable the toctou coverity check + // coverity[toctou] + fp = fopen(config_file, "r"); + if (!fp) { + cop_log(COP_FATAL, "could not open \"%s\"\n", config_file); + exit(1); + } + + build_config_table(fp); + fclose(fp); + + read_config_string("proxy.config.manager_binary", manager_binary, sizeof(manager_binary), true); + read_config_string("proxy.config.admin.user_id", admin_user, sizeof(admin_user)); + read_config_string("proxy.config.proxy_binary", server_binary, sizeof(server_binary), true); + + read_config_string("proxy.config.bin_path", bin_path, sizeof(bin_path), true); + Layout::get()->relative(bin_path, sizeof(bin_path), bin_path); + if (access(bin_path, R_OK) == -1) { + ink_strlcpy(bin_path, Layout::get()->bindir, sizeof(bin_path)); + if (access(bin_path, R_OK) == -1) { + cop_log(COP_FATAL, "could not access() \"%s\"\n", bin_path); + cop_log(COP_FATAL, "please set 'proxy.config.bin_path' \n"); + } + } + read_config_string("proxy.config.log.logfile_dir", log_dir, sizeof(log_dir)); + Layout::get()->relative(log_dir, sizeof(log_dir), log_dir); + if (access(log_dir, W_OK) == -1) { + ink_strlcpy(log_dir, Layout::get()->logdir, sizeof(log_dir)); + if (access(log_dir, W_OK) == -1) { + cop_log(COP_FATAL, "could not access() \"%s\"\n", log_dir); + cop_log(COP_FATAL, "please set 'proxy.config.log.logfile_dir' \n"); + } + } + read_config_string("proxy.config.output.logfile", log_filename, sizeof(log_filename)); + Layout::relative_to(log_file, sizeof(log_file), log_dir, log_filename); + read_config_int("proxy.config.process_manager.mgmt_port", &http_backdoor_port, true); + read_config_int("proxy.config.admin.autoconf_port", &autoconf_port, true); + read_config_int("proxy.config.cluster.rsport", &rs_port, true); + read_config_int("proxy.config.lm.sem_id", &sem_id, true); + + read_config_int("proxy.local.cluster.type", &tmp_int); + cluster_type = static_cast(tmp_int); + + read_config_string("proxy.config.syslog_facility", syslog_fac_str, sizeof(syslog_fac_str), true); + process_syslog_config(); + read_config_int("proxy.config.cop.core_signal", &coresig, true); + + read_config_int("proxy.config.cop.linux_min_swapfree_kb", &check_memory_min_swapfree_kb, true); + read_config_int("proxy.config.cop.linux_min_memfree_kb", &check_memory_min_memfree_kb, true); + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving read_config()\n"); +#endif +} + + +static void +spawn_manager() +{ + char prog[PATH_MAX]; + char *options[OPTIONS_MAX]; + char *last; + char *tok; + int log_fd; + int err; + int key; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering spawn_manager()\n"); +#endif + // Clean up shared memory segments. + if (sem_id > 0) { + key = sem_id; + } else { + key = 11452; + } + for (;; key++) { + err = semget(key, 1, 0666); + if (err < 0) { + break; + } +#if defined(solaris) || defined(kfreebsd) || defined(unknown) + err = semctl(err, 1, IPC_RMID); +#else + union semun dummy_semun; + memset(&dummy_semun, 0, sizeof(dummy_semun)); + err = semctl(err, 1, IPC_RMID, dummy_semun); +#endif + if (err < 0) { + break; + } + } + + Layout::relative_to(prog, sizeof(prog), bin_path, manager_binary); + if (access(prog, R_OK | X_OK) == -1) { + cop_log(COP_FATAL, "unable to access() manager binary \"%s\" [%d '%s']\n", prog, errno, strerror(errno)); + exit(1); + } + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "spawn_manager: Launching %s with options '%s'\n", + prog, manager_options); +#endif + int i; + for (i = 0; i < OPTIONS_MAX; i++) { + options[i] = NULL; + } + options[0] = prog; + i = 1; + tok = ink_strtok_r(manager_options, " ", &last); + options[i++] = tok; + if (tok != NULL) { + while (i < OPTIONS_MAX && (tok = ink_strtok_r(NULL, " ", &last))) { + options[i++] = tok; + } + } + + // Move any traffic.out that we can not write to, out + // of the way (TSqa2232) + // coverity[fs_check_call] + if (access(log_file, W_OK) < 0 && errno == EACCES) { + char old_log_file[PATH_MAX]; + snprintf(old_log_file, sizeof(old_log_file), "%s.old", log_file); + // coverity[toctou] + rename(log_file, old_log_file); + cop_log(COP_WARNING, "rename %s to %s as it is not accessable.\n", log_file, old_log_file); + } + // coverity[toctou] + if ((log_fd = open(log_file, O_WRONLY | O_APPEND | O_CREAT, 0640)) < 0) { + cop_log(COP_WARNING, "unable to open log file \"%s\" [%d '%s']\n", log_file, errno, strerror(errno)); + } + + err = fork(); + if (err == 0) { + if (log_fd >= 0) { + dup2(log_fd, STDOUT_FILENO); + dup2(log_fd, STDERR_FILENO); + close(log_fd); + } + + err = execv(prog, options); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Somehow execv(%s, options, NULL) failed (%d)!\n", prog, err); +#endif + exit(1); + } else if (err == -1) { + cop_log(COP_FATAL, "unable to fork [%d '%s']\n", errno, strerror(errno)); + exit(1); + } else { + close(log_fd); + } + + manager_failures = 0; +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving spawn_manager()\n"); +#endif +} + + + +static int +poll_read(int fd, int timeout) +{ + struct pollfd info; + int err; + + info.fd = fd; + info.events = POLLIN; + info.revents = 0; + + do { + err = poll(&info, 1, timeout); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if ((err > 0) && (info.revents & POLLIN)) { + return 1; + } + + return err; +} + +static int +poll_write(int fd, int timeout) +{ + struct pollfd info; + int err; + + info.fd = fd; + info.events = POLLOUT; + info.revents = 0; + + do { + err = poll(&info, 1, timeout); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + + if ((err > 0) && (info.revents & POLLOUT)) { + return 1; + } + + return err; +} + +static int +open_socket(int port, const char *ip = NULL, char *ip_to_bind = NULL) +{ + + int sock = 0; + struct addrinfo hints; + struct addrinfo *result = NULL; + struct addrinfo *result_to_bind = NULL; + char port_str[8] = {'\0'}; + int err = 0; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering open_socket(%d, %s, %s)\n", port, ip, ip_to_bind); +#endif + if (!ip) { + ip = "127.0.0.1"; + } + + snprintf(port_str, sizeof(port_str), "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + err = getaddrinfo(ip, port_str, &hints, &result); + if (err != 0) { + cop_log (COP_WARNING, "(test) unable to get address info [%d %s] at ip %s, port %s\n", err, gai_strerror(err), ip, port_str); + goto getaddrinfo_error; + } + + // Create a socket + do { + sock = socket(result->ai_family, result->ai_socktype, 0); + } while ((sock < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if (sock < 0) { + cop_log(COP_WARNING, "(test) unable to create socket [%d '%s']\n", errno, strerror(errno)); + goto error; + } + + if (ip_to_bind) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = result->ai_family; + hints.ai_socktype = result->ai_socktype; + + err = getaddrinfo(ip_to_bind, NULL, &hints, &result_to_bind); + if (err != 0) { + cop_log (COP_WARNING, "(test) unable to get address info [%d %s] at ip %s\n", err, gai_strerror(err), ip_to_bind); + freeaddrinfo(result_to_bind); + goto error; + } + + if (safe_bind(sock, result_to_bind->ai_addr, result_to_bind->ai_addrlen) < 0) { + cop_log (COP_WARNING, "(test) unable to bind socket [%d '%s']\n", errno, strerror (errno)); + } + + freeaddrinfo(result_to_bind); + } + + // Put the socket in non-blocking mode...just to be extra careful + // that we never block. + do { + err = fcntl(sock, F_SETFL, O_NONBLOCK); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if (err < 0) { + cop_log(COP_WARNING, "(test) unable to put socket in non-blocking mode [%d '%s']\n", errno, strerror(errno)); + goto error; + } + // Connect to the specified port on the machine we're running on. + do { + err = connect(sock, result->ai_addr, result->ai_addrlen); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if ((err < 0) && (errno != EINPROGRESS)) { + cop_log(COP_WARNING, "(test) unable to connect to server [%d '%s'] at port %d\n", errno, strerror(errno), port); + goto error; + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving open_socket(%d, %s, %s) --> %d\n", port, ip, ip_to_bind, sock); +#endif + freeaddrinfo(result); + return sock; + +error: + if (sock >= 0) { + close_socket(sock); + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving open_socket(%d, %s, %s) --> %d\n", port, ip, ip_to_bind, -1); +#endif +getaddrinfo_error: + freeaddrinfo(result); + return -1; +} + +static int +test_port(int port, const char *request, char *buffer, int bufsize, + int64_t test_timeout, char *ip = NULL, char *ip_to_bind = NULL) +{ + int64_t start_time, timeout; + int sock; + size_t length = strlen(request); + int64_t err, idx; + + start_time = milliseconds(); + + sock = open_socket(port, ip, ip_to_bind); + if (sock < 0) { + goto error; + } + + timeout = milliseconds() - start_time; + if (timeout >= test_timeout) { + cop_log(COP_WARNING, "(test) timeout occurred [%" PRId64 " ms]\n", timeout); + goto error; + } + timeout = test_timeout - timeout; + + err = poll_write(sock, timeout); + if (err < 0) { + cop_log(COP_WARNING, "(test) poll write failed [%d '%s']\n", errno, strerror(errno)); + goto error; + } else if (err == 0) { + cop_log(COP_WARNING, "(test) write timeout [%" PRId64 " ms]\n", timeout); + goto error; + } + // Write the request to the server. + while (length > 0) { + do { + err = write(sock, request, length); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if (err < 0) { + cop_log(COP_WARNING, "(test) write failed [%d '%s']\n", errno, strerror(errno)); + goto error; + } + + request += err; + length -= err; + } + + idx = 0; + for (;;) { + if (idx >= bufsize) { + cop_log(COP_WARNING, "(test) response is too large [%d]\n", idx); + goto error; + } + + timeout = milliseconds() - start_time; + if (timeout >= test_timeout) { + cop_log(COP_WARNING, "(test) timeout occurred [%" PRId64 " ms]\n", timeout); + goto error; + } + timeout = test_timeout - timeout; + + err = poll_read(sock, timeout); + if (err < 0) { + cop_log(COP_WARNING, "(test) poll read failed [%d '%s']\n", errno, strerror(errno)); + goto error; + } else if (err == 0) { + cop_log(COP_WARNING, "(test) read timeout [%" PRId64 " ]\n", timeout); + goto error; + } + + do { + err = read(sock, &buffer[idx], bufsize - idx); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if (err < 0) { + cop_log(COP_WARNING, "(test) read failed [%d '%s']\n", errno, strerror(errno)); + goto error; + } else if (err == 0) { + buffer[idx] = '\0'; + close(sock); + return 0; + } else { + idx += err; + } + } + +error: + if (sock >= 0) { + close_socket(sock); + } + return -1; +} + +static int +read_manager_string(const char *variable, char *value) +{ + char buffer[4096]; + char request[1024]; + char *p, *e; + int err; + + snprintf(request, sizeof(request), "read %s\n", variable); + + err = test_port(rs_port, request, buffer, 4095, manager_timeout * 1000); + if (err < 0) { + return err; + } + + p = strstr(buffer, variable); + if (!p) { + cop_log(COP_WARNING, "(manager test) could not find record " "name in response\n"); + return -1; + } + p += strlen(variable); + + p = strstr(p, "Val:"); + if (!p) { + cop_log(COP_WARNING, "(manager test) could not find record " "value in response\n"); + return -1; + } + p += sizeof("Val:") - 1; + + while (*p && (*p != '\'')) { + p += 1; + } + + if (*p == '\0') { + cop_log(COP_WARNING, "(manager test) could not find properly " "delimited value in response\n"); + return -1; + } + p += 1; + + e = p; + while (*e && (*e != '\'')) { + e += 1; + } + + if (*e != '\'') { + cop_log(COP_WARNING, "(manager test) could not find properly " "delimited value in response\n"); + return -1; + } + + strncpy(value, p, e - p); + value[e - p] = '\0'; + + return 0; +} + +static int +read_manager_int(const char *variable, int *value) +{ + char buffer[4096]; + char request[1024]; + char *p; + int err; + + snprintf(request, sizeof(request), "read %s\n", variable); + + err = test_port(rs_port, request, buffer, 4095, manager_timeout * 1000); + if (err < 0) { + return err; + } + + p = strstr(buffer, variable); + if (!p) { + cop_log(COP_WARNING, "(manager test) could not find record " "name in response\n"); + return -1; + } + p += strlen(variable); + + p = strstr(p, "Val:"); + if (!p) { + cop_log(COP_WARNING, "(manager test) could not find record " "value in response\n"); + return -1; + } + p += sizeof("Val:") - 1; + + while (*p && (*p != '\'')) { + p += 1; + } + + if (*p == '\0') { + cop_log(COP_WARNING, "(manager test) could not find properly " "delimited value in response\n"); + return -1; + } + p += 1; + + *value = 0; + while (isdigit(*p)) { + *value = *value * 10 + (*p - '0'); + p += 1; + } + + if (*p != '\'') { + cop_log(COP_WARNING, "(manager test) could not find properly " "delimited value in response\n"); + return -1; + } + return 0; +} + +static int +read_mgmt_cli_int(const char *variable, int *value) +{ + TSInt val; + + if (TSRecordGetInt(variable, &val) != TS_ERR_OKAY) { + cop_log(COP_WARNING, "(cli test) could not communicate with mgmt cli\n"); + return -1; + } + *value = val; + return 0; +} + + +static int +test_rs_port() +{ + char buffer[4096]; + int err; + + err = read_manager_string("proxy.config.manager_binary", buffer); + if (err < 0) { + return err; + } + + if (strcmp(buffer, manager_binary) != 0) { + cop_log(COP_WARNING, "(manager test) bad response value\n"); + return -1; + } + + return 0; +} + + +static int +test_mgmt_cli_port() +{ + TSString val; + int ret = 0; + + if (TSRecordGetString("proxy.config.manager_binary", &val) != TS_ERR_OKAY) { + cop_log(COP_WARNING, "(cli test) unable to retrieve manager_binary\n"); + ret = -1; + } else { + if (strcmp(val, manager_binary) != 0) { + cop_log(COP_WARNING, "(cli test) bad response value, got %s, expected %s\n", val, manager_binary); + ret = -1; + } + } + + if (val) + TSfree(val); + return ret; +} + + +static int +test_http_port(int port, char *request, int timeout, char *ip = NULL, char *ip_to_bind = NULL) +{ + char buffer[4096]; + char *p; + int err; + + err = test_port(port, request, buffer, 4095, timeout, ip, ip_to_bind); + if (err < 0) { + return err; + } + + p = buffer; + + if (strncmp(p, "HTTP/", 5) != 0) { + cop_log(COP_WARNING, "(http test) received malformed response\n"); + return -1; + } + + p += 5; + while (*p && !isspace(*p)) { + p += 1; + } + + while (*p && isspace(*p)) { + p += 1; + } + + if (strncmp(p, "200", 3) != 0) { + char pstatus[4] = { '\0', '\0', '\0', '\0' }; + strncpy(pstatus, p, 3); + cop_log(COP_WARNING, "(http test) received non-200 status(%s)\n", pstatus); + return -1; + } + + p = strstr(p, "\r\n\r\n"); + if (!p) { + cop_log(COP_WARNING, "(http test) could not find end of header\n"); + return -1; + } + + p += 4; + while (*p) { + if (strncmp(p, "abcdefghijklmnopqrstuvwxyz", 26) != 0) { + cop_log(COP_WARNING, "(http test) corrupted response data\n"); + return -1; + } + + p += 26; + while (*p && (*p != '\n')) { + p += 1; + } + p += 1; + } + + return 0; +} + +static int +test_server_http_port() +{ + char request[1024] = {'\0'}; + static char localhost[] = "127.0.0.1"; + + // Generate a request for a the 'synthetic.txt' document the manager + // servers up on the autoconf port. + snprintf(request, sizeof(request), "GET http://127.0.0.1:%d/synthetic.txt HTTP/1.0\r\n\r\n", autoconf_port); + + return test_http_port(http_backdoor_port, request, server_timeout * 1000, localhost, localhost); +} + +static int +heartbeat_manager() +{ + int err; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering heartbeat_manager()\n"); +#endif + // the CLI, and the rsport if cluster is enabled. + err = test_mgmt_cli_port(); + if ((0 == err) && (cluster_type != NO_CLUSTER)) + err = test_rs_port(); + + if (err < 0) { + if (err < 0) { + manager_failures += 1; + cop_log(COP_WARNING, "manager heartbeat [variable] failed [%d]\n", manager_failures); + + if (manager_failures > 1) { + manager_failures = 0; + cop_log(COP_WARNING, "killing manager\n"); + safe_kill(manager_lockfile, manager_binary, true); + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving heartbeat_manager() --> %d\n", err); +#endif + return err; + } + } + + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving heartbeat_manager() --> %d\n", err); +#endif + return err; +} + +static int +heartbeat_server() +{ + int err; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering heartbeat_server()\n"); +#endif + err = test_server_http_port(); + + if (err < 0) { + // If the test failed, increment the count of the number of + // failures. We don't kill the server the first time the test + // fails because we might just have gotten caught in a race + // where we decided to do the test because we thought the + // server was up even though somebody was in the process of + // bringing it down. The "server_up" function will reset + // 'server_failures' if it determines the server is down. + + server_failures += 1; + cop_log(COP_WARNING, "server heartbeat failed [%d]\n", server_failures); + + // If this is the second time that the server test has failed + // we kill the server. + if (server_failures > 1) { + server_failures = 0; + cop_log(COP_WARNING, "killing server\n"); + + // TSqa02622: Change the ALRM signal handler while + // trying to kill the process since if a core + // is being written, it could take a long time + // Set a new alarm so that we can print warnings + // if it is taking too long to kill the server + // + safe_kill(server_lockfile, server_binary, false); + } + } else { + if (server_failures) + cop_log(COP_WARNING, "server heartbeat succeeded\n"); + server_failures = 0; + } + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving heartbeat_server() --> %d\n", err); +#endif + return err; +} + +static int +server_up() +{ + static int old_val = 0; + int val = -1; + int err; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering server_up()\n"); +#endif + if (cluster_type != NO_CLUSTER) { + err = read_manager_int("proxy.node.proxy_running", &val); + if (err < 0) { + cop_log(COP_WARNING, "could not contact manager, " "assuming server is down\n"); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving server_up() --> 0\n"); +#endif + return 0; + } + } else { + err = read_mgmt_cli_int("proxy.node.proxy_running", &val); + if (err < 0) { + cop_log(COP_WARNING, "could not contact manager, " "assuming server is down\n"); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving server_up() --> 0\n"); +#endif + return 0; + } + } + + if (val != old_val) { + server_failures = 0; + server_not_found = 0; + old_val = val; + } + + if (val == 1) { +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving server_up() --> 1\n"); +#endif + return 1; + } else { +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving server_up() --> 0\n"); +#endif + return 0; + } +} + + +// | state | status | action +// --------|---------|----------|--------------- +// manager | up | ok | nothing +// server | up | ok | +// --------|---------|----------|--------------- +// manager | up | bad | kill manager +// server | up | ? | +// --------|---------|----------|--------------- +// manager | up | ok | kill manager +// server | down | ? | +// --------|---------|----------|--------------- +// manager | up | ok | kill server +// server | up | bad | + + +static void +check_programs() +{ + int err; + pid_t holding_pid; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering check_programs()\n"); +#endif + + // Try to get the manager lock file. If we succeed in doing this, + // it means there is no manager running. + Lockfile manager_lf(manager_lockfile); + err = manager_lf.Open(&holding_pid); + chown_file_to_user(manager_lockfile, admin_user); +#if defined(linux) + // if lockfile held, but process doesn't exist, killall and try again + if (err == 0) { + if (kill(holding_pid, 0) == -1) { + cop_log(COP_WARNING, "%s's lockfile is held, but its pid (%d) is missing;" + " killing all processes named '%s' and retrying\n", manager_binary, holding_pid, manager_binary); + ink_killall(manager_binary, killsig); + sleep(1); // give signals a chance to be received + err = manager_lf.Open(&holding_pid); + } + } +#endif + if (err > 0) { + // 'lockfile_open' returns the file descriptor of the opened + // lockfile. We need to close this before spawning the + // manager so that the manager can grab the lock. + manager_lf.Close(); + +#if !defined(MANAGER_FLAP_DETECTION) + // Make sure we don't have a stray traffic server running. + cop_log(COP_WARNING, "traffic_manager not running, making sure traffic_server is dead\n"); + safe_kill(server_lockfile, server_binary, false); + // Spawn the manager. + cop_log(COP_WARNING, "spawning traffic_manager\n"); + spawn_manager(); +#else + // Make sure we don't have a stray traffic server running. + if (!manager_flapping) { + cop_log(COP_WARNING, "traffic_manager not running, making sure traffic_server is dead\n"); + safe_kill(server_lockfile, server_binary, false); + } + // Spawn the manager (check for flapping manager too) + ink_hrtime now = milliseconds(); + if (!manager_flapping) { + if ((manager_flap_interval_start_time == 0) || + (now - manager_flap_interval_start_time > MANAGER_FLAP_INTERVAL_MSEC) + ) { + // either: + // . it's our first time through + // . we were flapping a while ago, but we would + // like to retry now + // . it's been a while since we last tried to start + // traffic_manager + manager_flap_count = 0; + } + if (manager_flap_count >= MANAGER_MAX_FLAP_COUNT) { + // we've flapped too many times, hold off for a while + cop_log(COP_WARNING, "unable to start traffic_manager, retrying in %d second(s)\n", + MANAGER_FLAP_RETRY_MSEC / 1000); + manager_flapping = true; + manager_flap_retry_start_time = now; + } else { + // try to spawn traffic_manager + cop_log(COP_WARNING, "spawning traffic_manager\n"); + spawn_manager(); + // track spawn attempt + if (manager_flap_count == 0) { + manager_flap_interval_start_time = now; + } + manager_flap_count++; + } + } else { + // we were flapping, take some time off and don't call + // spawn_manager + if (now - manager_flap_retry_start_time > MANAGER_FLAP_RETRY_MSEC) { + manager_flapping = false; + manager_flap_interval_start_time = 0; + } + } +#endif + } else { + // If there is a manager running we want to heartbeat it to + // make sure it hasn't wedged. If the manager test succeeds we + // check to see if the server is up. (That is, it hasn't been + // brought down via the UI). If the manager thinks the server + // is up, we make sure there is actually a server process + // running. If there is we test it. + + alarm(2 * manager_timeout); + err = heartbeat_manager(); + alarm(0); + + if (err < 0) { + return; + } + + if (server_up() <= 0) { + return; + } + + Lockfile server_lf(server_lockfile); + err = server_lf.Open(&holding_pid); +#if defined(linux) + // if lockfile held, but process doesn't exist, killall and try again + if (err == 0) { + if (kill(holding_pid, 0) == -1) { + cop_log(COP_WARNING, "%s's lockfile is held, but its pid (%d) is missing;" + " killing all processes named '%s' and retrying\n", server_binary, holding_pid, server_binary); + ink_killall(server_binary, killsig); + sleep(1); // give signals a chance to be received + err = server_lf.Open(&holding_pid); + } + } +#endif + if (err > 0) { + server_lf.Close(); + + server_not_found += 1; + cop_log(COP_WARNING, "cannot find traffic_server [%d]\n", server_not_found); + + if (server_not_found > 1) { + server_not_found = 0; + cop_log(COP_WARNING, "killing manager\n"); + safe_kill(manager_lockfile, manager_binary, true); + } + } else { + alarm(2 * server_timeout); + heartbeat_server(); + alarm(0); + } + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving check_programs()\n"); +#endif +} + +static void +check_memory() +{ +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering check_memory()\n"); +#endif +#if defined(linux) + if (check_memory_required) { + FILE *fp; + char buf[LINE_MAX]; + long long memfree, swapfree, swapsize; + memfree = swapfree = swapsize = 0; + if ((fp = fopen("/proc/meminfo", "r"))) { + while (fgets(buf, sizeof buf, fp)) { + if (strncmp(buf, "MemFree:", sizeof "MemFree:" - 1) == 0) + memfree = strtoll(buf + sizeof "MemFree:" - 1, 0, 10); + else if (strncmp(buf, "SwapFree:", sizeof "SwapFree:" - 1) == 0) + swapfree = strtoll(buf + sizeof "SwapFree:" - 1, 0, 10); + else if (strncmp(buf, "SwapTotal:", sizeof "SwapTotal:" - 1) == 0) + swapsize = strtoll(buf + sizeof "SwapTotal:" - 1, 0, 10); + } + fclose(fp); + // simple heuristic for linux 2.2.x + // swapsize swapfree memfree + // 1: >0 low high (bad) + // 2: >0 high low (okay) + // 3: >0 low low (bad; covered by 1) + // 4: 0 0 high (okay) + // 5: 0 0 low (bad) + if ((swapsize != 0 && swapfree < check_memory_min_swapfree_kb) || + (swapsize == 0 && memfree < check_memory_min_memfree_kb)) { + cop_log(COP_WARNING, "Low memory available (swap: %dkB, mem: %dkB)\n", (int) swapfree, (int) memfree); + cop_log(COP_WARNING, "Killing '%s' and '%s'\n", manager_binary, server_binary); + manager_failures = 0; + safe_kill(manager_lockfile, manager_binary, true); + server_failures = 0; + safe_kill(server_lockfile, server_binary, false); + } + } else { + cop_log(COP_WARNING, "Unable to open /proc/meminfo: %s\n", strerror(errno)); + } + } +#endif +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving check_memory()\n"); +#endif +} + +static int +check_no_run() +{ + char path[PATH_MAX * 2]; + struct stat info; + int err; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering check_no_run()\n"); +#endif + snprintf(path, sizeof(path), "%s/internal/no_cop", config_dir); + + do { + err = stat(path, &info); + } while ((err < 0) && (transient_error(errno, TRANSIENT_ERROR_WAIT_MS))); + + if (err < 0) { +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving check_no_run() --> 0\n"); +#endif + return 0; + } + + cop_log(COP_WARNING, "encountered \"%s\" file...exiting\n", path); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving check_no_run() --> -1\n"); +#endif + return -1; +} + +// Changed function from taking no argument and returning void +// to taking a void* and returning a void*. The change was made +// so that we can call ink_thread_create() on this function +// in the case of running cop as a win32 service. +static void* +check(void *arg) +{ + bool mgmt_init = false; +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering check()\n"); +#endif + + for (;;) { + // problems with the ownership of this file as root Make sure it is + // owned by the admin user + chown_file_to_user(manager_lockfile, admin_user); + chown_file_to_user(server_lockfile, admin_user); + + alarm(2 * (sleep_time + manager_timeout * 2 + server_timeout)); + + if (check_no_run() < 0) { + break; + } + // Log any SIGCLD singals we received + if (child_pid > 0) { + if (WIFEXITED(child_status) == 0) { + // Child terminated abnormally + cop_log(COP_WARNING, + "cop received non-normal child status signal [%d %d]\n", child_pid, WEXITSTATUS(child_status)); + } else { + // normal termination + cop_log(COP_WARNING, "cop received child status signal [%d %d]\n", child_pid, child_status); + } + if (WIFSIGNALED(child_status)) { + int sig = WTERMSIG(child_status); + cop_log(COP_WARNING, "child terminated due to signal %d: %s\n", sig, strsignal(sig)); + } + + child_pid = child_status = 0; + } + + // Re-read the config file information + read_config(); + + // Check to make sure the programs are running + check_programs(); + + // Check to see if we're running out of free memory + check_memory(); + + // Pause to catch our breath. (10 seconds). + // Use 'millisleep()' because normal 'sleep()' interferes with + // the SIGALRM signal which we use to heartbeat the cop. + millisleep(sleep_time * 1000); + + // We do this after the first round of checks, since the first "check" will spawn traffic_manager + if (!mgmt_init) { + TSInit(Layout::get()->runtimedir, static_cast(TS_MGMT_OPT_NO_EVENTS | TS_MGMT_OPT_NO_SOCK_TESTS)); + mgmt_init = true; + } + } + + // Done with the mgmt API. + TSTerminate(); + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving check()\n"); +#endif + return arg; +} + + +static void +check_lockfile() +{ + int err; + pid_t holding_pid; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering check_lockfile()\n"); +#endif + Lockfile cop_lf(cop_lockfile); + err = cop_lf.Get(&holding_pid); + if (err < 0) { + cop_log(COP_WARNING, "periodic cop heartbeat couldn't open '%s' (errno %d)\n", cop_lockfile, -err); + exit(1); + } else if (err == 0) { + cop_log(COP_DEBUG, "periodic heartbeat successful, another cop still on duty\n"); + exit(1); + } + + cop_log(LOG_NOTICE, "--- Cop Starting [Version: %s] ---\n", appVersionInfo.FullVersionInfoStr); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving check_lockfile()\n"); +#endif +} + +static void +init_signals() +{ + struct sigaction action; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering init_signals()\n"); +#endif + // Handle the SIGCHLD signal. We simply reap all children that + // die (which should only be spawned traffic_manager's). + action.sa_handler = sig_child; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + + sigaction(SIGCHLD, &action, NULL); + + // Handle a bunch of fatal signals. We simply call abort() when + // these signals arrive in order to generate a core. There is some + // difficulty with generating core files when linking with libthread + // under solaris. +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + action.sa_handler = NULL; + action.sa_sigaction = sig_fatal; +#else + action.sa_handler = sig_fatal; +#endif + sigemptyset(&action.sa_mask); +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + action.sa_flags = SA_SIGINFO; +#else + action.sa_flags = 0; +#endif + + sigaction(SIGQUIT, &action, NULL); + sigaction(SIGILL, &action, NULL); + sigaction(SIGFPE, &action, NULL); + sigaction(SIGBUS, &action, NULL); + sigaction(SIGSEGV, &action, NULL); +#if !defined(linux) + sigaction(SIGEMT, &action, NULL); + sigaction(SIGSYS, &action, NULL); +#endif + + // Handle the SIGALRM signal. We use this signal to make sure the + // cop never wedges. It gets reset every time through its loop. If + // the alarm ever expires we treat it as a fatal signal and dump + // core, secure in the knowledge we'll get restarted. + set_alarm_death(); + + action.sa_handler = sig_ignore; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + + sigaction(SIGPIPE, &action, NULL); +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving init_signals()\n"); +#endif +} + +static void +init_config_dir() +{ + + struct stat info; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering init_config_dir()\n"); +#endif + + root_dir = Layout::get()->prefix; + runtime_dir = Layout::get()->runtimedir; + config_dir = Layout::get()->sysconfdir; + + if (chdir(root_dir) < 0) { + cop_log(COP_FATAL, "unable to change to root directory \"%s\" [%d '%s']\n", root_dir, errno, strerror(errno)); + cop_log(COP_FATAL," please set correct path in env variable TS_ROOT \n"); + exit(1); + } + + if (stat(config_dir, &info) < 0) { + cop_log(COP_FATAL, "unable to locate config directory '%s'\n",config_dir); + cop_log(COP_FATAL, " please try setting correct root path in env variable TS_ROOT \n"); + exit(1); + } + + if (stat(runtime_dir, &info) < 0) { + cop_log(COP_FATAL, "unable to locate local state directory '%s'\n",runtime_dir); + cop_log(COP_FATAL, " please try setting correct root path in either env variable TS_ROOT \n"); + exit(1); + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving init_config_dir()\n"); +#endif +} + +static void +init_lockfiles() +{ + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering init_lockfiles()\n"); +#endif + Layout::relative_to(cop_lockfile, sizeof(cop_lockfile), Layout::get()->runtimedir, COP_LOCK); + Layout::relative_to(manager_lockfile, sizeof(manager_lockfile), Layout::get()->runtimedir, MANAGER_LOCK); + Layout::relative_to(server_lockfile, sizeof(server_lockfile), Layout::get()->runtimedir, SERVER_LOCK); + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving init_lockfiles()\n"); +#endif +} + +static void +init_syslog() +{ + openlog("traffic_cop", LOG_PID | LOG_NDELAY | LOG_NOWAIT, LOG_DAEMON); +} + +static void +init_config_file() +{ + struct stat info; + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering init_config_file()\n"); +#endif + Layout::relative_to(config_file, sizeof(config_file), + config_dir, "records.config.shadow"); + if (stat(config_file, &info) < 0) { + Layout::relative_to(config_file, sizeof(config_file), + config_dir, "records.config"); + if (stat(config_file, &info) < 0) { + cop_log(COP_FATAL, "unable to locate \"%s/records.config\" or \"%s/records.config.shadow\"\n", + config_dir, config_dir); + exit(1); + } + } +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving init_config_file()\n"); +#endif +} + +static void +init() +{ +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Entering init()\n"); +#endif + + init_signals(); + init_syslog(); + + init_config_dir(); + + init_config_file(); + init_lockfiles(); + check_lockfile(); + +#if defined(linux) + struct utsname buf; + if (uname(&buf) >= 0) { + if (strncmp(buf.release, "2.2.", 4) == 0) { + cop_log(COP_WARNING, "Linux 2.2.x kernel detected; enabling low memory fault protection"); + check_memory_required = true; + } + } +#endif + +#ifdef TRACE_LOG_COP + cop_log(COP_DEBUG, "Leaving init()\n"); +#endif +} + +int version_flag = 0; + +int +main(int argc, char *argv[]) +{ + int fd; + appVersionInfo.setup(PACKAGE_NAME,"traffic_cop", PACKAGE_VERSION, __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, ""); + + // Before accessing file system initialize Layout engine + Layout::create(); + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-stop") == 0) { + ink_fputln(stdout, "Cool! I think I'll be a STOP cop!"); + killsig = SIGSTOP; + } else if (strcmp(argv[i], "-V") == 0) { + ink_fputln(stderr, appVersionInfo.FullVersionInfoStr); + exit(0); + } + } + // Detach STDIN, STDOUT, and STDERR (basically, "nohup"). /leif + signal(SIGHUP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + + setsid(); // Important, thanks Vlad. :) +#if defined(freebsd) && !defined(kfreebsd) + setpgrp(0,0); +#else + setpgrp(); +#endif + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + if ((fd = open("/dev/null", O_WRONLY, 0)) >= 0) { + fcntl(fd, F_DUPFD, STDIN_FILENO); + fcntl(fd, F_DUPFD, STDOUT_FILENO); + fcntl(fd, F_DUPFD, STDERR_FILENO); + close(fd); + } else { + ink_fputln(stderr, "Unable to open /dev/null"); + return 0; + } + + // Initialize and start it up. + init(); + check(NULL); + + return 0; +} diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 00000000..2145cdb2 --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,1274 @@ +# Doxyfile 1.5.2 +# @configure_input@ + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file that +# follow. The default is UTF-8 which is also the encoding used for all text before +# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into +# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of +# possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE_NAME@ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = @abs_top_builddir@/doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = warn.log + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @abs_top_srcdir@/doc/mainpage.doc \ + @abs_top_srcdir@/iocore \ + @abs_top_srcdir@/lib/ts \ + @abs_top_srcdir@/lib/tsconfig \ + @abs_top_srcdir@/lib/records \ + @abs_top_srcdir@/proxy \ + @abs_top_srcdir@/test + +# This tag can be used to specify the character encoding of the source files that +# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default +# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. +# See http://www.gnu.org/software/libiconv for the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = *.c *.cc *.h *.i + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the output. +# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, +# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = letter + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = @PERL@ + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to +# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to +# specify the directory where the mscgen tool resides. If left empty the tool is assumed to +# be found in the default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = @abs_top_srcdir@/doc/dot + +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen will always +# show the root nodes and its direct children regardless of this setting. + +DOT_GRAPH_MAX_NODES = 100 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..dad0a8b5 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +EXTRA_DIST = Doxyfile.in + +clean-local: + -rm -rf html warn.log + +doxygen: Doxyfile + $(DOXYGEN) diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 00000000..f46082c2 --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,577 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = doc +DIST_COMMON = $(srcdir)/Doxyfile.in $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = Doxyfile +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +EXTRA_DIST = Doxyfile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local distclean distclean-generic distclean-libtool \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am + + +clean-local: + -rm -rf html warn.log + +doxygen: Doxyfile + $(DOXYGEN) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/doap.rdf b/doc/doap.rdf new file mode 100644 index 00000000..10910133 --- /dev/null +++ b/doc/doap.rdf @@ -0,0 +1,64 @@ + + + + + + 2011-04-08 + + Apache Traffic Server + + + Apache Traffic Server is an HTTP proxy cache. + Apache Traffic Server is fast, scalable and extensible HTTP/1.1 compliant caching proxy server. ATS can be used as a reverse, forward or even transparent HTTP proxy. + + + + + C + + + + trafficserver + 2011-03-21 + 2.1.7 + + + + + + + + + + + Leif Hedstrom + + + + + HTTP/1.1 + IETF + 2616 + + + + diff --git a/doc/dot/ResponseDiag.dot b/doc/dot/ResponseDiag.dot new file mode 100644 index 00000000..9fed3e03 --- /dev/null +++ b/doc/dot/ResponseDiag.dot @@ -0,0 +1,70 @@ +/* response processing diagram HttpSM */ +/* */ + +digraph g { +center=1; +size = "7.5,10"; +fontsize="20"; +label = "Inktomi CONFIDENTIAL"; +orientation = "portrait"; + +"READ_RESP_HDR" [ label = "Read Response Header" ]; +"CALL_HANDLE_RESP" [ label = "Call Handle Response" ]; + +/* Proxy Internal Nodes */ +"PROXY_INTERNAL" [ label = "PROXY_INTERNAL*" ]; +"PI_HANDLE_CACHE_WORK" [ label = "handle cache work" ]; +"PI_RESP_HDR_API" [label = "call Send Response Hdr Hook" ]; +"PI_INTERNAL_TRANSFER" [ label = "Internal Transfer" ]; + +/* Server Read Nodes */ +"SERVER_READ" [ label = "SERVER_READ*" ]; +"SER_HANDLE_CACHE_WORK" [ label = "handle cache work" ]; +"SER_TRANSFORM_Q" [ label = "transform?", shape = "diamond" ]; +"SER_NO_T_RESP_HDR_API" [label = "call Send Response Hdr Hook" ]; +"SER_NO_T_SERVER_TRANSFER" [ label = "Server Transfer" ]; + +/* Transform Nodes */ +"INIT_XFER_TO_TRANS" [label = "Initiate Transfer to Transform" ]; +"WAIT_FOR_READ_READY" [label = "Wait for Transform Read Ready" ]; +"TRANFORM_RESP_HDR_API" [label = "call Send Response Hdr Hook" ]; +"TRANSFORM_TRANSFER" [ label = "Transform Transfer" ]; + +/* Cache Read Nodes */ +"CACHE_READ" [ label = "CACHE_READ*" ]; +"CA_HANDLE_CACHE_WORK" [ label = "handle cache work" ]; +"CA_TRANSFORM_Q" [ label = "transform?", shape = "diamond" ]; +"CA_NO_T_RESP_HDR_API" [label = "call Send Response Hdr Hook" ]; +"CA_NO_T_SERVER_TRANSFER" [ label = "Cache Transfer" ]; + +/* Common path */ +"READ_RESP_HDR" -> "CALL_HANDLE_RESP"; +"CALL_HANDLE_RESP" -> "SERVER_READ"; +"CALL_HANDLE_RESP" -> "CACHE_READ"; +"CALL_HANDLE_RESP" -> "PROXY_INTERNAL"; + +/* Proxy Internal Path */ +"PROXY_INTERNAL" -> "PI_HANDLE_CACHE_WORK"; +"PI_HANDLE_CACHE_WORK" -> "PI_RESP_HDR_API"; +"PI_RESP_HDR_API" -> "PI_INTERNAL_TRANSFER"; + +/* Server Read Path */ +"SERVER_READ" -> "SER_HANDLE_CACHE_WORK"; +"SER_HANDLE_CACHE_WORK" -> "SER_TRANSFORM_Q"; +"SER_TRANSFORM_Q" -> "SER_NO_T_RESP_HDR_API" [ label = "no" ]; +"SER_NO_T_RESP_HDR_API" -> "SER_NO_T_SERVER_TRANSFER"; + +/* Cache Read Path" */ +"CACHE_READ" -> "CA_HANDLE_CACHE_WORK"; +"CA_HANDLE_CACHE_WORK" -> "CA_TRANSFORM_Q"; +"CA_TRANSFORM_Q" -> "CA_NO_T_RESP_HDR_API" [ label = "no" ]; +"CA_NO_T_RESP_HDR_API" -> "CA_NO_T_SERVER_TRANSFER"; + + +/* Transform Path */ +"SER_TRANSFORM_Q" -> "INIT_XFER_TO_TRANS" [ label = "yes" ]; +"CA_TRANSFORM_Q" -> "INIT_XFER_TO_TRANS" [ label = "yes" ]; +"INIT_XFER_TO_TRANS" -> "WAIT_FOR_READ_READY"; +"WAIT_FOR_READ_READY" -> "TRANFORM_RESP_HDR_API"; +"TRANFORM_RESP_HDR_API" -> "TRANSFORM_TRANSFER"; +} \ No newline at end of file diff --git a/doc/dot/SimpleStateDiag.dot b/doc/dot/SimpleStateDiag.dot new file mode 100644 index 00000000..0a49b691 --- /dev/null +++ b/doc/dot/SimpleStateDiag.dot @@ -0,0 +1,65 @@ +/* A simplified state diagram for HttpSM */ +/* */ + +digraph g { +center=1; +size = "7.5,10"; +fontsize="20"; +label = "Inktomi CONFIDENTIAL"; +orientation = "portrait"; + +"ACCEPT" [ label = "accept" ]; +"RD_REQ_HDRS" [ label = "Read Req Headers" ]; +"DNS" [ label = "DNS" ]; +"C_LOOKUP" [ label = "Cache Lookup" ]; +"CACHE_LOCK" [ label = "Lock URL in Cache" ]; +"PICK_ADDR" [ label = "Pick Address" ]; +"CACHE_MATCH" [ label = "Cache Match" ]; +"CACHE_FRESH" [ label = "Cache Fresh" ]; +"SND_REQ_HDRS" [ label = "Send Req Headers" ]; +"SETUP_C_READ" [ label = "Setup Cache Read" ]; +"SND_C_HDRS" [ label = "Send Cached Headers" ]; +"CONNECT" [ label = "Try Connect" ]; +"SND_REQ_HDRS" [ label = "Send Req Headers" ]; +"RD_REP_HDRS" [ label = "Read Reply Headers" ]; +"VALID" [ label = "Check Valid" ]; +"SETUP_S_READ" [ label = "Setup Server Read" ]; +"SETUP_CACHE_WRITE" [ label = "Setup Cache Write" ]; +"SETUP_TRANS" [ label = "Setup Transform" ]; +"SETUP_REQ_TRANS" [ label = "Setup Request Transform" ]; +"SETUP_BODY_READ" [ label = "Setup POST/PUT Read" ]; +"TUNNEL" [ label = "Tunnel Response" ]; +"TUNNEL_REQ" [ label = "Tunnel Request Body" ]; + + +"ACCEPT" -> "RD_REQ_HDRS"; +"RD_REQ_HDRS" -> "DNS"; +"DNS" -> "C_LOOKUP"; +"C_LOOKUP" -> "CACHE_MATCH" [ label = "hit" ]; +"C_LOOKUP" -> "CACHE_LOCK" [ label = "miss" ]; +"CACHE_LOCK" -> "PICK_ADDR"; +"CACHE_MATCH" -> "CACHE_LOCK" [ label = "no match" ]; +"CACHE_MATCH" -> "CACHE_FRESH" [ label ="match" ]; +"CACHE_FRESH" -> "SND_C_HDRS" [ label ="fresh" ]; +"CACHE_FRESH" -> "CACHE_LOCK" [ label ="stale" ]; +"SND_C_HDRS" -> "SETUP_C_READ"; +"SETUP_C_READ" -> "SETUP_TRANS"; +"PICK_ADDR" -> "CONNECT"; +"CONNECT" -> "PICK_ADDR" [ label = "fail" ]; +"CONNECT" -> "SND_REQ_HDRS" [ label = "success" ]; +"SND_REQ_HDRS" -> "SETUP_BODY_READ" [label = "POST/PUT" ]; +"SETUP_BODY_READ" -> "SETUP_REQ_TRANS"; +"SETUP_REQ_TRANS" -> "TUNNEL_REQ"; +"TUNNEL_REQ" -> "RD_REP_HDRS"; +"SND_REQ_HDRS" -> "RD_REP_HDRS" [label = "GET" ]; +"RD_REP_HDRS" -> "VALID"; +"VALID" -> "PICK_ADDR" [ label = "no" ]; +"VALID" -> "SETUP_S_READ" [ label = "yes" ]; +"SETUP_S_READ" -> "SETUP_TRANS" [ label = "Uncachable" ]; +"SETUP_S_READ" -> "SETUP_CACHE_WRITE" [ label = "Cachable" ]; +"SETUP_CACHE_WRITE" -> "SETUP_TRANS"; +"SETUP_TRANS" -> "TUNNEL"; +"TUNNEL" -> "ACCEPT"; + +} + diff --git a/doc/dot/SimpleStateDiagAPI.dot b/doc/dot/SimpleStateDiagAPI.dot new file mode 100644 index 00000000..2a2f1d0d --- /dev/null +++ b/doc/dot/SimpleStateDiagAPI.dot @@ -0,0 +1,86 @@ +/* A simplified state diagram for HttpSM with API callout points */ +/* */ + + +digraph g { +center=1; +size = "7.5,10"; +fontsize="20"; +label = "Inktomi CONFIDENTIAL"; +orientation = "portrait"; + +"ACCEPT" [ label = "Accept" ]; +"RD_REQ_HDRS" [ label = "Read Req Headers" ]; +"DNS" [ label = "DNS" ]; +"C_LOOKUP" [ label = "Cache Lookup" ]; +"CACHE_LOCK" [ label = "Lock URL in Cache" ]; +"PICK_ADDR" [ label = "Pick Address" ]; +"CACHE_MATCH" [ label = "Cache Match" ]; +"CACHE_FRESH" [ label = "Cache Fresh" ]; +"SND_REQ_HDRS" [ label = "Send Req Headers" ]; +"SETUP_C_READ" [ label = "Setup Cache Read" ]; +"SND_C_HDRS" [ label = "Send Cached Headers" ]; +"CONNECT" [ label = "Try Connect" ]; +"SND_REQ_HDRS" [ label = "Send Req Headers" ]; +"RD_REP_HDRS" [ label = "Read Reply Headers" ]; +"VALID" [ label = "Check Valid" ]; +"SETUP_S_READ" [ label = "Setup Server Read" ]; +"SETUP_CACHE_WRITE" [ label = "Setup Cache Write" ]; +"SETUP_TRANS" [ label = "Setup Transform" ]; +"SETUP_REQ_TRANS" [ label = "Setup Request Transform" ]; +"SETUP_BODY_READ" [ label = "Setup POST/PUT Read" ]; +"TUNNEL" [ label = "Tunnel Response" ]; +"TUNNEL_REQ" [ label = "Tunnel Request Body" ]; +"SND_REP_HDRS" [ label = "Send Reply Headers" ]; + +"API_START" [ label = "API - Start" shape=box ]; +"API_RD_REQ_HDRS" [ label = "API - Read Req Headers" shape=box ]; +"API_DNS" [ label = "API - DNS" shape=box ]; +"API_CACHE_MATCH" [ label = "API - Cache Match" shape=box ]; +"API_CACHE_READ_HDR" [ label = "API - Cache Read Header" shape=box ]; +"API_SND_REQ_HDRS" [ label = "API - Send Req Headers" shape=box ]; +"API_RD_REP_HDRS" [ label = "API - Read Reply Headers" shape=box ]; +"API_SND_REP_HDRS" [ label = "API - Send Reply Headers" shape=box ]; +"API_SHUTDOWN" [ label = "API - Shutdown" shape=box ]; + +"ACCEPT" -> "API_START"; +"API_START" -> "RD_REQ_HDRS"; +"RD_REQ_HDRS" -> "API_RD_REQ_HDRS"; +"API_RD_REQ_HDRS" -> "DNS"; +"DNS" -> "API_DNS"; +"API_DNS" -> "C_LOOKUP"; +"C_LOOKUP" -> "API_CACHE_MATCH" [ label = "hit" ]; +"C_LOOKUP" -> "CACHE_LOCK" [ label = "miss" ]; +"CACHE_LOCK" -> "PICK_ADDR"; +"API_CACHE_MATCH" -> "CACHE_MATCH"; +"CACHE_MATCH" -> "CACHE_LOCK" [ label = "no match" ]; +"CACHE_MATCH" -> "API_CACHE_READ_HDR" [ label ="match" ]; +"API_CACHE_READ_HDR" -> "CACHE_FRESH"; +"CACHE_FRESH" -> "SND_C_HDRS" [ label ="fresh" ]; +"CACHE_FRESH" -> "CACHE_LOCK" [ label ="stale" ]; +"SND_C_HDRS" -> "SETUP_C_READ"; +"SETUP_C_READ" -> "SETUP_TRANS"; +"PICK_ADDR" -> "CONNECT"; +"CONNECT" -> "PICK_ADDR" [ label = "fail" ]; +"CONNECT" -> "API_SND_REQ_HDRS" [ label = "success" ]; +"API_SND_REQ_HDRS" -> "SND_REQ_HDRS"; +"SND_REQ_HDRS" -> "SETUP_BODY_READ" [label = "POST/PUT" ]; +"SETUP_BODY_READ" -> "SETUP_REQ_TRANS"; +"SETUP_REQ_TRANS" -> "TUNNEL_REQ"; +"TUNNEL_REQ" -> "RD_REP_HDRS"; +"SND_REQ_HDRS" -> "RD_REP_HDRS" [label = "GET" ]; +"RD_REP_HDRS" -> "API_RD_REP_HDRS" +"API_RD_REP_HDRS" -> "VALID"; +"VALID" -> "PICK_ADDR" [ label = "no" ]; +"VALID" -> "SETUP_S_READ" [ label = "yes" ]; +"SETUP_S_READ" -> "SETUP_TRANS" [ label = "Uncachable" ]; +"SETUP_S_READ" -> "SETUP_CACHE_WRITE" [ label = "Cachable" ]; +"SETUP_CACHE_WRITE" -> "SETUP_TRANS"; +"SETUP_TRANS" -> "API_SND_REP_HDRS"; +"API_SND_REP_HDRS" -> "SND_REP_HDRS"; +"SND_REP_HDRS" -> "TUNNEL"; +"TUNNEL" -> "API_SHUTDOWN" +"API_SHUTDOWN" -> "ACCEPT"; + +} + diff --git a/doc/mainpage.doc b/doc/mainpage.doc new file mode 100644 index 00000000..9def1731 --- /dev/null +++ b/doc/mainpage.doc @@ -0,0 +1,16 @@ +/* + This file is for the documentation that appears on the main page of + the Doxygen output. Description of the code structure and layout + should go here. + */ + +/** @mainpage + + @section intro Introduction + + Traffic Server is an efficient caching proxy. Traffic Server provides + an extensible plug-in architecture, allowing properties to modify + its behavior when necessary. + + */ + diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am new file mode 100644 index 00000000..d354d889 --- /dev/null +++ b/doc/man/Makefile.am @@ -0,0 +1,81 @@ +# +# Makefile.am for the Enterprise Management module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +man_MANS = \ + config_alarms.1 \ + config_cache.1 \ + config_clock.1 \ + config_dns.1 \ + config_get.1 \ + config_hard-restart.1 \ + config_hostdb.1 \ + config_http.1 \ + config_icp.1 \ + config_logging.1 \ + config_name.1 \ + config_network.1 \ + config_parent.1 \ + config_port-tunnels.1 \ + config_remap.1 \ + config_reset-stats.1 \ + config_restart.1 \ + config_root.1 \ + config_scheduled-update.1 \ + config_security.1 \ + config_set.1 \ + config_snmp.1 \ + config_socks.1 \ + config_ssl.1 \ + config_start.1 \ + config_stop.1 \ + config_upgrade.1 \ + config_virtual-ip.1 \ + disable.1 \ + enable.1 \ + exit.1 \ + show_alarms.1 \ + show_cache.1 \ + show_cache-stats.1 \ + show_cluster.1 \ + show_dns-resolver.1 \ + show_dns-stats.1 \ + show_hostdb.1 \ + show_hostdb-stats.1 \ + show_http.1 \ + show_http-stats.1 \ + show_http-trans-stats.1 \ + show_icp.1 \ + show_icp-stats.1 \ + show_logging.1 \ + show_logging-stats.1 \ + show_network.1 \ + show_parent.1 \ + show_port-tunnels.1 \ + show_proxy.1 \ + show_proxy-stats.1 \ + show_remap.1 \ + show_scheduled-update.1 \ + show_security.1 \ + show_snmp.1 \ + show_socks.1 \ + show_ssl.1 \ + show_status.1 \ + show_version.1 \ + show_virtual-ip.1 \ + traffic_shell.1 diff --git a/doc/man/config_alarms.1 b/doc/man/config_alarms.1 new file mode 100644 index 00000000..283cf287 --- /dev/null +++ b/doc/man/config_alarms.1 @@ -0,0 +1,52 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:alarms" +.SH NAME +config:alarms \- Configure alarm notification. +.SH SYNOPSIS +config:alarms [options] +.SH DESCRIPTION +You use the config:alarms command to enable or disable alarm notification, and to +resolve active alarms. +.SH OPTIONS +The following options are supported for the config:alarms command: +.SS "notify " +Enables (on) or disables (off) the alarm notification feature. When off, alarm +messages will not appear in traffic_shell. +.SS "resolve-name " +Specifies the name of the alarm to resolve. +.SS "resolve-number " +Specifies the alarm to resolve from the show:alarms list. +.SS "resolve-all" +Specifies resolution of all active alarms. +.SH EXAMPLES +.SS "Example 1. Enabling Alarm notification" +.PP +.nf +traffic_shell> config:alarms notify on +traffic_shell> +.SS "Example 2. Resolving an alarm by name" +.PP +.nf +traffic_shell> config:alarms resolve-name MGMT_ALARM_PROXY_PROCESS_DIED +traffic_shell> +.SS "Example 3. Resolving an alarm by number" +.PP +.nf +traffic_shell> config:alarms resolve-name 1 +traffic_shell> +.SH "SEE ALSO" +show:alarms diff --git a/doc/man/config_cache.1 b/doc/man/config_cache.1 new file mode 100644 index 00000000..d7648d9b --- /dev/null +++ b/doc/man/config_cache.1 @@ -0,0 +1,140 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:cache" +.SH NAME +config:cache \- Enables caching for various protocols and configures general +caching parameters. +.SH SYNOPSIS +config:cache [options] +.SH DESCRIPTION +Use the config:cache command to enable caching for HTTP based +protocols. Also use this command to configure general caching parameters, +including storage, freshness, bypass, and alternates. When you execute the +config:cache command, you must use one of the options described below. +.SH OPTIONS +The following options are supported for the config:cache command: +.SS "http " +Enables (on) or disables (off) the caching of HTTP requests. (The default value +is on.) +.SS "ignore-bypass " +Enables (on) or disables (off) the ignore-bypass option. When enabled (on), the proxy ignores client requests to bypass the cache. (The default value is off.) +.SS "max-object-size " +Specifies the maximum byte size of documents in the cache. A maximum byte size of zero means that there is no maximum. (The default value is zero.) +.SS "max-alternates " +Specifies the maximum number of HTTP alternates that the proxy can cache. (The +default value is three.) +.SS "file [url]" +Specifies the location (URL) from which the proxy should retrieve and install +your cache.config file. +.SS "freshness verify " +Specifies when to revalidate content. Type when-expired to use cache directives +or heuristic. Type no-date to consider the object stale if the object contains +no Expires or cache-control headers. (The default value is when-expired.) +.SS "freshness minimum " +Specifies the type of headers required for the request to be cacheable. Type +nothing if you want no required headers to make the document cacheable. Type +last-modified if you want at least the last-modified header to be required. Type +explicit if you want the Expires or Cache-Control headers required (these +explicitly indicate lifetime duration). (The default value is nothing.) +.SS "freshness no-expire-limit greater-than less-than " +Specifies the minimum amount of time in seconds that a document in the cache can be considered fresh. (The default value is 3600.) +Specifies the maximum amount of time in seconds that a document in the cache can be considered fresh. (The default value is 86400.) +.SS "dynamic " +Enables (on) or disables (off) the caching of URLs that look dynamic. (The +default value is off.) +.SS "alternates " +Enables (on) or disables (off) the caching of alternate versions of HTTP objects +that do not contain the Vary header. (The default value is off.) +.SS "vary " +Specifies the headers on which the proxy should vary for text, images, and +anything other than text and images. (The default value is NULL.) +.SS "cookies " +Specifies how cookies are cached. Type none to cache no responses to cookies. +Type all to cache for any content type. Type images to cache only for image +types. Type non-text to cache for all but text content-types. (The default value +is non-text.) +.SH EXAMPLES +.SS "Example 1. Enabling the caching of HTTP requests" +.PP +.nf +traffic_shell> config:cache http on +traffic_shell> +.SS "Example 2. Enabling the proxy to ignore client requests to" +.SS " bypass the cache" +.PP +.nf +traffic_shell> config:cache ignore-bypass on +traffic_shell> +.SS "Example 3. Specifying no maximum size of documents in the" +.SS " cache" +.PP +.nf +traffic_shell> config:cache max-object-size 0 +traffic_shell> +.SS "Example 4. Specifying zero as the maximum number of HTTP" +.SS " alternates that the proxy can cache" +.PP +.nf +traffic_shell> config:cache max-alternates 0 +traffic_shell> +.SS "Example 5. Specifying the location (URL) from which the proxy" +.SS " should retrieve and install your cache.config file" +.PP +.nf +traffic_shell> config:cache file http://somedomain.com/path/cache.config +traffic_shell> +.SS "Example 6. Revalidating content by using cache directives" +.SS " or heuristic" +.PP +.nf +traffic_shell> config:cache freshness verify when-expired +traffic_shell> +.SS "Example 7. Requiring the Expires or Cache-Control headers " +.SS " for cacheability" +.PP +.nf +traffic_shell> config:cache freshness minimum explicit +traffic_shell> +.SS "Example 8. Specifying a minimum and a maximum amount of time" +.SS " seconds for a document in the cache to be " +.SS " considered fresh" +.PP +.nf +traffic_shell> config:cache freshness no-expire-limit greater-than 900 less-than 7200 +traffic_shell> +.SS "Example 9. Enabling the caching of URLs that look dynamic" +.PP +.nf +traffic_shell> config:cache dynamic on +traffic_shell> +.SS "Example 10. Enabling the caching of alternate versions of HTTP +.SS " objects that do not contain the Vary header" +.PP +.nf +traffic_shell> config:cache alternates on +traffic_shell> +.SS "Example 11. Specifying the Cookie header for the proxy to vary on for text" +.PP +.nf +traffic_shell> config:cache vary text Cookie +traffic_shell> +.SS "Example 12. Specifying not to cache responses from cookies" +.PP +.nf +traffic_shell> config:cache cookies none +traffic_shell> +.SH "SEE ALSO" +show:cache, show:cache-stats diff --git a/doc/man/config_clock.1 b/doc/man/config_clock.1 new file mode 100644 index 00000000..947abe35 --- /dev/null +++ b/doc/man/config_clock.1 @@ -0,0 +1,64 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:clock" +.SH NAME +config:clock \- Configure system clock settings. +.SH SYNOPSIS +config:clock [options] +.SH DESCRIPTION +You use the config:clock command specify system date, time, and timezone settings. +A full restart of proxy software occurs when these changes take place. This command +requires root privileges, see config:root command. +.SH OPTIONS +The following options are supported for the config:clock command: +.SS "date " +Specifies the month, day, and year. +.SS "time " +Specifies the hour, minute, and seconds values in the local time zone. The hour value +is in 24-hour format. +.SS "timezone " +List the available timezones, or specify the timezone from the numbered list. +.SH EXAMPLES +.SS "Example 1. Specifying system date" +.PP +.nf +traffic_shell> config:clock date +DATE: 10/14/2001 +traffic_shell> config:clock date 10/15/2001 +(Stopping Proxy Software) +Changing Date +(Starting Proxy Software) +DATE: 10/15/2001 +traffic_shell> +.SS "Example 2. Listing available timezones" +.PP +.nf +traffic_shell> config:clock timezone list +0 Africa/Abidjan +1 Africa/Accra +2 Africa/Addis_Ababa +... +362 Pacific/Wake +363 Pacific/Wallis +364 Pacific/Yap +traffic_shell> +.SS "Example 3. Specifying the local timezone" +.PP +.nf +traffic_shell> config:clock timezone 109 +traffic_shell> +.SH "SEE ALSO" +config:root diff --git a/doc/man/config_dns.1 b/doc/man/config_dns.1 new file mode 100644 index 00000000..5e00acae --- /dev/null +++ b/doc/man/config_dns.1 @@ -0,0 +1,46 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:dns" +.SH NAME +config:dns \- Configures DNS lookups. +.SH SYNOPSIS +config:dns [options] +.SH DESCRIPTION +Use the config:dns command to configure DNS proxying and DNS lookups. When you execute the +config:dns command, you must use one of the options described below. +.SH OPTIONS +The following options are supported for the config:dns command: +.SS "proxy " +Enables (on) or disables (off) the DNS proxying feature. +.SS "proxy-port " +Specifies the port number used by the DNS proxy. +.SS "resolve-timeout " +Specifies the DNS lookup timeout in seconds. (The default value is 20.) +.SS "retries " +Specifies the number of DNS retries. (The default value is 5.) +.SH EXAMPLES +.SS "Example 1. Specifying 10 seconds as the DNS lookup timeout" +.PP +.nf +traffic_shell> config:dns resolve-timeout 10 +traffic_shell> +.SS "Example 2. Specifying a value of three for DNS retries" +.PP +.nf +traffic_shell> config:dns retries 3 +traffic_shell> +.SH "SEE ALSO" +show:dns-resolver, show:dns-stats diff --git a/doc/man/config_get.1 b/doc/man/config_get.1 new file mode 100644 index 00000000..bdb38022 --- /dev/null +++ b/doc/man/config_get.1 @@ -0,0 +1,37 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:get" +.SH NAME +config:get \- Displays a variable from the records.config file. +.SH SYNOPSIS +config:get [variable] +.SH DESCRIPTION +The config:get command enables you to display a variable and its value from the +records.config file. +.SH OPERANDS +The following operand is supported: +.SS "" +You must type the name of the variable that you want to see. +.SH EXAMPLES +.SS "When you execute the config:get command, you see results " +.SS "in the following format:" +.PP +.nf +traffic_shell> config:get proxy.config.http.server_port +proxy.config.http.server_port = 8080 +traffic_shell> +.SH "SEE ALSO" +config:set diff --git a/doc/man/config_hard-restart.1 b/doc/man/config_hard-restart.1 new file mode 100644 index 00000000..9f63e447 --- /dev/null +++ b/doc/man/config_hard-restart.1 @@ -0,0 +1,31 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:hard-restart" +.SH NAME +config:hard-restart \- Restarts the mangement, monitoring, and proxy software. +.SH SYNOPSIS +config:hard-restart +.SH DESCRIPTION +The config:hard-restart command restarts your management, monitoring, and proxy software. +The config:hard-restart command takes no options. +.SH EXAMPLES +When you execute the config:hard-restart command, you see results in the following format. +.PP +.nf +traffic_shell> config:hard-restart +traffic_shell> +.SH "SEE ALSO" +config:start, config:stop, config:restart diff --git a/doc/man/config_hostdb.1 b/doc/man/config_hostdb.1 new file mode 100644 index 00000000..8660cd5b --- /dev/null +++ b/doc/man/config_hostdb.1 @@ -0,0 +1,72 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:hostdb" +.SH NAME +config:hostdb \- Configures the host database. +.SH SYNOPSIS +config:hostdb [options] +.SH DESCRIPTION +Use the config:hostdb command to configure the host database. You configure such +parameters as foreground, background, and lookup timeouts. When you execute the +config:hostdb command, you must use one of the options described below. +.SH OPTIONS +The following options are supported for the config:hostdb command: +.SS "lookup-timeout " +Specifies the maximum number of seconds the proxy can wait for a lookup response +from the Domain Name Server. (The default value is 120.) +.SS "foreground-timeout " +Specifies the foreground timeout in seconds. (The default value is 1440.) +.SS "background-timeout " +Specifies the background timeout in minutes. (The default value is 720.) +.SS "invalid-host-timeout " +Specifies the invalid host timeout in minutes. (The default value is zero.) +.SS "re-dns-on-reload " +Enables (on) or disables (off) DNS lookup upon reload. (The default value is +off.) +.SS "clear" +Clear the Host DB. +.SH EXAMPLES +.SS "Example 1. Specifying 30 seconds as the maximum that" +.SS " the proxy waits for a DNS lookup response" +.PP +.nf +traffic_shell> config:hostdb lookup-timeout 30 +traffic_shell> +.SS "Example 2. Specifying 12 seconds as the foreground " +.SS " timeout" +.PP +.nf +traffic_shell> config:hostdb foreground-timeout 12 +traffic_shell> +.SS "Example 3. Specifying 24 seconds as the background" +.SS " timeout" +.PP +.nf +traffic_shell> config:hostdb background-timeout 24 +traffic_shell> +.SS "Example 4. Specifying 30 minutes as the invalid host" +.SS " timeout" +.PP +.nf +traffic_shell> config:hostdb invalid-host-timeout 30 +traffic_shell> +.SS "Example 5. Enabling DNS on reload" +.PP +.nf +traffic_shell> config:hostdb re-dns-on-reload on +traffic_shell> +.SH "SEE ALSO" +show:hostdb, show:hostdb-stats diff --git a/doc/man/config_http.1 b/doc/man/config_http.1 new file mode 100644 index 00000000..91dfcfbd --- /dev/null +++ b/doc/man/config_http.1 @@ -0,0 +1,78 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:http" +.SH NAME +config:http \- Configures HTTP caching. +.SH SYNOPSIS +config:http [options] +.SH DESCRIPTION +The config:http command enables you to configure HTTP caching through a variety of options. +You must use one of the options described below. +.SH OPTIONS +The following options are supported for the config:http command: +.SS "status " +Enables (on) or disables (off) the proxy from serving HTTP requests. +.SS "keep-alive-timeout-in " +Specifies the keep-alive timeout for inbound connections. +.SS "keep-alive-timeout-out " +Specifies the keep-alive timeout for outbound connections. +.SS "inactive-timeout-in " +Specifies the inactivity timeout for inbound connections. +.SS "inactive-timeout-out " +Specifies the inactivity timeout for outbound connections. +.SS "active-timeout-in " +Specifies the active timeout for inbound connections. +.SS "active-timeout-out " +Specifies the active timeout for outbound connections. +.SS "remove-from " +Enables (on) or disables (off) the removal of the From header from HTTP requests. +.SS "remove-referer " +Enables (on) or disables (off) the removal of the Referer header from HTTP requests. +.SS "remove-user " +Enables (on) or disables (off) the removal of the User header from HTTP requests. +.SS "remove-cookie " +Enables (on) or disables (off) the removal of the Cookie header from HTTP requests. +.SS "remove-header " +Specifies the name of a header to remove from HTTP requests. +.SS "insert-ip " +Enables (on) or disables (off) the insertion of the client IP address into HTTP requests. +.SS "remove-ip " +Enables (on) or disables (off) the removal of the client IP address from HTTP requests. +.SS "proxy " +Specifies HTTP proxying in forward, reverse, or forward and reverse simultaneously. +.SH EXAMPLES +.SS "Example 1. Enabling the proxy to serve HTTP requests" +.PP +.nf +traffic_shell> config:http on +traffic_shell> +.SS "Example 2. Specifying the keep-alive tiemout for inbound requests" +.PP +.nf +traffic_shell> config:http keep-alive-timeout-in 10 +traffic_shell> +.SS "Example 3. Specifying removal of the From header from HTTP requests" +.PP +.nf +traffic_shell> config:http remove-from on +traffic_shell> +.SS "Example 4. Specifying forward proxy mode for HTTP" +.PP +.nf +traffic_shell> config:http fwd +traffic_shell> +.SH "SEE ALSO" +show:http, show:http-stats, show:http-trans-stats diff --git a/doc/man/config_icp.1 b/doc/man/config_icp.1 new file mode 100644 index 00000000..01499186 --- /dev/null +++ b/doc/man/config_icp.1 @@ -0,0 +1,72 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:icp" +.SH NAME +config:icp \- Configures ICP caching. +.SH SYNOPSIS +config:icp [options] +.SH DESCRIPTION +The config:icp command enables you to configure ICP caching through a variety of +options. Use the config:icp command with options to configure mode, port +numbers, timeouts, and to enable ICP multicast. You must use one of the options +described below. +.SH OPTIONS +The following options are supported for the config:icp command: +.SS "mode " +Sets the ICP mode for hierarchical caching. Type receive if you want to allow +the proxy to only receive ICP queries. Type send-receive if you want the proxy +to both send and receive ICP queries. Type disabled if you want to disable the +proxy from sending and receiving ICP queries. (The default value is disabled.) +.SS "port " +Specifies the UDP port that you want to use for ICP messages. (The default is +3130.) +.SS "multicast " +Enables (on) or disables (off) ICP multicast. (The default value is off.) +.SS "query-timeout " +Specifies the timeout duration in seconds used for ICP queries. (The default value is 2.) +.SS "query-timeout " +Retrieves (and updates) your icp.config file from a URL that you specify. +.SH EXAMPLES +.SS "Example 1. Enabling the proxy to receive ICP queries" +.PP +.nf +traffic_shell> config:icp mode receive +traffic_shell> +.SS "Example 2. Specifying UDP port number 3130 for ICP messages" +.PP +.nf +traffic_shell> config:icp port 3130 +traffic_shell> +.SS "Example 3. Enabling ICP multicast" +.PP +.nf +traffic_shell> config:icp multicast on +traffic_shell> +.SS "Example 4. Specifying an ICP query timeout duration of two" +.SS " seconds" +.PP +.nf +traffic_shell> config:icp query-timeout 2 +traffic_shell> +.SS "Example 5. Specifying a URL from which the proxy should" +.SS " retrieve and install or update your icp.config" +.SS " file" +.PP +.nf +traffic_shell> config:icp peers http://somedomain.com/path/icp.config +traffic_shell> +.SH "SEE ALSO" +show:icp, show:icp-stats diff --git a/doc/man/config_logging.1 b/doc/man/config_logging.1 new file mode 100644 index 00000000..d00934b7 --- /dev/null +++ b/doc/man/config_logging.1 @@ -0,0 +1,160 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:logging" +.SH NAME +config:logging \- Enables and configures logging parameters. +.SH SYNOPSIS +config:logging [options] +.SH DESCRIPTION +Use the config:logging command to enable and configure logging. Use the +config:logging command to specify format, type, storage, splitting, rolling, and +other parameters. When you execute the config:logging command, you must use one +of the options described below. +.SH OPTIONS +The following options are supported for the config:logging command: +.SS "event " +Enables and disables event logging. Type trans-only to log only transactions. +Type error-only to log only errors. Type enabled to enable full logging that +includes errors and transactions. Type disabled to disable logging completely. +(The default value is enabled.) +.SS "mgmt-directory " +Specifies the full path to the logging directory. (The default is +/home/inktomi/5.0.0/logs.) +.SS "space-limit " +Specifies the amount of space allocated to the logging directory in MB. (The +default value is 2000MB.) +.SS "space-headroom " +Specifies the tolerance for the log space limit.(The default value is 10MB.) +.SS "collation-status " +Specifies the log collation mode. Type inactive to disable collation. Type host +to specify the local host as a collation server. Type send-standard to specify +the local host as collation client that sends entries using standard formats to +the collation server. Type send-custom to specify this host as a collation +client that sends entries using the traditional custom formats to the collation +server. Type send-all to specify this host as a collation client that sends +entries that use both the standard and traditional custom formats to the +collation server. (The default value is inactive.) +.SS "collation-host " +Specifies the hostname of the log collation server. (The default value is NULL.) +.SS "collation secret tagged orphan-limit " +Specifies the password used to validate logging data and prevent the exchange of +unauthorized information when a collation server is being used. (The default +value is foobar.) +Specifies the tagged option in log entry. When enabled (on), configures Traffic Server to include the hostname of the collation client that generated the log entry in each entry. (The default value is off.) +Specifies the storage limit for orphan files in MB. (The default value is +25.) +.SS "format type file header
" +Specifies which logging formats you want on/off. Also specifies the log file +type (ASCII or binary), file name, and header text. The default log file format +(on) is the Squid format. The default values for all formats are as follows: +.PP +.nf +Squid Format ----------------------------- on + File Type ------------------------------ ASCII + File Name ------------------------------ squid + File Header ---------------------------- NULL + +Netscape Common -------------------------- off + File Type ------------------------------ ASCII + File Name ------------------------------ common + File Header ---------------------------- NULL + +Netscape Extended ------------------------ off + File Type ------------------------------ ASCII + File Name ------------------------------ extended + File Header ---------------------------- NULL + +Netscape Extended2 ----------------------- off + File Type ------------------------------ ASCII + File Name ---------------------------- extended2 + File Header ---------------------------- NULL + +.SS "splitting " +Enables (on) or disables (off) log splitting for ICP, and HTTP. When +enabled, the proxy stores the transactions for the protocol you choose in a +separate log file. (The default value is off for ICP and HTTP.) +.SS"custom format " +Enables (on) or disables (off) custom logging. When you enable custom logging, +you must specify the format, traditional or XML. (The default values are off for +custom logging and traditional for format.) +.SS "rolling offset interval auto-delete " +Enables (on) or disables (off) log file rolling. (The default value is on.) +The offset parameter specifies the hour of the day that starts the log +rolling period. (The default value is 0.) The interval parameter +specifies the log file rolling interval. (The default value is 86400 seconds.) +The auto-delete parameter enables (on) or disables (off) the +automatic deletion of rolled log files. (The default value is on.) +.SH EXAMPLES +.SS "Example 1. Enabling error and transaction logging" +.PP +.nf +traffic_shell> config:logging event enabled +traffic_shell> +.SS "Example 2. Specifying the full path to the logging directory" +.PP +.nf +traffic_shell> config:logging mgmt-directory /home/inktomi/rc4/logs +traffic_shell> +.SS "Example 3. Specifying logging directory storage allocation (MB)" +.PP +.nf +traffic_shell> config:logging space-limit 10 +traffic_shell> +.SS "Example 4. Specifying the tolerance for the log space limit" +.PP +.nf +traffic_shell> config:logging space-headroom 100 +traffic_shell> +.SS "Example 5. Configuring the host to send entries using the " +.SS " traditional custom formats to the collation server" +.PP +.nf +traffic_shell> config:logging collation-status send-custom +traffic_shell> +.SS "Example 6. Specifying the hostname (jupiter) of the log" +.SS " collation server" +.PP +.nf +traffic_shell> config:logging collation-host jupiter +traffic_shell> +.SS "Example 7. Specifying the password used to validate logging" +.SS " data, configuring logging to include the hostname" +.SS " of the collation, and specifying 10MB as the " +.SS " storage limit for orphan files" +.PP +.nf +traffic_shell> config:logging collation secret foobar tagged on orphan-limit 10 +traffic_shell> +.SS "Example 8. Enabling the Squid logging format, and specifying" +.SS " the ASCII file type and squid.log file name" +.PP +.nf +traffic_shell> config:log format squid on type ascii file squid.log +traffic_shell> +.SS "Example 9. Enabling custom XML logging" +.PP +.nf +traffic_shell> config:logging custom on format xml +traffic_shell> +.SS "Example 10. Enabling log rolling, to begin rolling at " +.SS " midnight, with an interval of 60 seconds and" +.SS " no automatic deletion of rolled files" +.PP +.nf +traffic_shell> config:logging rolling on offset 0 interval 1 auto-delete off +traffic_shell> +.SH "SEE ALSO" +show:logging, show:logging-stats diff --git a/doc/man/config_name.1 b/doc/man/config_name.1 new file mode 100644 index 00000000..c85e47ac --- /dev/null +++ b/doc/man/config_name.1 @@ -0,0 +1,36 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:name" +.SH NAME +config:name \- Sets the name of the proxy. +.SH SYNOPSIS +config:name [hostname] +.SH DESCRIPTION +The config:name command enables you to set the name of your proxy system. +.SH OPERANDS +The following operand is supported: +.SS "" +The hostname is your name for your proxy system. +.SH EXAMPLES +.SS "When you execute the config:name command, you see " +.SS "results in the following format:" +.PP +.nf +traffic_shell> config:name somename +somename.yourdomain.com +traffic_shell> +.SH "SEE ALSO" +show:network diff --git a/doc/man/config_network.1 b/doc/man/config_network.1 new file mode 100644 index 00000000..db638b3a --- /dev/null +++ b/doc/man/config_network.1 @@ -0,0 +1,75 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:network" +.SH NAME +config:network \- Configures system network settings. +.SH SYNOPSIS +config:network [options] +.SH DESCRIPTION +The config:network command enables you to configure network settings such as hostname, +defaultrouter, search-domain, dns, and interface settings. +You must use one of the options described below. +.SH OPTIONS +The following options are supported for the config:network command: +.SS "hostname " +Specifies the fully qualified hostname. +.SS "defaultrouter " +Specifies the IP address of the default router. +.SS "search-domain " +Specifies the search domain. +.SS "dns " +Specifies the IP addresses of one or more DNS servers. +.SS "int" +Displays the Network Interfaces. +.SS "int " +Displays information pertaining to a Network Interface. +.SS "int down" +Bring down a Network Interface. +.SS "int up " +Bring up a Network Interface with the specified settings: boot status, static IP versus DHCP, IP address, netmask, and gateway IP (or default). +.SS "int " +Specify the boot status of a Network Interface. NIC must already be up. +.SS "int +Specify static IP or DHCP for a Network Interface. NIC must already be up. +.SS "int ip " +Specify the IP address of a network interface. NIC must already be up. +.SS "int netmask " +Specify the netmask of a network interface. NIC must already be up. +.SS "int gateway " +Specify the gateway IP address, or default to use the defaultrouter. +.SH EXAMPLES +.SS "Example 1. Specifying the hostname" +.PP +.nf +traffic_shell> config:network hostname host.example.com +traffic_shell> +.SS "Example 2. Specifying multiple DNS servers" +.PP +.nf +traffic_shell> config:network dns "x.x.x.x y.y.y.y z.z.z.z" +traffic_shell> +.SS "Example 3. Listing the Network Interfaces" +traffic_shell> config:network int +eth0 +eth1 +traffic_shell> +.SS "Example 4. Bringing up a Network Interface with IP address x.x.x.x and netmask y.y.y.y" +.PP +.nf +traffic_shell> config:network int eth0 onboot static x.x.x.x y.y.y.y default +traffic_shell> +.SH "SEE ALSO" +show:network diff --git a/doc/man/config_parent.1 b/doc/man/config_parent.1 new file mode 100644 index 00000000..ae39549b --- /dev/null +++ b/doc/man/config_parent.1 @@ -0,0 +1,53 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:parent" +.SH NAME +config:parent \- Configure parent proxy caching. +.SH SYNOPSIS +config:parent [options] +.SH DESCRIPTION +You use the config:parent command to enable HTTP parent caching, specify a +parent cache, and indicate where the proxy should locate the parent.config file, +which contains specific parent cache configuration information. +.SH OPTIONS +The following options are supported for the config:parent command: +.SS "status " +Enables (on) or disables (off) the HTTP parent caching option. (The default +value is off.) +.SS "name " +Specifies the parent cache. (The default value is NULL.) +.SS "rules " +Specifies from which location (URL) the proxy should retrieve and install your +parent.config file. +.SH EXAMPLES +.SS "Example 1. Enabling HTTP parent caching" +.PP +.nf +traffic_shell> config:parent status on +traffic_shell> +.SS "Example 2. Specifying the parent cache" +.PP +.nf +traffic_shell> config:parent name www.example.com +traffic_shell> +.SS "Example 3. Locating the access file to specify administrators" +.SS " with access to the Traffic Manager UI" +.PP +.nf +traffic_shell> config:parent rules http://somedomain.com/path/parent.config +traffic_shell> +.SH "SEE ALSO" +show:parent diff --git a/doc/man/config_port-tunnels.1 b/doc/man/config_port-tunnels.1 new file mode 100644 index 00000000..5dd4102c --- /dev/null +++ b/doc/man/config_port-tunnels.1 @@ -0,0 +1,35 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:port-tunnels" +.SH NAME +config:port-tunnels \- Configures port tunnels. +.SH SYNOPSIS +config:port-tunnels [server-other-ports] +.SH DESCRIPTION +Use the config:port-tunnels command to specify a port for the proxy to use for +tunneling. +.SH OPTIONS +The following option is supported for the config:port-tunnels command: +.SS "server-other-ports " +Specifies a port for tunneling. (The default value is NULL.) +.SH EXAMPLE +.SS "Specifying a port for the proxy to use for tunneling" +.PP +.nf +traffic_shell> config:port-tunnels server-other-ports 5678 +traffic_shell> +.SH "SEE ALSO" +show:port-tunnels, show:remap diff --git a/doc/man/config_remap.1 b/doc/man/config_remap.1 new file mode 100644 index 00000000..7d18580a --- /dev/null +++ b/doc/man/config_remap.1 @@ -0,0 +1,35 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:remap" +.SH NAME +config:remap \- Specify the location of your remap.config file. +.SH SYNOPSIS +config:remap [url] +.SH DESCRIPTION +You use the config:remap command to specify from which location (URL) the proxy +should retrieve and install your remap.config file. +.SH OPERAND +The following operand is supported for the config:remap command: +.SS "" +Specifies the location of your remap.config file. +.SH EXAMPLE +.SS "Specifying the location of your remap.config file" +.PP +.nf +traffic_shell> config:remap http://somedomain.com/path/remap.config +traffic_shell> +.SH "SEE ALSO" +show:remap diff --git a/doc/man/config_reset-stats.1 b/doc/man/config_reset-stats.1 new file mode 100644 index 00000000..2b09e2a2 --- /dev/null +++ b/doc/man/config_reset-stats.1 @@ -0,0 +1,46 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:reset-stats" + +.SH NAME + +config:reset-stats \- Resets all statistics. + +.SH SYNOPSIS + +config:reset-stats + +.SH DESCRIPTION + +The config:reset-stats command resets all statistics. (See the "See Also" +section below for a list of commands that display statistics.) The config:reset- +stats command takes no options. + +.SH EXAMPLES + +.TP + +When you execute the config:reset-stats command, you see results in the +following format: + +.TP +ts_shell>config:reset-stats + +OK +ts_shell> + +.SH "SEE ALSO" +show:cache-stats, show:dns-stats, show:hostdb-stats, show:http-stats, +show:proxy-stats, show:http-trans-stats, show:icp-stats, show:logging-stats diff --git a/doc/man/config_restart.1 b/doc/man/config_restart.1 new file mode 100644 index 00000000..cc4e9796 --- /dev/null +++ b/doc/man/config_restart.1 @@ -0,0 +1,33 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:restart" +.SH NAME +config:restart \- Restarts the proxy software. +.SH SYNOPSIS +config:restart [options] +.SH DESCRIPTION +The config:restart command restarts your proxy software. When you execute the +config:restart command, you may use one of the options described below. +.SS "cluster" +Specifies cluster-wide restart. +.SH EXAMPLES +When you execute the config:restart command, you see results in the following format. +.PP +.nf +traffic_shell> config:restart +traffic_shell> +.SH "SEE ALSO" +config:start, config:stop, config:hard-restart diff --git a/doc/man/config_root.1 b/doc/man/config_root.1 new file mode 100644 index 00000000..e527c515 --- /dev/null +++ b/doc/man/config_root.1 @@ -0,0 +1,34 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:root" +.SH NAME +config:root \- Switch to root user. +.SH SYNOPSIS +config:root +.SH DESCRIPTION +If you want to become the root user type the config:root command. +You will be prompted to enter the root password. The config:root command takes no options. +.SH EXAMPLE +.TP +.fi +When you execute the config:root command, you see the following: +.PP +.nf +traffic_shell> config:root +Password: (enter password) +traffic_shell# +.SH "SEE ALSO" +enable, disable, exit diff --git a/doc/man/config_scheduled-update.1 b/doc/man/config_scheduled-update.1 new file mode 100644 index 00000000..3b824349 --- /dev/null +++ b/doc/man/config_scheduled-update.1 @@ -0,0 +1,84 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:scheduled-update" +.SH NAME +config:scheduled-update \- Enables and configures the scheduled update option. +.SH SYNOPSIS +config:scheduled-update [options] +.SH DESCRIPTION +When you enable scheduled update, the proxy can automatically update certain +objects in the local cache at a specified time. When you execute the +config:scheduled-update command, you must use one of the options described +below. +.SH OPTIONS +The following options are supported for the config:scheduled-update command: +.SS "status " +Enables (on) or disables (off) the scheduled update option. When this option is +enabled, the proxy can automatically update certain objects in the local cache +at a specified time. (The default value is disabled.) +.SS "retry-count " +The retry count specifies the number of times the proxy can retry the scheduled +update of a URL in the event of failure. (The default value is 10.) +.SS "retry-interval " +The interval specifies the delay in seconds between each scheduled update retry for a URL in +the event of failure. (The default value is 2 seconds.) +.SS "max-concurrent " +Specifies the maximum number of simultaneous update requests allowed at any +point in time. This option prevents the scheduled update process from +overburdening the host. (The default value is 100.) +.SS "force-immediate " +Enables (on) or disables (off) a force immediate update. When enabled, the proxy +overrides the scheduling expiration time for all scheduled update entries and +initiates updates until this option is disabled.(The default value is disabled.) +.SS "rules " +Specifies the location (URL) from which the proxy should retrieve your scheduled +update rules file. The proxy retrieves your rules file and saves it locally as +update.config. The update.config file controls how the proxy performs a +scheduled update of specific local cache content. +Once you use the rules option with a URL, thereby saving your update.config +file, you can use the rules option (without typing a URL) to display the +update.config file. +.SH EXAMPLES +.SS "Example 1. Enabling the scheduled update option" +.PP +.nf +traffic_shell> config:scheduled-update on +traffic_shell> +.SS "Example 2. Specifying the number of retries allowed in case of failure and the delay between each retry" +.PP +.nf +traffic_shell> config:scheduled-update retry count 10 interval 2 +traffic_shell> +.SS "Example 3. Disabling the force immediate updates option" +.PP +.nf +traffic_shell> config:scheduled-update force-immediate off +traffic_shell> +.SS "Example 4. Specifying the location (URL) from which the proxy should retrieve your scheduled update rules file to be saved locally as the update.config file" +.PP +.nf +traffic_shell> config:scheduled-update rules http://somedomain.com/~path/rulesfile +traffic_shell> +.SS "Example 5. Displaying the update.config file" +.PP +.nf +traffic_shell> config:scheduled-update rules + update.config rules + ------------------- + (Displays the rules from the update.config file.) +traffic_shell> +.SH "SEE ALSO" +show:scheduled-update diff --git a/doc/man/config_security.1 b/doc/man/config_security.1 new file mode 100644 index 00000000..b3e23810 --- /dev/null +++ b/doc/man/config_security.1 @@ -0,0 +1,52 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:security" +.SH NAME +config:security \- This command enables you to apply Traffic Server and Traffic +Manager access configuration file settings to Traffic Server. +.SH SYNOPSIS +config:security [ip-allow | mgmt-allow | admin] [url-config-file] +.SH DESCRIPTION +The config:security command enables you to indicate from what URL Traffic Server +should retrieve the configuration file (IP_allow) that controls client access to +the Traffic Server proxy cache. The command also enables you to indicate from +what URL Traffic Server should retrieve the configuration file (mgmt_allow) that +controls remote host access to the Traffic Manager UI. Finally, the +config:security command enables you to indicate from what URL Traffic Server +should retrieve the configuration file (admin) (password) that controls +administrator access to Traffic Manager activities. +.SH OPTIONS +The following options are supported for the config:security command: +.SS "ip-allow " +Specifies the configuration file that controls client access to the Traffic +Server proxy cache. +.SS "mgmt-allow " +Specifies the configuration file that controls remote host access to the Traffic +Manager UI. +.SS "admin " +Specifies the configuration file that controls administrator access to Traffic +Manager activities. +.SS "password " +Specifies the administrator password that the administrator must use to access +the Traffic Manager UI. +.SH EXAMPLES +.SS "Example 1. Locating the access file to specify client access" +.PP +.nf +traffic_shell> config:security ip-allow http://something.com/ip_allow.config +traffic_shell> +.SH "SEE ALSO" +show:security diff --git a/doc/man/config_set.1 b/doc/man/config_set.1 new file mode 100644 index 00000000..9d08faa4 --- /dev/null +++ b/doc/man/config_set.1 @@ -0,0 +1,36 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:set" +.SH NAME +config:set \- Sets the value of a variable. +.SH SYNOPSIS +config:set [variable] +.SH DESCRIPTION +The config:set command enables you to set the value of a variable from the +records.config file. +.SH OPERANDS +The following operand is supported: +.SS " " +You must type the name of the records.config file variable for which you want to +set a value. +.SH EXAMPLES +When you execute the config:set command, you see results in the following format: +.PP +.nf +traffic_shell> config:set proxy.config.http.server_port 8080 +traffic_shell> +.SH "SEE ALSO" +config:get diff --git a/doc/man/config_socks.1 b/doc/man/config_socks.1 new file mode 100644 index 00000000..c2f6839a --- /dev/null +++ b/doc/man/config_socks.1 @@ -0,0 +1,60 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:socks" +.SH NAME +config:socks \- Enable and configure SOCKS. +.SH SYNOPSIS +config:socks [options] +.SH DESCRIPTION +You use the config:socks command to enable the SOCKS option and configure SOCKS +parameters, including default servers, version, and port values. +.SH OPTIONS +The following options are supported for the config:socks command: +.SS "status " +Enables (on) or disables (off) the SOCKS option. (The default value is +disabled.) +.SS "version " +Specifies the SOCKS version number. +.SS "default-servers " +Specifies the IP address of the SOCKS server. +.SS "accept " +Specifies whether SOCKS accept is on or off. +.SS "accept-port " +Specifies the port used by the proxy to communicate with the SOCKS server. (The +default value is 1080.) +.SH EXAMPLES +.SS "Example 1. Enabling the SOCKS option" +.PP +.nf +traffic_shell> config:socks mode on +traffic_shell> +.SS "Example 2. Specifying the SOCKS server IP address" +.PP +.nf +traffic_shell> config:socks server-ip 209.1.1.1 +traffic_shell> +.SS "Example 3. Specifying the port used by the proxy to communicate with the SOCKS server" +.PP +.nf +traffic_shell> config:socks port 1080 +traffic_shell> +.SS "Example 4. Specifying the timeout duration for the proxy to wait for a SOCKS server response" +.PP +.nf +traffic_shell> config:socks timeout 100 +traffic_shell> +.SH "SEE ALSO" +show:socks diff --git a/doc/man/config_ssl.1 b/doc/man/config_ssl.1 new file mode 100644 index 00000000..8f7d4e98 --- /dev/null +++ b/doc/man/config_ssl.1 @@ -0,0 +1,43 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:ssl" +.SH NAME +config:ssl \- Configures SSL protocol settings. +.SH SYNOPSIS +config:ssl [options] +.SH DESCRIPTION +The config:ssl command enables you to configure SSL protocol settings +through a variety of options. +You must use one of the options described below. +.SH OPTIONS +The following options are supported for the config:ssl command: +.SS "status " +Enables (on) or disables (off) SSL connections. +.SS "ports " +Specifies the port number for SSL. +.SH EXAMPLES +.SS "Example 1. Enabling SSL" +.PP +.nf +traffic_shell> config:ssl status on +traffic_shell> +.SS "Example 2. Specifying the SSL port number" +.PP +.nf +traffic_shell> config:ssl port 4443 +traffic_shell> +.SH "SEE ALSO" +show:ssl diff --git a/doc/man/config_start.1 b/doc/man/config_start.1 new file mode 100644 index 00000000..28be29b4 --- /dev/null +++ b/doc/man/config_start.1 @@ -0,0 +1,32 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:start" +.SH NAME +config:start \- Starts the proxy software. +.SH SYNOPSIS +config:start +.SH DESCRIPTION +The config:start command starts your proxy software. The config:start command +takes no options. +.SH EXAMPLES +When you execute the config:start command, you see results in the following +format: +.PP +.nf +traffic_shell> config:start +traffic_shell> +.SH "SEE ALSO" +config:stop, config:restart, config:hard-restart diff --git a/doc/man/config_stop.1 b/doc/man/config_stop.1 new file mode 100644 index 00000000..e7b15eac --- /dev/null +++ b/doc/man/config_stop.1 @@ -0,0 +1,31 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:stop" +.SH NAME +config:stop \- Stops the proxy software. +.SH SYNOPSIS +config:stop +.SH DESCRIPTION +The config:stop command stops your proxy software. The config:stop command takes +no options. +.SH EXAMPLES +When you execute the config:stop command, you see results in the following format. +.PP +.nf +traffic_shell> config:stop +traffic_shell> +.SH "SEE ALSO" +config:start, config:restart, config:hard-restart diff --git a/doc/man/config_upgrade.1 b/doc/man/config_upgrade.1 new file mode 100644 index 00000000..c3935594 --- /dev/null +++ b/doc/man/config_upgrade.1 @@ -0,0 +1,52 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:upgrade" +.SH NAME +config:upgrade \- Perform an over-the-wire software upgrade. +.SH SYNOPSIS +config:upgrade [username] [password] +.SH DESCRIPTION +You use the config:upgrade command to perform over-the-wire software upgrades. +This command supports three types of upgrades: silent, interactive, and reinstall. +When you use this command, you must specify an upgrade server URL, +and optionally specify a username and password. This command requires root privileges. +Use the config:root command to switch to root user. +.SH OPTIONS +The following options are required for the config:upgrade command: +.SS "" +Silent upgrade automatically chooses the appropriate upgrade from the upgrade server. +Interactive upgrade allows you to choose the upgrade package from a list. +Reinstall allows you to install an older version of software with default +configuration settings. +.SS "" +Specifies the URL which is the location of the upgrade files on a remote +server.If the URL is for HTTP or HTTPS, then username and password are optional. +.SS "" +Specifies the username that is used to access the URL on the remote server. +.SS "" +Specifies the password that is used to access the URL on the remote server. +If a username is specified, but the password is omitted, then the config:upgrade command +will prompt you to enter a password. + +.SH EXAMPLES +.SS "Example 1. Perform a silent upgrade" +.PP +.nf +traffic_shell> config:upgrade silent http://upgradeserver.domain.com user password +(Upgrade command status messages) +traffic_shell> +.SH "SEE ALSO" +config:root diff --git a/doc/man/config_virtual-ip.1 b/doc/man/config_virtual-ip.1 new file mode 100644 index 00000000..62f4e551 --- /dev/null +++ b/doc/man/config_virtual-ip.1 @@ -0,0 +1,52 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "config:virtual-ip" +.SH NAME +config:virtual-ip \- Enables and configures virtual IP addressing. +.SH SYNOPSIS +config:virtual-ip [options] +.SH DESCRIPTION +You use the config:virtual-ip command to enable and configure virtual IP +addressing, including IP address, device, and subinterface. +.SH OPTIONS +The following options are supported for the config:virtual-ip command: +.SS "status " +Enables (on) or disables (off) the virtual IP option. (The default value is +off.) +.SS "list" +List the virtual IP addresses in use. +.SS "add device sub-intf " +Specifies IP address, device and subinterface. +.SS "delete " +Specified Virtual IP address element to be deleted. +.SH EXAMPLES +.SS "Example 1. Enabling the virtual IP option" +.PP +.nf +traffic_shell> config:virtual-ip on +traffic_shell> +.SS "Example 2. Specifying an IP address, device, and subinterface" +.PP +.nf +traffic_shell> config:virtual-ip add ip 202.112.105.89 device hme0 sub-intf 28 +traffic_shell> +.SS "Example 3. Deleting a virtual IP address." +.PP +.nf +traffic_shell> config:virtual-ip delete 1 +traffic_shell> +.SH "SEE ALSO" +show:virtual-ip diff --git a/doc/man/disable.1 b/doc/man/disable.1 new file mode 100644 index 00000000..1254d84e --- /dev/null +++ b/doc/man/disable.1 @@ -0,0 +1,33 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "disable" +.SH NAME +disable \- Disable privileged commands. +.SH SYNOPSIS +disable +.SH DESCRIPTION +If you are in Configure mode and want to return to Monitor mode, type +the disable command. The disable command has no options. +.SH EXAMPLE +.TP +.fi +When you execute the disable command, you see the following: +.PP +.nf +traffic_shell> disable +traffic_shell> +.SH "SEE ALSO" +enable, config:root, exit diff --git a/doc/man/enable.1 b/doc/man/enable.1 new file mode 100644 index 00000000..bb60cb6e --- /dev/null +++ b/doc/man/enable.1 @@ -0,0 +1,42 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "enable" +.SH NAME +enable \- Enable privileged commands. +.SH SYNOPSIS +enable +.SH DESCRIPTION +If you are in Monitor mode and want to enter Configure mode, type +the enable command. You will be prompted to enter the administrator password. +.SH OPTIONS +The following options are supported for the enable command: +.SS "status" +Display the enable status, on or off. +.SH EXAMPLE +.TP +.fi +When you execute the enable command, you see the following: +.PP +.nf +traffic_shell> enable status +off +traffic_shell> enable +Password: (enter password) +traffic_shell> enable status +on +traffic_shell> +.SH "SEE ALSO" +config:root, disable, exit diff --git a/doc/man/exit.1 b/doc/man/exit.1 new file mode 100644 index 00000000..33e4e966 --- /dev/null +++ b/doc/man/exit.1 @@ -0,0 +1,34 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "exit" +.SH NAME +exit \- Type exit to end your CLI session. +.SH SYNOPSIS +exit +.SH DESCRIPTION +Use the exit command while in show or configure mode to end your CLI +session. After you use the exit command, you return to your normal UNIX +prompt. The exit command has no options. +.SH EXAMPLE +.PP +.fi +When you execute the exit command, you see results in the following format: +.PP +traffic_shell> exit +.TP +[username@hostname bin]# +.SH "SEE ALSO" +enable, disable diff --git a/doc/man/man_page_template.txt b/doc/man/man_page_template.txt new file mode 100644 index 00000000..044911b1 --- /dev/null +++ b/doc/man/man_page_template.txt @@ -0,0 +1,67 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "" 1 +.SH NAME + \- +.SH SYNOPSIS +.B + +.SH DESCRIPTION + +.SH OPTIONS +.TP +.B \- + +.TP +.B \- + +.TP +.B +.SH "SEE ALSO" + +.SH BUGS + +.SH Reference +http://www.cs.hmc.edu/tech_docs/qref/writing_man_pages.html + + + +Review comments on man pages +----------------------------- +1. No extra blank lines specified on any section. +2. Formatting of the synopsis section should be consistent with + a. -help + b. cli_detailed_command_list.txt + c. Man page section. + +3. Only options sections should be present. All operand section should be moved to options section. + + 3.a. Any missing Option section should be listed in the section. + (Look in the spec and the example listed in the man page to fill up the option section.) + +4. Execute the command and see if it is consistent. File a DDTS bug if the command does not work fine as the detailed_spec. + +5. All example section should be aligned correctly. + Use the following formats to achieve this option. + a. Change All .TP command to .PP (For paragraphs.) + b. For example use .PP followed by .fi + +6. Prompt to be replaced to traffic_shell> + +7. All commands should return either +OK or -ERROR after execution. + + + diff --git a/doc/man/show_alarms.1 b/doc/man/show_alarms.1 new file mode 100644 index 00000000..372f5ac9 --- /dev/null +++ b/doc/man/show_alarms.1 @@ -0,0 +1,33 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:alarms" +.SH NAME +show:alarms \- This command displays information about active alarms. +.SH SYNOPSIS +show:alarms +.SH DESCRIPTION +The show:alarms command displays a list of active alarms. +The show:alarms command takes no options. +.SH EXAMPLE +When you execute the show:alarms command, you see results in the following format: +.PP +.nf +traffic_shell> show:alarm +Active Alarms + 1. MGMT_ALARM_PROXY_PROCESS_DIED +traffic_shell> +.SH "SEE ALSO" +config:alarms diff --git a/doc/man/show_cache-stats.1 b/doc/man/show_cache-stats.1 new file mode 100644 index 00000000..79343820 --- /dev/null +++ b/doc/man/show_cache-stats.1 @@ -0,0 +1,60 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:cache-stats" +.SH NAME +show:cache-stats \- This command displays a summary of cache statistics. +.SH SYNOPSIS +show:cache-stats +.SH DESCRIPTION +The show:cache-stats command displays a summary of cache statistics, including +RAM cache, lookups, reads, writes, updates, and removes detail. The show:cache- +stats command takes no options. +.SH EXAMPLE +When you execute the show:cache-stats command, you see results in the following +format: +.PP +.nf +traffic_shell> show:cache-stats +Bytes Used --- 0 GB +Cache Size --- 0 GB +--RAM Cache-- +Total Bytes -- 0 +Bytes Used --- 0 +Hits --------- 0 +Misses ------- 0 +--Lookups-- +In Progress -- 0 +Hits --------- 0 +Misses ------- 0 +--Reads-- +In Progress -- 0 +Hits --------- 0 +Misses ------- 0 +--Writes-- +In Progress -- 0 +Hits --------- 0 +Misses ------- 0 +--Updates-- +In Progress -- 0 +Hits --------- 0 +Misses ------- 0 +--Removes-- +In Progress -- 0 +Hits --------- 0 +Misses ------- 0 +traffic_shell> +.SH "SEE ALSO" +show:cache, config:cache diff --git a/doc/man/show_cache.1 b/doc/man/show_cache.1 new file mode 100644 index 00000000..eda329d3 --- /dev/null +++ b/doc/man/show_cache.1 @@ -0,0 +1,70 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:cache" +.SH NAME +show:cache \- This command displays cache configuration information. +.SH SYNOPSIS +show:cache [rules | storage] +.SH DESCRIPTION +Execute the show:cache command to view basic cache configuration information, or type the servers +or access options to display access. +.SH OPTIONS +The following options are supported for the show:cache command: +.SS rules +The rules option enables you to specify the caching parameters of specific objects or sets of +objects. +.SS storage +The storage option displays the storage.confg file, which lists all the files, directories, or +hard disk partitions that make up the cache. +.SH EXAMPLES +.SS "Example 1. Displaying basic cache configuration information" +.PP +.nf +traffic_shell> show:cache +HTTP Caching --------------------------- on +Ignore User Requests To Bypass Cache --- off +Maximum HTTP Object Size ----------- NONE +Freshness + Verify Freshness By Checking --------- When The Object Has Expired + Minimum Information to be Cacheable -- Nothing + If Object has no Expiration Date: + Leave it in Cache for at least ----- 3600 s + but no more than ------------------- 86400 s +Variable Content + Cache Responses to URLs that contain + "?",";","cgi" or end in ".asp" ----- off + Alternates Enabled ------------------- off + Vary on HTTP Header Fields: + Text ------------------------------- NULL + Images ----------------------------- NULL + Other ------------------------------ NULL + Cache responses to requests containing cookies for: + Content Types which are not Text +traffic_shell> +.SS "Example 2. Displaying cache.config file rules" +.PP +.nf +traffic_shell> show:cache rules +(Displays rules from the cache.config file.) +traffic_shell> +.SS "Example 3. Displaying the storage.config file rules" +.PP +.nf +traffic_shell> show:cache storage +(Displays rules from the storage.config file.) +traffic_shell> +.SH "SEE ALSO" +config:cache diff --git a/doc/man/show_cluster.1 b/doc/man/show_cluster.1 new file mode 100644 index 00000000..6907c0ac --- /dev/null +++ b/doc/man/show_cluster.1 @@ -0,0 +1,35 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:cluster" +.SH NAME +show:cluster \- This command displays the cluster port. +.SH SYNOPSIS +show:cluster +.SH DESCRIPTION +The show:cluster command displays the ports used for cluster communication. The +show:cluster command takes no options. +.SH EXAMPLE +.PP +When you execute the show:cluster command, you see results in the following +format: +.PP +.nf +traffic_shell> show:cluster + +Cluster Port ----------- 8086 +Cluster RS Port -------- 8088 +Cluster MC Port -------- 8089 +traffic_shell> diff --git a/doc/man/show_dns-resolver.1 b/doc/man/show_dns-resolver.1 new file mode 100644 index 00000000..63d68e1d --- /dev/null +++ b/doc/man/show_dns-resolver.1 @@ -0,0 +1,37 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:dns-resolver" +.SH NAME +show:dns-resolver \- This command displays DNS Resolver configuration +information. +.SH SYNOPSIS +show:dns-resolver +.SH DESCRIPTION +The show:dns-resolver command displays the DNS Resolver configuration +information, including local domain expansion configuration (see example below). +The show:dns-resolver command takes no options. +.SH EXAMPLE +.PP +When you execute the show:dns-resolver command, you see results in the following +format: +.PP +.nf +traffic_shell> show:dns-resolver +Local Domain Expansion -- on + .com Domain Expansion --- on +traffic_shell> +.SH "SEE ALSO" +config:dns diff --git a/doc/man/show_dns-stats.1 b/doc/man/show_dns-stats.1 new file mode 100644 index 00000000..db41b44c --- /dev/null +++ b/doc/man/show_dns-stats.1 @@ -0,0 +1,34 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:dns-stats" +.SH NAME +show:dns-stats \- This command displays DNS statistics. +.SH SYNOPSIS +show:dns-stats +.SH DESCRIPTION +The show:dns-stats command displays DNS statistics, including DNS lookup detail. +The show:dns-stats command takes no options. +.SH EXAMPLE +.PP +When you execute the show:dns-stats command, you see results in the following +format: +.PP +.nf +traffic_shell> show:dns-stats +DNS Lookups Per Second -- 0.000000 +traffic_shell> +.SH "SEE ALSO" +config:dns diff --git a/doc/man/show_hostdb-stats.1 b/doc/man/show_hostdb-stats.1 new file mode 100644 index 00000000..6efe1375 --- /dev/null +++ b/doc/man/show_hostdb-stats.1 @@ -0,0 +1,35 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:hostdb-stats" +.SH NAME +show:hostdb-stats \- This command displays host database statistics. +.SH SYNOPSIS +show:hostdb-stats +.SH DESCRIPTION +The show:hostdb-stats command displays host database statistics, including hit +rate and DNS lookup detail. The show:hostdb-stats command takes no options. +.SH EXAMPLE +.PP +When you execute the show:hostdb-stats command, you see results in the following format: +.PP +.nf +traffic_shell> show:hostdb-stats +Host Database hit Rate -- 99.988437%I * +DNS Lookups Per Second -- 0.000000 +* Value reprensents 10 second average. +traffic_shell> +.SH "SEE ALSO" +config:hostdb diff --git a/doc/man/show_hostdb.1 b/doc/man/show_hostdb.1 new file mode 100644 index 00000000..6cccfaa4 --- /dev/null +++ b/doc/man/show_hostdb.1 @@ -0,0 +1,40 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:hostdb" +.SH NAME +show:hostdb \- This command displays host database configuration information. +.SH SYNOPSIS +show:hostdb +.SH DESCRIPTION +The show:hostdb command displays the host database configuration information, +including various timeout values and number of retries (see example below). The +show:hostdb command takes no options. +.SH EXAMPLE +.PP +When you execute the show:hostdb command, you see results in the following format: +.PP +.nf +traffic_shell> show:hostdb +Lookup Timeout ----------- 120 s +Foreground Timeout ------- 1440 s +Background Timeout ------- 720 s +Invalid Host Timeout ----- 0 s +Re-DNS on Reload --------- off +Resolve Attempt Timeout -- 20 s +Number of retries -------- 5 +traffic_shell> +.SH "SEE ALSO" +config:hostdb diff --git a/doc/man/show_http-stats.1 b/doc/man/show_http-stats.1 new file mode 100644 index 00000000..9edeef03 --- /dev/null +++ b/doc/man/show_http-stats.1 @@ -0,0 +1,43 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:http-stats" +.SH NAME +show:http-stats \- This command displays HTTP protocol statistics. +.SH SYNOPSIS +show:http-stats +.SH DESCRIPTION +The show:http-stats command displays HTTP protocol statistics, including +document and header size and connections values. The show:http-stats command +takes no options. +.SH EXAMPLE +.PP +When you execute the show:http-stats command, you see results in the following format: +.PP +.nf +traffic_shell> show:http-stats +--Client-- +Total Document Bytes ----- 0 MB +Total Header Bytes ------- 0 MB +Total Connections -------- 0 +Transactins In Progress -- 0 +--Server-- +Total Document Bytes ----- 0 MB +Total Header Bytes ------- 0 MB +Total Connections -------- 0 +Transactins In Progress -- 0 +traffic_shell> +.SH "SEE ALSO" +show:cache, show:http-trans-stats, config:http diff --git a/doc/man/show_http-trans-stats.1 b/doc/man/show_http-trans-stats.1 new file mode 100644 index 00000000..2714fa79 --- /dev/null +++ b/doc/man/show_http-trans-stats.1 @@ -0,0 +1,55 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:http-trans-stats" +.SH NAME +show:http-trans-stats \- This command displays HTTP transaction statistics. +.SH SYNOPSIS +show:http-trans-stats +.SH DESCRIPTION +The show:http-trans-stats command displays HTTP transaction statistics, +including hit, miss, and abort details. The show:http-trans-stats command takes +no options. +.SH EXAMPLE +.PP +When you execute the show:http-trans-stats command, you see results in the +following format: +.PP +.nf +traffic_shell> show:http-trans-stats +HTTP Transaction Frequency and Speeds +Transaction Type Frequency Speed(ms) +--Hits-- +Fresh ----------------------- 0.000000% 0 +Stale Revalidated ----------- 0.000000% 0 +--Misses-- +Now Cached ------------------ 0.000000% 0 +Server No Cache ------------- 0.000000% 0 +Stale Reloaded -------------- 0.000000% 0 +Client No Cache ------------- 0.000000% 0 +--Errors-- +Connection Failures --------- 0.000000% 0 +Other Errors ---------------- 0.000000% 0 +--Aborted Transactions-- +Client Aborts --------------- 0.000000% 0 +Questionable Client Aborts -- 0.000000% 0 +Partial Request Hangups ----- 0.000000% 0 +Pre-Request Hangups --------- 0.000000% 0 +Pre-Connect Hangups --------- 0.000000% 0 +--Other Transactions-- +Unclassified ---------------- 0.000000% 0 +traffic_shell> +.SH "SEE ALSO" +show:cache-stats, show:http-stats, config:http diff --git a/doc/man/show_http.1 b/doc/man/show_http.1 new file mode 100644 index 00000000..459e9b40 --- /dev/null +++ b/doc/man/show_http.1 @@ -0,0 +1,45 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:http" +.SH NAME +show:http \- This command displays HTTP configuration. +.SH SYNOPSIS +show:http +.SH DESCRIPTION +Execute the show:http command to view HTTP configuration information, such as +timeouts values, header insertions, and port specifications. The show:http command +takes no options. +.SH EXAMPLE +.PP +When you execute the show:http command, you see results in the following format: +.PP +.nf +traffic_shell> show:http +HTTP Caching ------------------ on +HTTP Server Port -------------- 8080 +HTTP Other Ports -------------- NULL +Keep-Alive Timeout Inbound ---- 10 s +Keep-Alive Timeout Outbound --- 10 s +Inactivity Timeout Inbound ---- 120 s +Inactivity Timeout Outbound --- 120 s +Activity Timeout Inbound ------ 7200 s +Activity Timeout Outbound ----- 7200 s +Maximum Number of Alternates -- 3 +Remove additional headers ----- NULL +Insert Client IP Address into Header +traffic_shell> +.SH "SEE ALSO" +show:cache, show:proxy, show:proxy-stats, show:cache-stats, config:reset-stats diff --git a/doc/man/show_icp-stats.1 b/doc/man/show_icp-stats.1 new file mode 100644 index 00000000..3a2fb65b --- /dev/null +++ b/doc/man/show_icp-stats.1 @@ -0,0 +1,46 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:icp-stats" +.SH NAME +show:icp-stats \- This command displays ICP statistics. +.SH SYNOPSIS +show:icp-stats +.SH DESCRIPTION +The show:icp-stats command displays ICP statistics, including query, hit, and +miss values. The show:icp-stats command takes no options. +.SH EXAMPLE +.PP +When you execute the show:icp-stats command, you see results in the following +format: +.PP +.nf +traffic_shell> show:icp-stats +--Queries Originating From This Node-- +Query Requests ----------------------------- 0 +Query Messages Sent ------------------------ 0 +Peer Hit Messages Received ----------------- 0 +Peer Miss Messages Received ---------------- 0 +Total Responses Received ------------------- 0 +Average ICP Message Response Time ---------- 0.000000 ms +Average ICP Request Time ------------------- 0.000000 ms +--Queries Originating from ICP Peers-- +Query Messages Received -------------------- 0 +Remote Query Hits -------------------------- 0 +Remote Query Misses ------------------------ 0 +Successful Response Message Sent to Peers -- 0 +traffic_shell> +.SH "SEE ALSO" +config:icp diff --git a/doc/man/show_icp.1 b/doc/man/show_icp.1 new file mode 100644 index 00000000..36bfa0ca --- /dev/null +++ b/doc/man/show_icp.1 @@ -0,0 +1,73 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:icp" +.SH NAME +show:icp \- This command displays ICP configuration. +.SH SYNOPSIS +show:icp [peers] +.SH DESCRIPTION +The show:icp command displays ICP configuration settings, including connectivity +and timeout and expiration values. The show:icp command takes no options. +.SH OPTIONS +The following option is supported for the show:icp command: +.SS peers +The peers option describes ICP parent and sibling configuration. +.SH EXAMPLES +.SS "Example 1. Displaying ICP configuration information" +.PP +.nf +traffic_shell> show:icp +ICP Mode Enabled ------- off +ICP Port --------------- 3130 +ICP Multicast Enabled -- off +ICP Query Timeout ------ 2 s +traffic_shell> +.SS "Example 2. Describing ICP parent and sibling configuration" +.PP +.nf +traffic_shell> show:icp peers +icp.config Rules +------------------- +########################################################### +# +# ICP Configuration -- Defines ICP parent/sibling configuration +# +# Each line is formatted as follows with ":" separator for each field. +# - hostname (string) -- Identifier for entry +# - host_ip_str (string) -- decimal dot notation +# - ctype (int) -- 1=Parent, 2=Sibling +# - proxy_port (int) -- TCP Port # +# - icp_port (int) -- UDP Port # +# - multicast_member -- 0=No 1=Yes +# - multicast_ip_str (string) -- decimal dot notation +# 224.0.0.0 - 239.255.255.255 +# - multicast_ttl (int) -- (1 - 2; default 1) +# +# :::::::: +# +# Example #1 (1 parent and 1 sibling): +# ========================================================= +# host1:209.1.33.10:1:8080:3130:0:0.0.0.0:1: +# host2:209.1.33.11:2:8080:3130:0:0.0.0.0:1: +# +# +# Example #2 (1 parent and 1 sibling using MultiCast): +# ========================================================= +# host1:209.1.33.10:1:8080:3130:1:239.128.16.128:1: +# host2:209.1.33.11:2:8080:3130:1:239.128.16.128:1: +traffic_shell> +.SH "SEE ALSO" +show:icp-stats, config:icp diff --git a/doc/man/show_logging-stats.1 b/doc/man/show_logging-stats.1 new file mode 100644 index 00000000..44072f3b --- /dev/null +++ b/doc/man/show_logging-stats.1 @@ -0,0 +1,39 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:logging-stats" +.SH NAME +show:logging-stats \- This command displays logging statistics. +.SH SYNOPSIS +show:logging-stats +.SH DESCRIPTION +The show:logging-stats command displays logging statistics, including storage, +events logged, and events skipped. The show:logging-stats command takes no +options. +.SH EXAMPLE +.PP +When you execute the show:logging-stats command, you see results in the +following format: +.PP +.nf +traffic_shell> show:logging-stats +Current Open Log Files ----------- 0 +Space Used For Log Files --------- 13697 +Number of Access Events Logged --- 0 +Number of Access Events Skipped -- 0 +Number of Error Events Logged ---- 0 +traffic_shell> +.SH "SEE ALSO" +config:logging diff --git a/doc/man/show_logging.1 b/doc/man/show_logging.1 new file mode 100644 index 00000000..67847b01 --- /dev/null +++ b/doc/man/show_logging.1 @@ -0,0 +1,69 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:logging" +.SH NAME +show:logging \- This command displays logging configuration information. +.SH SYNOPSIS +show:logging +.SH DESCRIPTION +The show:logging command displays logging configuration information, including +collation, management, format, and rolling configuration (see example below). +The show:logging command takes no options. +.SH EXAMPLE +.PP +When you execute the show:logging command, you see results in the following +format: +.PP +.nf +traffic_shell> show:logging +Logging Mode ----------------------------- errors and transactions +Management + Log Space Limit ------------------------ 2000 MB + Log Space Headroom --------------------- 10 MB +Log Collation ---------------------------- off + Host ----------------------------------- NULL + Port ----------------------------------- 8085 + Secret --------------------------------- foobar + Host Tagged ---------------------------- off + Space Limit for Orphan Files ----------- 25 MB +Squid Format ----------------------------- on + File Type ------------------------------ ASCII + File Name ------------------------------ squid + File Header ---------------------------- NULL +Netscape Common -------------------------- off + File Type ------------------------------ ASCII + File Name ------------------------------ common + File Header ---------------------------- NULL +Netscape Extended ------------------------ off + File Type ------------------------------ ASCII + File Name ------------------------------ extended + File Header ---------------------------- NULL +Netscape Extended2 ----------------------- off + File Type ------------------------------ ASCII + File Name ---------------------------- extended2 + File Header ---------------------------- NULL +Splitting + ICP Log Splitting ---------------------- off + HTTP Host Log Splitting ---------------- off +Custom Logs ------------------------------ off +Custom Log Definition Format ------------- Traditional +Rolling ---------------------------------- on + Roll Offset Hour ----------------------- 0 + Roll Interval -------------------------- 86400 s + Auto-delete rolled files (low space) --- on +traffic_shell> +.SH "SEE ALSO" +config:logging diff --git a/doc/man/show_network.1 b/doc/man/show_network.1 new file mode 100644 index 00000000..9fe53c9a --- /dev/null +++ b/doc/man/show_network.1 @@ -0,0 +1,51 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:network" +.SH NAME +show:network \- Basic network parameters. +.SH SYNOPSIS +show:network +.SH DESCRIPTION +The show:network command displays the values for basic network parameters. The +show:network command takes no options. +.SH EXAMPLE +.PP +When you execute the show:network command, you see results in the following +format: +.PP +.nf +traffic_shell> show:network +Hostname ---------------- hostname.domain.com +Default Gateway --------- x.x.x.x +Search Domain ----------- domain.com +DNS IP Addresses--------- x.x.x.x +NIC eth0 + Status ---------------- up + Start on Boot --------- onboot + Start Protocol -------- none + IP Address ------------ x.x.x.x + Netmask --------------- x.x.x.x + Gateway --------------- default +NIC eth1 + Status ---------------- up + Start on Boot --------- onboot + Start Protocol -------- none + IP Address ------------ x.x.x.x + Netmask --------------- x.x.x.x + Gateway --------------- default +traffic_shell> +.SH "SEE ALSO" +config:network diff --git a/doc/man/show_parent.1 b/doc/man/show_parent.1 new file mode 100644 index 00000000..811ffa1b --- /dev/null +++ b/doc/man/show_parent.1 @@ -0,0 +1,50 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:parent" +.SH NAME +show:parent \- This command displays parent configuration information. +.SH SYNOPSIS +show:parent [rules] +.SH DESCRIPTION +The show:parent command displays parent configuration details, specifying +whether parent caching is enabled and identifying the parent cache, if +appropriate. The show:parent command takes an option called rules and returns +additional details. +.SH OPTIONS +.SS rules +The rules option enables you to specify the parent proxy and parent directives +for specific objects or sets of objects. +.SH EXAMPLES +When you execute the show:parent command, you see results in the following +format: +.SS "Example 1. Displaying basic parent configuration information" +.PP +.nf +traffic_shell> show:parent +Parent Caching -- off +Parent Cache ---- NULL +traffic_shell> +.SS "Example 2. Displaying parent configuration rules," +.SS " including parent directives" +.PP +.nf +traffic_shell> show:parent rules +parent.config rules +------------------- +(Displays the rules in the parent.config file.) +traffic_shell> +.SH "SEE ALSO" +config:parent diff --git a/doc/man/show_port-tunnels.1 b/doc/man/show_port-tunnels.1 new file mode 100644 index 00000000..8a42fa88 --- /dev/null +++ b/doc/man/show_port-tunnels.1 @@ -0,0 +1,37 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:port-tunnels" +.SH NAME +show:port-tunnels \- This command displays the ports through which the proxy may +tunnel. +.SH SYNOPSIS +show:port-tunnels +.SH DESCRIPTION +Execute the show:port-tunnels command to see the tunneling ports. The show:port- +tunnels command takes no options. +.SH EXAMPLE +When you execute the show:port-tunnels command, you see results in the following +format: +.PP +.nf +traffic_shell> show:port-tunnels +server-other-ports -- NULL +To view the corresponding rule of the remap.config file in the following format +map tunnel://:/tunnel://: +use show:remap +traffic_shell> +.SH "SEE ALSO" +config:port-tunnels, show:remap diff --git a/doc/man/show_proxy-stats.1 b/doc/man/show_proxy-stats.1 new file mode 100644 index 00000000..392c4f30 --- /dev/null +++ b/doc/man/show_proxy-stats.1 @@ -0,0 +1,42 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:proxy-stats" +.SH NAME +show:proxy-stats \- This command displays a summary of proxy statistics. +.SH SYNOPSIS +show:proxy-stats +.SH DESCRIPTION +The show:proxy-stats command displays a summary of global proxy statistics, +including hit rate, bandwidth saving, open connections, and throughput. The +show:proxy-stats command takes no options. +.SH EXAMPLE +When you execute the show:proxy-stats command, you see results in the following +format: +.PP +.nf +traffic_shell> show:proxy-stats +Document Hit Rate -------- 0.000000% * +Bandwidth Saving --------- 0.000000% * +Cache Percent Free ------- 0.000000% +Open Server Connections -- 0 +Open Client Connections -- 0 +Open Cache Connections --- 0 +Client Throughput -------- 0.000000 MBit/Sec +Transaction Per Second --- 0.100000 +* Value represents 10 second average. +traffic_shell> +.SH "SEE ALSO" +show:cache, config:cache diff --git a/doc/man/show_proxy.1 b/doc/man/show_proxy.1 new file mode 100644 index 00000000..014dcc14 --- /dev/null +++ b/doc/man/show_proxy.1 @@ -0,0 +1,32 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:proxy" +.SH NAME +show:proxy \- This command displays the proxy name. +.SH SYNOPSIS +show:proxy +.SH DESCRIPTION +Execute the show:proxy command to see the name of the proxy. The show:proxy +command takes no options. +.SH EXAMPLE +When you execute the show:proxy command, you see results in the following format: +.PP +.nf +traffic_shell> show:proxy +Name -- rubicon +traffic_shell> +.SH "SEE ALSO" +show:proxy-stats diff --git a/doc/man/show_remap.1 b/doc/man/show_remap.1 new file mode 100644 index 00000000..9f4b380e --- /dev/null +++ b/doc/man/show_remap.1 @@ -0,0 +1,36 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:remap" +.SH NAME +show:remap \- This command displays logging configuration information. +.SH SYNOPSIS +show:remap +.SH DESCRIPTION +The show:remap command displays logging configuration information, including +collation, management, format, and rolling configuration (see example below). +The show:remap command takes no options. +.SH EXAMPLE +When you execute the show:remap command, you see results in the following format +(comments included with the format example): +.PP +.nf +traffic_shell> show:remap +remap.config rules +------------------- +(Displays rules from remap.config.) +traffic_shell> +.SH "SEE ALSO" +config:remap diff --git a/doc/man/show_scheduled-update.1 b/doc/man/show_scheduled-update.1 new file mode 100644 index 00000000..6a14452d --- /dev/null +++ b/doc/man/show_scheduled-update.1 @@ -0,0 +1,53 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:scheduled-update" +.SH NAME +show:scheduled-update \- This command displays basic object-update information. +.SH SYNOPSIS +show:scheduled-update [rules] +.SH DESCRIPTION +With scheduled update, the proxy loads specific objects into the cache at scheduled times. +Execute the show:scheduled-update command to view basic object-update information, which +includes whether scheduled update is enabled, as well as error retry and concurrent update +values. +.SH OPTIONS +The following option is supported for the show:scheduled-update command: +.SS rules +The rules option displays update.config file configuration detail. The file contains a list of +URLs specifying objects that you want to schedule for update. Be aware that the system validates +these URLs for syntactic correctness, but not for existence. +.SH EXAMPLES +.SS "Example 1. Displaying basic object-update configuration" +.SS " information" +.PP +.nf +traffic_shell> show:scheduled-update +Scheduled Update ------------- off +Update Error Retry Count ----- 10 +Update Error Retry Interval -- 2 s +Maximum Concurrent Updates --- 100 +Force Immediate Update ------- off +traffic_shell> +.SS "Example 2. Displaying update.config file rules" +.PP +.nf +traffic_shell> show:scheduled-update rules +update.config rules +------------------- +(Displays rules from the update.config file.) +traffic_shell> +.SH "SEE ALSO" +config:scheduled-update diff --git a/doc/man/show_security.1 b/doc/man/show_security.1 new file mode 100644 index 00000000..20596f97 --- /dev/null +++ b/doc/man/show_security.1 @@ -0,0 +1,37 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:security" +.SH NAME +show:security \- This command displays key security port assignments and the +clients and hosts that have access to Traffic Server and Traffic Server Manager. +.SH SYNOPSIS +show:security +.SH DESCRIPTION +The show:security command displays the web interface This command takes +no options. +.SH EXAMPLE +When you execute the show:security command, you see results in the following +format: +.PP +.nf +traffic_shell> show:security +Web Interface Port ----- 8081 +Overseer Port ---------- 8082 +Traffic Server Access + (ip_allow.config contents) +traffic_shell> +.SH "SEE ALSO" +config:security diff --git a/doc/man/show_socks.1 b/doc/man/show_socks.1 new file mode 100644 index 00000000..ab0c0c02 --- /dev/null +++ b/doc/man/show_socks.1 @@ -0,0 +1,47 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:socks" +.SH NAME +show:socks \- This command displays SOCKS configuration information. +.SH SYNOPSIS +show:socks [rules] +.SH DESCRIPTION +Execute the show:socks command to view basic SOCKS configuration information, which include whether SOCKS is enabled, as well as default servers, version, and port values. +.SH OPTION +The following option is supported for the show:socks command: +.SS "[ rules ]" +The rules option displays SOCKS configuration detail from the socks.config file. +.SH EXAMPLES +.SS "Example 1. Displaying basic SOCKS configuration information" +.PP +.nf +traffic_shell> show:socks +SOCKS -------------------- off +SOCKS Version ------------ 4 +SOCKS Default Servers ---- s1.example.com:1080;socks2:4080 +SOCKS Accept Enabled ----- off +SOCKS Accept Port -------- 1080 +traffic_shell> +.SS "Example 2. Displaying socks.config file rules" +.PP +.nf +traffic_shell> show:socks rules +socks.config rules +------------------- +(Displays rules from the socks.config file.) +traffic_shell> +.SH "SEE ALSO" +config:socks diff --git a/doc/man/show_ssl.1 b/doc/man/show_ssl.1 new file mode 100644 index 00000000..25f809b4 --- /dev/null +++ b/doc/man/show_ssl.1 @@ -0,0 +1,33 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:ssl" +.SH NAME +show:ssl \- This command displays SSL port configuration. +.SH SYNOPSIS +show:ssl +.SH DESCRIPTION +The show:ssl command displays SSL port configuration information. The show:ssl +command takes no options. +.SH EXAMPLE +.SS "When you execute the show:ssl command, you see results in the" +.SS "following format" +.PP +.nf +traffic_shell> show:ssl +Restrict SSL Connections to Ports -- 443 563 +traffic_shell> +.SH "SEE ALSO" +config:ssl diff --git a/doc/man/show_status.1 b/doc/man/show_status.1 new file mode 100644 index 00000000..910761cf --- /dev/null +++ b/doc/man/show_status.1 @@ -0,0 +1,33 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:status" +.SH NAME +show:status \- This command shows you whether the proxy is running. +.SH SYNOPSIS +show:status +.SH DESCRIPTION +If you want confirmation that the proxy is running, use the show:status command. +The show:status command has no arguments. +.SH EXAMPLE +.SS "When you execute the show:status command, you see the " +.SS "following if the proxy is on." +.PP +.nf +traffic_shell> show:status +Proxy -- on +traffic_shell> +.SH "SEE ALSO" +show:proxy, show:proxy-stats, show:cache-stats, config:reset-stats diff --git a/doc/man/show_version.1 b/doc/man/show_version.1 new file mode 100644 index 00000000..5ea92dce --- /dev/null +++ b/doc/man/show_version.1 @@ -0,0 +1,33 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:version" +.SH NAME +show:version \- This command displays Traffic Server and Traffic Manager +version information. +.SH SYNOPSIS +show:version +.SH DESCRIPTION +The show:version command displays Traffic Server and Traffic Manager +version numbers. The show:version command takes no options. +.SH EXAMPLE +When you execute the show:version command, you see results in the following +format: +.PP +.nf +traffic_shell> show:version +traffic_server version --- 5.2.0 +traffic_manager version -- 5.2.0 +traffic_shell> diff --git a/doc/man/show_virtual-ip.1 b/doc/man/show_virtual-ip.1 new file mode 100644 index 00000000..ca37c5a1 --- /dev/null +++ b/doc/man/show_virtual-ip.1 @@ -0,0 +1,35 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "show:virtual-ip" +.SH NAME +show:virtual-ip \- This command displays virtual IP configuration information +.SH SYNOPSIS +show:virtual-ip +.SH DESCRIPTION +The show:virtual-ip command displays the virtual IP addresses configured for +your system. The show:virtual-ip command takes no options. +.SH EXAMPLE +.SS "When you execute the show:virtual-ip command, you see results" +.SS "in the following format." +.PP +.nf +traffic_shell> show:virtual-ip + 2 Elements in Record + 0 1.1.1.1 23 23 + 1 1.1.1.1 23 24 +traffic_shell> +.SH "SEE ALSO" +config:virtual-ip diff --git a/doc/man/traffic_shell.1 b/doc/man/traffic_shell.1 new file mode 100644 index 00000000..0553ae58 --- /dev/null +++ b/doc/man/traffic_shell.1 @@ -0,0 +1,127 @@ +.\" Licensed to the Apache Software Foundation (ASF) under one .\" +.\" or more contributor license agreements. See the NOTICE file .\" +.\" distributed with this work for additional information .\" +.\" regarding copyright ownership. The ASF licenses this file .\" +.\" to you under the Apache License, Version 2.0 (the .\" +.\" "License"); you may not use this file except in compliance .\" +.\" with the License. You may obtain a copy of the License at .\" +.\" .\" +.\" http://www.apache.org/licenses/LICENSE-2.0 .\" +.\" .\" +.\" Unless required by applicable law or agreed to in writing, software .\" +.\" distributed under the License is distributed on an "AS IS" BASIS, .\" +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. .\" +.\" See the License for the specific language governing permissions and .\" +.\" limitations under the License. .\" +.TH "traffic_shell" +.SH NAME +traffic_shell \- Describes how to use Traffic Shell. +.SH DESCRIPTION +This page describes how to use the Traffic Shell command-line interface to +monitor and configure Traffic Server and Media-IXT software. +.SH This page describes the following topics: +.nf +About Traffic Shell +Using the Interactive Method +Using the File Execution Method +Exiting Traffic Shell +Using Traffic Shell Commands +Traffic Shell Command Shortcuts +Accessing Man Pages +.SH ABOUT TRAFFIC SHELL +Traffic Shell enables you to monitor and configure Traffic Server using a +UNIX shell-like command interface. Traffic Shell is one of several +interfaces for monitoring and configuring Traffic Server. Using Traffic Shell +is an alternative to manually editing Traffic Server's configuration +files or using Traffic Server's Traffic Line or Traffic Manager UI. +.SH Traffic Shell supports two operational methods: +The Interactive method lets you type individual commands at the +traffic_shell prompt. +.PP +The File Execution method lets you run a set of Traffic Shell commands. +.SH USING THE INTERACTIVE METHOD +You use Traffic Shell interactively by typing individual commands at the +traffic_shell prompt. As you enter a command, Traffic Shell processes it +and displays the result. You can continue to enter commands until you +manually exit Traffic Shell. +.SH USING THE FILE EXECUTION METHOD +When you use the File Execution method, you run a set of Traffic Shell +commands that you list in a text file. You use a separate command that +points to that file to run your entire set of commands. +.PP +To start Traffic Shell and execute a file that contains a set of +Traffic Shell commands, enter the following command at your UNIX shell prompt: +traffic_shell -f filename +.PP +This starts Traffic Shell and runs all Traffic Shell commands in the +named file. It displays the results and leaves your cursor at the +traffic_shell prompt. You can now enter individual commands at the +traffic_shell prompt, as described in Using the Interactive Method, above. +.PP +IMPORTANT: You exit Traffic Shell by typing exit at the traffic_shell +prompt. Therefore, if the word exit appears in your file, your cursor +returns to the UNIX shell prompt (instead of the traffic_shell prompt) +after you run your script. (This does not affect the results of running +your script.) +.SH EXITING TRAFFIC SHELL +Type exit at the traffic_shell prompt to exit Traffic Shell. +.SH USING TRAFFIC SHELL COMMANDS +Once you start Traffic Shell, you use one of two modes: +.PP +The Monitor mode allows you to run Show commands, which display system +information and Traffic Server statistics. You use Show commands to monitor +Traffic Server performance. When you start Traffic Shell, you are +automatically in Monitor mode. +.PP +To see a list of Show commands, type show at the traffic_shell prompt. +To use a Show command, enter the command at the traffic_shell prompt. +For example, enter the show:http command as follows: +traffic_shell> show:http +.PP +The Enable mode allows you to run Config commands, which set Traffic Server +and network parameters. The Enable mode is password-protected. +.nf +To enter Enable mode: + 1. Type enable at the traffic_shell> prompt. + 2. Enter your Administrator password. +.PP +IMPORTANT: You must enter Traffic Shell's Enable mode to use +Traffic Shell's Config commands. You can use both Show and Config commands +when you are in Enable mode. It is not necessary to return to Monitor mode +to use Show commands. +.PP +Once you enter Enable mode, you can use the Config commands. +To see a list of Config commands, type config at the traffic_shell prompt. +To use a Config command, enter the command at the traffic_shell prompt. +For example, enter the config:icp multicast on command as follows: +traffic_shell> config:icp multicast on +.PP +To return to Monitor mode, in which you cannot use Config commands to +set parameters, use the disable command, as follows: +traffic_shell> disable +.SH TRAFFIC SHELL COMMAND SHORTCUTS +Traffic Shell supports the following shortcuts for entering commands. +.PP +Command completion +.PP +Type the initial characters of a valid command, and then press the tab key. +Traffic Shell completes the command. +.PP +Command abbreviation +.PP +Type the initial characters of a valid command, and then press the Enter key. +Traffic Shell displays all commands that begin with the characters that you +enter. If only one command begins with those characters, Traffic Shell +immediately executes that command. +.PP +Command history +.PP +From the traffic_shell prompt, press the Up and Down arrow keys to scroll +through commands that you previously entered. +.SH ACCESSING MAN PAGES +Traffic Shell includes manual pages (man pages) that describe each +Traffic Shell command. (These man pages are similar to your UNIX man pages.) +To access Traffic Shell's man pages, type man, followed by any Traffic Shell +command at the traffic_shell prompt. For example, to view a man page for +the show:security command, enter the following man page command: +traffic_shell> man show:security diff --git a/emacs-style b/emacs-style new file mode 100644 index 00000000..c24e647d --- /dev/null +++ b/emacs-style @@ -0,0 +1,31 @@ +;; M-x load-file +;; or emacs -l +;; to use this style: C-c . apache +;; Licensed to the Apache Software Foundation (ASF) under one +;; or more contributor license agreements. See the NOTICE file +;; distributed with this work for additional information +;; regarding copyright ownership. The ASF licenses this file +;; to you under the Apache License, Version 2.0 (the +;; "License"); you may not use this file except in compliance +;; with the License. You may obtain a copy of the License at +;; +;; http://www.apache.org/licenses/LICENSE-2.0 +;; +;; Unless required by applicable law or agreed to in writing, software +;; distributed under the License is distributed on an "AS IS" BASIS, +;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +;; See the License for the specific language governing permissions and +;; limitations under the License. +;; +(c-add-style "trafficserver" + '((inclass . ++) + (defun-block-intro . ++) + (statement-block-intro . ++) + (substatement . ++) + (brace-list-intro . ++) + (statement-case-intro . ++) + (inextern-lang . 0) + )) +(setq-default indent-tabs-mode nil) +;; if you forgot to do this at startup, then M-x eval-expression +;; (setq indent-tabs-mode nil) on each buffer diff --git a/example/Makefile.am b/example/Makefile.am new file mode 100644 index 00000000..c28e2ad5 --- /dev/null +++ b/example/Makefile.am @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if STANDALONE_IOCORE +SUBDIRS = app-template +else +SUBDIRS = . add-header append-transform basic-auth blacklist-0 blacklist-1 bnull-transform cache_scan file-1 gzip-transform hello null-transform output-header protocol query_remap redirect-1 remap replace-header response-header-1 server-transform session-1 thread-1 thread-pool +endif diff --git a/example/Makefile.in b/example/Makefile.in new file mode 100644 index 00000000..d886909a --- /dev/null +++ b/example/Makefile.in @@ -0,0 +1,774 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = . add-header append-transform basic-auth blacklist-0 \ + blacklist-1 bnull-transform cache_scan file-1 gzip-transform \ + hello null-transform output-header protocol query_remap \ + redirect-1 remap replace-header response-header-1 \ + server-transform session-1 thread-1 thread-pool app-template +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +@STANDALONE_IOCORE_FALSE@SUBDIRS = . add-header append-transform basic-auth blacklist-0 blacklist-1 bnull-transform cache_scan file-1 gzip-transform hello null-transform output-header protocol query_remap redirect-1 remap replace-header response-header-1 server-transform session-1 thread-1 thread-pool +@STANDALONE_IOCORE_TRUE@SUBDIRS = app-template +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/add-header/Makefile.am b/example/add-header/Makefile.am new file mode 100644 index 00000000..b1e1a902 --- /dev/null +++ b/example/add-header/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = add-header.la +add_header_la_SOURCES = add-header.c +add_header_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/add-header.so diff --git a/example/add-header/Makefile.in b/example/add-header/Makefile.in new file mode 100644 index 00000000..f8c66fea --- /dev/null +++ b/example/add-header/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/add-header +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +add_header_la_LIBADD = +am_add_header_la_OBJECTS = add-header.lo +add_header_la_OBJECTS = $(am_add_header_la_OBJECTS) +add_header_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(add_header_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(add_header_la_SOURCES) +DIST_SOURCES = $(add_header_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = add-header.la +add_header_la_SOURCES = add-header.c +add_header_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/add-header/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/add-header/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +add-header.la: $(add_header_la_OBJECTS) $(add_header_la_DEPENDENCIES) + $(add_header_la_LINK) -rpath $(pkglibdir) $(add_header_la_OBJECTS) $(add_header_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/add-header.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/add-header.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/add-header/add-header.c b/example/add-header/add-header.c new file mode 100644 index 00000000..d09f0f3c --- /dev/null +++ b/example/add-header/add-header.c @@ -0,0 +1,228 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* add-header.c: a plugin that adds MIME headers to + * client request headers. + * + * + * Usage: + * (NT): AddHeader.dll "name1: value1" "name2: value2" ... + * (Solaris): add-header.so "name1: value1" "name2: value2" ... + * + * namei and valuei are the name and value of the + * ith MIME header to be added to the client request + */ + +#include +#include +#include +#include + +static TSMBuffer hdr_bufp; +static TSMLoc hdr_loc; + +static void +add_header(TSHttpTxn txnp, TSCont contp) +{ + TSMBuffer req_bufp; + TSMLoc req_loc; + TSMLoc field_loc; + TSMLoc next_field_loc; + TSMLoc new_field_loc; + int retval; + + if (TSHttpTxnClientReqGet(txnp, &req_bufp, &req_loc) != TS_SUCCESS) { + TSError("[add_header] Error while retrieving client request header\n"); + goto done; + } + + field_loc = TSMimeHdrFieldGet(hdr_bufp, hdr_loc, 0); + if (field_loc == TS_NULL_MLOC) { + TSError("[add_header] Error while getting field"); + goto error; + } + + /* Loop on our header containing fields to add */ + while (field_loc) { + + /* First create a new field in the client request header */ + if (TSMimeHdrFieldCreate(req_bufp, req_loc, &new_field_loc) != TS_SUCCESS) { + TSError("[add_header] Error while creating new field"); + TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); + break; + } + + /* Then copy our new field at this new location */ + retval = TSMimeHdrFieldCopy(req_bufp, req_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc); + if (retval == TS_ERROR) { + TSError("[add_header] Error while copying new field"); + TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); + break; + } + + /* Add this field to the Http client request header */ + retval = TSMimeHdrFieldAppend(req_bufp, req_loc, new_field_loc); + if (retval != TS_SUCCESS) { + TSError("[add_header] Error while appending new field"); + TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); + break; + } + + /* We can now release this handle */ + TSHandleMLocRelease(req_bufp, req_loc, new_field_loc); + + next_field_loc = TSMimeHdrFieldNext(hdr_bufp, hdr_loc, field_loc); + TSHandleMLocRelease(hdr_bufp, hdr_loc, field_loc); + field_loc = next_field_loc; + } + + +error: + TSHandleMLocRelease(req_bufp, TS_NULL_MLOC, req_loc); + +done: + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + +static int +add_header_plugin(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = (TSHttpTxn) edata; + + switch (event) { + case TS_EVENT_HTTP_READ_REQUEST_HDR: + add_header(txnp, contp); + return 0; + default: + break; + } + return 0; +} + +int +check_ts_version() +{ + + const char *ts_version = TSTrafficServerVersionGet(); + int result = 0; + + if (ts_version) { + int major_ts_version = 0; + int minor_ts_version = 0; + int patch_ts_version = 0; + + if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) { + return 0; + } + + /* Need at least TS 2.0 */ + if (major_ts_version >= 2) { + result = 1; + } + } + + return result; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + TSMLoc field_loc; + const char *p; + int i, retval; + TSPluginRegistrationInfo info; + + info.plugin_name = "add-header"; + info.vendor_name = "MyCompany"; + info.support_email = "ts-api-support@MyCompany.com"; + + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + TSError("[PluginInit] Plugin registration failed.\n"); + goto error; + } + + if (!check_ts_version()) { + TSError("[PluginInit] Plugin requires Traffic Server 3.0 or later\n"); + goto error; + } + + if (argc < 2) { + TSError("[PluginInit] Usage: %s \"name1: value1\" \"name2: value2\" ...>\n", argv[0]); + goto error; + } + + hdr_bufp = TSMBufferCreate(); + if (TSMimeHdrCreate(hdr_bufp, &hdr_loc) != TS_SUCCESS) { + TSError("[PluginInit] Can not create mime header"); + goto error; + } + + for (i = 1; i < argc; i++) { + if (TSMimeHdrFieldCreate(hdr_bufp, hdr_loc, &field_loc) != TS_SUCCESS) { + TSError("[PluginInit] Error while creating field"); + goto error; + } + + retval = TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc); + if (retval != TS_SUCCESS) { + TSError("[PluginInit] Error while adding field"); + goto error; + } + + p = strchr(argv[i], ':'); + if (p) { + retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], p - argv[i]); + if (retval == TS_ERROR) { + TSError("[PluginInit] Error while naming field"); + goto error; + } + + p += 1; + while (isspace(*p)) { + p += 1; + } + retval = TSMimeHdrFieldValueStringInsert(hdr_bufp, hdr_loc, field_loc, -1, p, strlen(p)); + if (retval == TS_ERROR) { + TSError("[PluginInit] Error while inserting field value"); + goto error; + } + } else { + retval = TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, argv[i], strlen(argv[i])); + if (retval == TS_ERROR) { + TSError("[PluginInit] Error while inserting field value"); + goto error; + } + } + } + + /* Create a continuation with a mutex as there is a shared global structure + containing the headers to add */ + TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(add_header_plugin, TSMutexCreate())); + goto done; + +error: + TSError("[PluginInit] Plugin not initialized"); + +done: + return; +} diff --git a/example/add-header/readme.txt b/example/add-header/readme.txt new file mode 100644 index 00000000..99f49cfd --- /dev/null +++ b/example/add-header/readme.txt @@ -0,0 +1,50 @@ +About add-header.c + +This plugin adds a header to a request. + +Enter the text of the header to be added into the plugin.config file; for +example, +enter the following line in plugin.config + + On NT: AddHeader.dll "name1: value1" "name2: value2" + On Solaris: add-header.so "name1: value1" "name2: value2" + +The TSPluginInit function does the following: + +- creates a MIME field buffer that contains the header to be added, + using the following functions: + TSMBufferCreate + TSMimeHdrCreate + TSMimeHdrFieldCreate + TSMimeHdrFieldAppend + TSMimeHdrFieldNameSet + TSMimeHdrFieldValueAppend + + +- sets up the callback for the add-header-plugin function, which + is the main callback function, using + TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, + TSContCreate(add_header_plugin, NULL); + +add_header_plugin is the main function in the plugin. In the +event of TS_EVENT_HTTP_READ_REQUEST_HDR (when the HTTP +state machine reads a request header), it calls the function +add_header. + +add_header first makes sure that it can retrieve the client request +header from the current transaction, using + TSHttpTxnClientReqGet + + copies the header into the MIME headers of the +HTTP request, using the following functions: + + TSMimeHdrFieldGet + TSMimeHdrFieldCreate + TSMimeHdrFieldCopy + TSMimeHdrFieldAPpend + TSMimeHdrFieldNext + +When add_header is done, it uses + TSHttpTxnReenable +to continue. + diff --git a/example/app-template/Makefile.am b/example/app-template/Makefile.am new file mode 100644 index 00000000..b62e4b8d --- /dev/null +++ b/example/app-template/Makefile.am @@ -0,0 +1,63 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = -I$(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy +# -I$(top_srcdir)/proxy/hdrs +# I$(top_srcdir)/proxy/logging + + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +bin_PROGRAMS = tsapp + +tsapp_SOURCES = app-template.cc + +tsapp_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +tsapp_LDADD = \ + $(top_builddir)/proxy/libTrafficServerStandalone.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/iocore/cache/libinkcache.a \ + $(top_builddir)/iocore/aio/libinkaio.a \ + $(top_builddir)/iocore/hostdb/libinkhostdb.a \ + $(top_builddir)/iocore/dns/libinkdns.a \ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/utils/libinkutils.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecprocess.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + @LIBTHREAD@ @LIBSOCKET@ @LIBNSL@ @LIBRESOLV@ @LIBRT@ \ + @LIBPCRE@ @LIBSSL@ @LIBTCL@ @LIBDL@ \ + @LIBEXPAT@ @LIBDEMANGLE@ @LIBICONV@ \ + @LIBMLD@ @LIBEXC@ -lm @LIBEV@ @LIBPROFILER@ @LIBEXECINFO@ + +EXTRA_DIST = records.config.in +sysconfdir = $(pkgsysconfdir) +nodist_sysconf_DATA = records.config + +install-data-local: + $(INSTALL) -d -o $(pkgsysuser) -g $(pkgsysgroup) $(DESTDIR)$(pkglocalstatedir) $(DESTDIR)$(pkglogdir) $(DESTDIR)$(pkgsysconfdir) $(DESTDIR)$(pkgdatadir) + +install-data-hook: + -chown -R $(pkgsysuser):$(pkgsysgroup) $(DESTDIR)$(pkgsysconfdir) $(DESTDIR)$(pkgdatadir) + +install-exec-local: + $(INSTALL) -d -o $(pkgsysuser) -g $(pkgsysgroup) $(DESTDIR)$(pkglibexecdir) + +install-exec-hook: + -chown -R $(pkgsysuser):$(pkgsysgroup) $(DESTDIR)$(pkglibexecdir) + diff --git a/example/app-template/Makefile.in b/example/app-template/Makefile.in new file mode 100644 index 00000000..31779151 --- /dev/null +++ b/example/app-template/Makefile.in @@ -0,0 +1,824 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = tsapp$(EXEEXT) +subdir = example/app-template +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/records.config.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = records.config +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sysconfdir)" +PROGRAMS = $(bin_PROGRAMS) +am_tsapp_OBJECTS = app-template.$(OBJEXT) +tsapp_OBJECTS = $(am_tsapp_OBJECTS) +tsapp_DEPENDENCIES = \ + $(top_builddir)/proxy/libTrafficServerStandalone.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/iocore/cache/libinkcache.a \ + $(top_builddir)/iocore/aio/libinkaio.a \ + $(top_builddir)/iocore/hostdb/libinkhostdb.a \ + $(top_builddir)/iocore/dns/libinkdns.a \ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/utils/libinkutils.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecprocess.a \ + $(top_builddir)/lib/ts/libtsutil.la +tsapp_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(tsapp_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(tsapp_SOURCES) +DIST_SOURCES = $(tsapp_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +DATA = $(nodist_sysconf_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +# -I$(top_srcdir)/proxy/hdrs +# I$(top_srcdir)/proxy/logging +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = $(pkgsysconfdir) +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = -I$(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy + +tsapp_SOURCES = app-template.cc +tsapp_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +tsapp_LDADD = \ + $(top_builddir)/proxy/libTrafficServerStandalone.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/iocore/cache/libinkcache.a \ + $(top_builddir)/iocore/aio/libinkaio.a \ + $(top_builddir)/iocore/hostdb/libinkhostdb.a \ + $(top_builddir)/iocore/dns/libinkdns.a \ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/utils/libinkutils.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/records/librecprocess.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + @LIBTHREAD@ @LIBSOCKET@ @LIBNSL@ @LIBRESOLV@ @LIBRT@ \ + @LIBPCRE@ @LIBSSL@ @LIBTCL@ @LIBDL@ \ + @LIBEXPAT@ @LIBDEMANGLE@ @LIBICONV@ \ + @LIBMLD@ @LIBEXC@ -lm @LIBEV@ @LIBPROFILER@ @LIBEXECINFO@ + +EXTRA_DIST = records.config.in +nodist_sysconf_DATA = records.config +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/app-template/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/app-template/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +records.config: $(top_builddir)/config.status $(srcdir)/records.config.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +tsapp$(EXEEXT): $(tsapp_OBJECTS) $(tsapp_DEPENDENCIES) + @rm -f tsapp$(EXEEXT) + $(tsapp_LINK) $(tsapp_OBJECTS) $(tsapp_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app-template.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-nodist_sysconfDATA: $(nodist_sysconf_DATA) + @$(NORMAL_INSTALL) + test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" + @list='$(nodist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ + done + +uninstall-nodist_sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(nodist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sysconfdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sysconfdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sysconfdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-exec-local \ + install-nodist_sysconfDATA + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-nodist_sysconfDATA + +.MAKE: install-am install-data-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-data-hook install-data-local install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-exec-local install-html install-html-am install-info \ + install-info-am install-man install-nodist_sysconfDATA \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-nodist_sysconfDATA + + +install-data-local: + $(INSTALL) -d -o $(pkgsysuser) -g $(pkgsysgroup) $(DESTDIR)$(pkglocalstatedir) $(DESTDIR)$(pkglogdir) $(DESTDIR)$(pkgsysconfdir) $(DESTDIR)$(pkgdatadir) + +install-data-hook: + -chown -R $(pkgsysuser):$(pkgsysgroup) $(DESTDIR)$(pkgsysconfdir) $(DESTDIR)$(pkgdatadir) + +install-exec-local: + $(INSTALL) -d -o $(pkgsysuser) -g $(pkgsysgroup) $(DESTDIR)$(pkglibexecdir) + +install-exec-hook: + -chown -R $(pkgsysuser):$(pkgsysgroup) $(DESTDIR)$(pkglibexecdir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/app-template/app-template.cc b/example/app-template/app-template.cc new file mode 100644 index 00000000..024c6d19 --- /dev/null +++ b/example/app-template/app-template.cc @@ -0,0 +1,262 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Example application template to be used with the standalone iocore + * + */ + +#include "libts.h" + +#include "I_Version.h" +#include "I_EventSystem.h" +#include "I_Layout.h" +#include "I_Net.h" +#include "I_HostDB.h" +#include "I_DNS.h" +#include "I_SplitDNS.h" +#include "I_Cache.h" + +//#include "ts.h" // plugin API's + +#include "Initialize.h" // TODO: move to I_Initialize.h ??? +#include "signals.h" // TODO: move to I_Signals.h ??? + +#include "app-template.h" + +#define PROGRAM_NAME "tsapp" + +int use_accept_thread = 0; // TODO: rename and move to I_UnixNetProcessor.h +extern void RecDumpRecordsHt(RecT rec_type); // TODO: move from P_RecCore.h -> I_RecCore.h + +int system_num_of_processors = ink_number_of_processors(); +int system_num_of_net_threads = DEFAULT_NUMBER_OF_THREADS; +int system_num_of_udp_threads = DEFAULT_NUMBER_OF_UDP_THREADS; + +char system_root_dir[PATH_NAME_MAX + 1]; +char system_runtime_dir[PATH_NAME_MAX + 1]; +char system_config_directory[PATH_NAME_MAX + 1]; +char system_log_dir[PATH_NAME_MAX + 1]; + +//int system_remote_management_flag = DEFAULT_REMOTE_MANAGEMENT_FLAG; + +//Diags *diags = NULL; +char debug_tags[1024] = ""; +char action_tags[1024] = ""; + +int version_flag = 0; +int tsapp_port = 12345; + +AppVersionInfo appVersionInfo; + +ArgumentDescription argument_descriptions[] = { + {"version", 'V', "Print Version Id", "T", + &version_flag, NULL, NULL}, + {"tsapp_port", 'p', "tsapp port", "I", + &tsapp_port, "TSAPP_PORT", NULL}, + {"net_threads", 'n', "Number of Net Threads", "I", + &system_num_of_net_threads, "TSAPP_NET_THREADS", NULL}, + {"accept_thread", 'a', "Use an Accept Thread", "T", + &use_accept_thread, "TSAPP_ACCEPT_THREAD", NULL}, + {"poll_timeout", 't', "poll timeout in milliseconds", "I", + &net_config_poll_timeout, NULL, NULL}, + {"debug_tags", 'T', "Debug Tags ('|' separated)", "S1023", + debug_tags, "TSAPP_DEBUG_TAGS", NULL}, + {"action_tags", 'T', "Action Tags ('|' separated)", "S1023", + action_tags, "TSAPP_ACTION_TAGS", NULL}, + {"help", 'h', "Help", NULL, NULL, NULL, usage} +}; +int n_argument_descriptions = SIZE(argument_descriptions); + +void init_app_config() { + // Net + RecRegisterConfigInt( + RECT_CONFIG, + "proxy.config.net.listen_backlog", + 1024, + RECU_DYNAMIC, RECC_NULL, NULL); + + RecRegisterConfigInt( + RECT_CONFIG, + "proxy.config.net.connections_throttle", + 8000, + RECU_DYNAMIC, RECC_NULL, NULL); + + RecRegisterConfigInt( + RECT_CONFIG, + "proxy.config.accept_threads", + 0, + RECU_DYNAMIC, RECC_NULL, NULL); + + // IO + RecRegisterConfigInt( + RECT_CONFIG, + "proxy.config.io.max_buffer_size", + 32768, + RECU_DYNAMIC, RECC_NULL, NULL); + + // Cache, etc +} + +int +MyAccept::main_event(int event, void *data) { + if (event == NET_EVENT_ACCEPT) { + //NetVConnection *netvc = (NetVConnection*)data; + NOWARN_UNUSED(data); + // allocate continuation to handle this connection/request + // + // ..handle request, etc + // + return EVENT_CONT; + } else { + Fatal("tsapp accept received fatal error: errno = %d", -((int)(intptr_t)data)); + return EVENT_CONT; + } +} + + +// +// Shutdown, called from signals interrupt_handler() +// TODO: rename, consolidate signals stuff, etc +void +shutdown_system() +{ +} + +int main(int argc, char * argv[]) +{ + // build the application information structure + appVersionInfo.setup(PACKAGE_NAME,PROGRAM_NAME, PACKAGE_VERSION, __DATE__, + __TIME__, BUILD_MACHINE, BUILD_PERSON, ""); + // create the layout engine + Layout::create(); + process_args(argument_descriptions, n_argument_descriptions, argv); + + // check for the version number request + if (version_flag) { + fprintf(stderr, "%s\n", appVersionInfo.FullVersionInfoStr); + _exit(0); + } + + // Get TS directories + ink_strncpy(system_root_dir, Layout::get()->prefix, sizeof(system_root_dir)); + ink_strncpy(system_config_directory, Layout::get()->sysconfdir, sizeof(system_config_directory)); + ink_strncpy(system_runtime_dir, Layout::get()->runtimedir, sizeof(system_runtime_dir)); + ink_strncpy(system_log_dir, Layout::get()->logdir, sizeof(system_log_dir)); + + if (system_root_dir[0] && (chdir(system_root_dir) < 0)) { + fprintf(stderr,"unable to change to root directory \"%s\" [%d '%s']\n", system_root_dir, errno, strerror(errno)); + fprintf(stderr," please set correct path in env variable TS_ROOT \n"); + _exit(1); + } else { + printf("[tsapp] using root directory '%s'\n",system_root_dir); + } + + // Diags + init_system_diags(debug_tags, NULL); + if (is_debug_tag_set("tsapp")) + diags->dump(stdout); + + // Config & Stats + RecModeT mode_type = RECM_STAND_ALONE; + RecProcessInit(mode_type,diags); + //RecProcessInitMessage(mode_type); + + signal(SIGPIPE, SIG_IGN); // ignore broken pipe + + init_buffer_allocators(); + + // Initialze iocore modules + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + ink_net_init(NET_SYSTEM_MODULE_VERSION); + ink_aio_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); + ink_cache_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); + ink_hostdb_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); + ink_dns_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); + //ink_split_dns_init(makeModuleVersion(1, 0, PRIVATE_MODULE_HEADER)); + + init_app_config(); // initialize stats and configs + + if (!use_accept_thread) { + RecInt tmp = 0; + RecGetRecordInt("proxy.config.accept_threads",(RecInt*) &tmp); + use_accept_thread = (int32_t)tmp; \ + } + + if (initialize_store()) { // cache + printf("unable to initialize storage, (Re)Configuration required\n"); + _exit(0); + } + + // Start processors + eventProcessor.start(system_num_of_net_threads); + + RecProcessStart(); + + init_signals2(); + + netProcessor.start(); + + dnsProcessor.start(); + + if (hostDBProcessor.start() < 0) + printf("bad hostdb or storage configuration, hostdb disabled"); + + //clusterProcessor.init(); + + cacheProcessor.start(); + + //udpNet.start(system_num_of_udp_threads); // XXX : broken + + //sslNetProcessor.start(getNumSSLThreads()); + + // initialize logging (after event and net processor) + //Log::init(system_remote_management_flag ? 0 : Log::NO_REMOTE_MANAGEMENT); + +#if !defined(TS_NO_API) + //plugin_init(system_config_directory, true); // extensions.config +#endif + +#ifndef TS_NO_API + //plugin_init(system_config_directory, false); // plugin.config +#else + //api_init(); // still need to initialize some of the data structure other module needs. + //extern void init_inkapi_stat_system(); + //init_inkapi_stat_system(); // i.e. http_global_hooks +#endif + + // Create accept continuation + MyAccept *a = new MyAccept; + a->accept_port = tsapp_port; + a->mutex = new_ProxyMutex(); + Action *act= netProcessor.accept(a, a->accept_port, AF_INET, true); + + RecDumpRecordsHt(RECT_NULL); // debugging, specify '-T "rec.*"' to see records + + Debug("tsapp","listening port %d, started %d ethreads, use_accept_thread (%d), act(%p)\n" , + tsapp_port,system_num_of_net_threads,use_accept_thread, act); + + this_thread()->execute(); +} + + diff --git a/example/app-template/app-template.h b/example/app-template/app-template.h new file mode 100644 index 00000000..4749e810 --- /dev/null +++ b/example/app-template/app-template.h @@ -0,0 +1,48 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _app_template_h_ +#define _app_template_h_ + +#include "libts.h" + +#define DEFAULT_ROOT_DIRECTORY PREFIX +#define DEFAULT_LOCAL_STATE_DIRECTORY "var/trafficserver" +#define DEFAULT_SYSTEM_CONFIG_DIRECTORY "etc/trafficserver" +#define DEFAULT_LOG_DIRECTORY "var/log/trafficserver" + +#define DEFAULT_NUMBER_OF_THREADS ink_number_of_processors() +#define DEFAULT_NUMBER_OF_UDP_THREADS 1 + + +struct MyAccept : public Continuation { + int accept_port; + int main_event(int event, void *netvc); + + MyAccept() + { SET_HANDLER(&MyAccept::main_event); } + +}; + + +#endif diff --git a/example/app-template/records.config.in b/example/app-template/records.config.in new file mode 100644 index 00000000..e17b0b64 --- /dev/null +++ b/example/app-template/records.config.in @@ -0,0 +1,73 @@ +# +# +# Process Records Config File +# +# +# +# RECORD-TYPE: CONFIG, LOCAL +# NAME: name of variable +# TYPE: INT, STRING, FLOAT +# VALUE: Initial value for record +# +# +# +# +############################################################################## +# +# System Variables +# +############################################################################## +CONFIG proxy.config.bin_path STRING bin +CONFIG proxy.config.config_dir STRING etc/@PACKAGE@ +CONFIG proxy.config.temp_dir STRING /tmp +CONFIG proxy.config.syslog_facility STRING LOG_DAEMON +CONFIG proxy.config.cop.linux_min_swapfree_kb INT 10240 +CONFIG proxy.config.cop.linux_min_memfree_kb INT 10240 +CONFIG proxy.config.system.mmap_max INT 2097152 +CONFIG proxy.config.system.memalign_heap INT 0 +CONFIG proxy.config.exec_thread.autoconfig INT 1 +CONFIG proxy.config.exec_thread.autoconfig.scale FLOAT 3.0 +CONFIG proxy.config.exec_thread.limit INT 2 +CONFIG proxy.config.accept_threads INT 1 + +############################################################################## +# +# Net Subsystem +# +############################################################################## +CONFIG proxy.config.net.connections_throttle INT 10000 + # timeout in seconds for defering the accept, 0 is disabled +CONFIG proxy.config.net.tcp_accept_defer_timeout INT 0 + +############################################################################## +# +# Socket send/recv buffer sizes (0 == don't call setsockopt() ) +# +############################################################################## +CONFIG proxy.config.net.sock_send_buffer_size_in INT 262144 +CONFIG proxy.config.net.sock_recv_buffer_size_in INT 0 +CONFIG proxy.config.net.sock_send_buffer_size_out INT 0 +CONFIG proxy.config.net.sock_recv_buffer_size_out INT 0 + +############################################################################## +# +# Debugging +# +############################################################################## + # Uses a regular expression to match the debugging topic name, performance + # will be affected! +CONFIG proxy.config.diags.debug.enabled INT 1 +CONFIG proxy.config.diags.debug.tags STRING tsmemcache.*|rec.* + # Great for tracking down memory leaks, but you need to use the + # ink allocators +CONFIG proxy.config.dump_mem_info_frequency INT 0 + +############################################################################## +# +# User Overridden Configurations Below +# +############################################################################## + + + + diff --git a/example/append-transform/Makefile.am b/example/append-transform/Makefile.am new file mode 100644 index 00000000..049bad0c --- /dev/null +++ b/example/append-transform/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = append-transform.la +append_transform_la_SOURCES = append-transform.c +append_transform_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/append-transform.so diff --git a/example/append-transform/Makefile.in b/example/append-transform/Makefile.in new file mode 100644 index 00000000..b7b1e6ac --- /dev/null +++ b/example/append-transform/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/append-transform +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +append_transform_la_LIBADD = +am_append_transform_la_OBJECTS = append-transform.lo +append_transform_la_OBJECTS = $(am_append_transform_la_OBJECTS) +append_transform_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(append_transform_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(append_transform_la_SOURCES) +DIST_SOURCES = $(append_transform_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = append-transform.la +append_transform_la_SOURCES = append-transform.c +append_transform_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/append-transform/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/append-transform/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +append-transform.la: $(append_transform_la_OBJECTS) $(append_transform_la_DEPENDENCIES) + $(append_transform_la_LINK) -rpath $(pkglibdir) $(append_transform_la_OBJECTS) $(append_transform_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/append-transform.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/append-transform.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/append-transform/append-transform.c b/example/append-transform/append-transform.c new file mode 100644 index 00000000..5c11f307 --- /dev/null +++ b/example/append-transform/append-transform.c @@ -0,0 +1,414 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * append-transform.c: an example program that appends the text + * contained in a file to all HTTP/text response + * bodies. + * + * + * + * Usage: + * (NT): AppendTransform.dll + * (Solaris): append-transform.so + * + * is the name of the file containing the + * text to be appended + * + */ + +#include +#include +#include +#include + +#define ASSERT_SUCCESS(_x) TSAssert ((_x) == TS_SUCCESS) + +typedef struct +{ + TSVIO output_vio; + TSIOBuffer output_buffer; + TSIOBufferReader output_reader; + int append_needed; +} MyData; + +static TSIOBuffer append_buffer; +static TSIOBufferReader append_buffer_reader; +static int append_buffer_length; + +static MyData * +my_data_alloc() +{ + MyData *data; + + data = (MyData *) TSmalloc(sizeof(MyData)); + TSReleaseAssert(data); + + data->output_vio = NULL; + data->output_buffer = NULL; + data->output_reader = NULL; + data->append_needed = 1; + + return data; +} + +static void +my_data_destroy(MyData * data) +{ + if (data) { + if (data->output_buffer) + TSIOBufferDestroy(data->output_buffer); + TSfree(data); + } +} + +static void +handle_transform(TSCont contp) +{ + TSVConn output_conn; + TSVIO write_vio; + MyData *data; + int towrite; + int avail; + + /* Get the output connection where we'll write data to. */ + output_conn = TSTransformOutputVConnGet(contp); + + /* Get the write VIO for the write operation that was performed on + ourself. This VIO contains the buffer that we are to read from + as well as the continuation we are to call when the buffer is + empty. */ + write_vio = TSVConnWriteVIOGet(contp); + + /* Get our data structure for this operation. The private data + structure contains the output VIO and output buffer. If the + private data structure pointer is NULL, then we'll create it + and initialize its internals. */ + data = TSContDataGet(contp); + if (!data) { + towrite = TSVIONBytesGet(write_vio); + if (towrite != INT64_MAX) { + towrite += append_buffer_length; + } + data = my_data_alloc(); + data->output_buffer = TSIOBufferCreate(); + data->output_reader = TSIOBufferReaderAlloc(data->output_buffer); + data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, towrite); + TSContDataSet(contp, data); + } + + /* We also check to see if the write VIO's buffer is non-NULL. A + NULL buffer indicates that the write operation has been + shutdown and that the continuation does not want us to send any + more WRITE_READY or WRITE_COMPLETE events. For this simplistic + transformation that means we're done. In a more complex + transformation we might have to finish writing the transformed + data to our output connection. */ + if (!TSVIOBufferGet(write_vio)) { + if (data->append_needed) { + data->append_needed = 0; + TSIOBufferCopy(TSVIOBufferGet(data->output_vio), append_buffer_reader, append_buffer_length, 0); + } + + TSVIONBytesSet(data->output_vio, TSVIONDoneGet(write_vio) + append_buffer_length); + TSVIOReenable(data->output_vio); + + return; + } + + /* Determine how much data we have left to read. For this append + transform plugin this is also the amount of data we have left + to write to the output connection. */ + towrite = TSVIONTodoGet(write_vio); + if (towrite > 0) { + /* The amount of data left to read needs to be truncated by + the amount of data actually in the read buffer. */ + avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio)); + if (towrite > avail) { + towrite = avail; + } + + if (towrite > 0) { + /* Copy the data from the read buffer to the output buffer. */ + TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(write_vio), towrite, 0); + + /* Tell the read buffer that we have read the data and are no + longer interested in it. */ + TSIOBufferReaderConsume(TSVIOReaderGet(write_vio), towrite); + + /* Modify the write VIO to reflect how much data we've + completed. */ + TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite); + } + } + + /* Now we check the write VIO to see if there is data left to + read. */ + if (TSVIONTodoGet(write_vio) > 0) { + if (towrite > 0) { + /* If there is data left to read, then we reenable the output + connection by reenabling the output VIO. This will wakeup + the output connection and allow it to consume data from the + output buffer. */ + TSVIOReenable(data->output_vio); + + /* Call back the write VIO continuation to let it know that we + are ready for more data. */ + TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio); + } + } else { + if (data->append_needed) { + data->append_needed = 0; + TSIOBufferCopy(TSVIOBufferGet(data->output_vio), append_buffer_reader, append_buffer_length, 0); + } + + /* If there is no data left to read, then we modify the output + VIO to reflect how much data the output connection should + expect. This allows the output connection to know when it + is done reading. We then reenable the output connection so + that it can consume the data we just gave it. */ + TSVIONBytesSet(data->output_vio, TSVIONDoneGet(write_vio) + append_buffer_length); + TSVIOReenable(data->output_vio); + + /* Call back the write VIO continuation to let it know that we + have completed the write operation. */ + TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio); + } +} + +static int +append_transform(TSCont contp, TSEvent event, void *edata) +{ + /* Check to see if the transformation has been closed by a call to + TSVConnClose. */ + if (TSVConnClosedGet(contp)) { + my_data_destroy(TSContDataGet(contp)); + TSContDestroy(contp); + return 0; + } else { + switch (event) { + case TS_EVENT_ERROR: + { + TSVIO write_vio; + + /* Get the write VIO for the write operation that was + performed on ourself. This VIO contains the continuation of + our parent transformation. */ + write_vio = TSVConnWriteVIOGet(contp); + + /* Call back the write VIO continuation to let it know that we + have completed the write operation. */ + TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio); + } + break; + case TS_EVENT_VCONN_WRITE_COMPLETE: + /* When our output connection says that it has finished + reading all the data we've written to it then we should + shutdown the write portion of its connection to + indicate that we don't want to hear about it anymore. */ + TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1); + break; + case TS_EVENT_VCONN_WRITE_READY: + default: + /* If we get a WRITE_READY event or any other type of + event (sent, perhaps, because we were reenabled) then + we'll attempt to transform more data. */ + handle_transform(contp); + break; + } + } + + return 0; +} + +static int +transformable(TSHttpTxn txnp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc field_loc; + TSHttpStatus resp_status; + const char *value; + int val_length; + + TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc); + + /* + * We are only interested in "200 OK" responses. + */ + + if (TS_HTTP_STATUS_OK == (resp_status = TSHttpHdrStatusGet(bufp, hdr_loc))) { + + /* We only want to do the transformation on documents that have a + content type of "text/html". */ + field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, "Content-Type", 12); + if (!field_loc) { + ASSERT_SUCCESS(TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc)); + return 0; + } + + value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, &val_length); +#ifndef _WIN32 + if (value && (strncasecmp(value, "text/html", sizeof("text/html") - 1) == 0)) { +#else + if (value && (strnicmp(value, "text/html", sizeof("text/html") - 1) == 0)) { +#endif + ASSERT_SUCCESS(TSHandleMLocRelease(bufp, hdr_loc, field_loc)); + ASSERT_SUCCESS(TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc)); + + return 1; + } else { + ASSERT_SUCCESS(TSHandleMLocRelease(bufp, hdr_loc, field_loc)); + ASSERT_SUCCESS(TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc)); + return 0; + } + } + + return 0; /* not a 200 */ +} + +static void +transform_add(TSHttpTxn txnp) +{ + TSVConn connp; + + connp = TSTransformCreate(append_transform, txnp); + TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp); +} + +static int +transform_plugin(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = (TSHttpTxn) edata; + + switch (event) { + case TS_EVENT_HTTP_READ_RESPONSE_HDR: + if (transformable(txnp)) { + transform_add(txnp); + } + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); + return 0; + default: + break; + } + + return 0; +} + +static int +load(const char *filename) +{ + TSFile fp; + TSIOBufferBlock blk; + char *p; + int64_t avail; + int err; + + fp = TSfopen(filename, "r"); + if (!fp) { + return 0; + } + + append_buffer = TSIOBufferCreate(); + append_buffer_reader = TSIOBufferReaderAlloc(append_buffer); + + for (;;) { + blk = TSIOBufferStart(append_buffer); + p = TSIOBufferBlockWriteStart(blk, &avail); + + err = TSfread(fp, p, avail); + if (err > 0) { + TSIOBufferProduce(append_buffer, err); + } else { + break; + } + } + + append_buffer_length = TSIOBufferReaderAvail(append_buffer_reader); + + TSfclose(fp); + return 1; +} + +int +check_ts_version() +{ + + const char *ts_version = TSTrafficServerVersionGet(); + int result = 0; + + if (ts_version) { + int major_ts_version = 0; + int minor_ts_version = 0; + int patch_ts_version = 0; + + if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) { + return 0; + } + + /* Need at least TS 2.0 */ + if (major_ts_version >= 2) { + result = 1; + } + + } + + return result; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + TSPluginRegistrationInfo info; + + info.plugin_name = "append-transform"; + info.vendor_name = "MyCompany"; + info.support_email = "ts-api-support@MyCompany.com"; + + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + TSError("Plugin registration failed.\n"); + goto Lerror; + } + + if (!check_ts_version()) { + TSError("Plugin requires Traffic Server 3.0 or later\n"); + goto Lerror; + } + + if (argc != 2) { + TSError("usage: %s \n", argv[0]); + goto Lerror; + } + + if (!load(argv[1])) { + TSError("[append-transform] Could not load %s\n", argv[1]); + goto Lerror; + } + + TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, NULL)); + return; + +Lerror: + + TSError("[append-transform] Unable to initialize plugin\n"); +} diff --git a/example/append-transform/readme.txt b/example/append-transform/readme.txt new file mode 100644 index 00000000..84fea1cb --- /dev/null +++ b/example/append-transform/readme.txt @@ -0,0 +1,89 @@ +About append-transform.c + +This example is based on null-transform.c. It appends text to the body +of an HTML text response document on its way from the cache to the +client. + +The plugin first makes sure that it has received a "200 OK" +response from the origin server. It then verifies that the returned +document is of type "text/html". It "transforms" the document by +appending text to the file. To read and write to the body of the +document, the plugin uses functions similar to those in null-transform.c. + +You place the text to be appended in a file, and you must provide the +path to the file in plugin.config. In other words, plugin.config must +have a line similar to the following: + +On NT: AppendTransform.dll path/to/file +On Solaris: append-transform.so path/to/file + +Specify an absolute path to the text file, or a relative path as +described in the file-plugin README. + +TSPluginInit does the following: + +- makes sure that there is a text file specified in plugin.config + (if not, it returns an error message) + +- calls the function load to load the contents of the file into + a buffer to be appended to HTML response bodies + +- sets up the global hook to call back the plugin: + TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, +TSContCreate (transform_plugin, NULL)); + +The load function does the following (similar to file-1.c): + +- opens the file specified in plugin.config using + TSfopen + +- creates a buffer for the text to be appended using + TSIOBufferCreate + +- creates a buffer reader for the text to be appended using + TSIOBufferReaderAlloc + +- reads the contents of the file in to the buffer using: + TSIOBufferStart + TSIOBufferBlockWriteStart + TSfread + TSIOBufferProduce + TSIOBufferReaderAvail + +- closes the file using + TSfclose + +The transform_plugin function does the following: + +- tests the response body to make sure it is text/html, using + the function "transformable". The transformable function + uses the following API calls: + TSHttpTxnServerRespGet + TSHttpHdrStatusGet + TSMimeHdrFieldFind + TSMimeHdrFieldValueStringGet + +- if the response body is deemed transformable, transform_plugin calls + transform_add + +- continues the HTTP transaction using + TSHttpTxnReenable + +The transform_add function does the following: + +- creates a continuation for the append transform, using + TSTransformCreate (append_transform, txnp); + The handler function for this continuation is + append_transform. + +- adds a transaction hook for the append transform, using + TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp); + This transaction hook sets up a callback during transactions. + When the event TS_HTTP_RESPONSE_TRANSFORM_HOOK happens, + the append_transform function is called back. + +The remaining functions in the plugin, append_transform and +handle_transform, are similar to null_transform and +handle_transform in the null-transform.c plugin. + + diff --git a/example/basic-auth/Makefile.am b/example/basic-auth/Makefile.am new file mode 100644 index 00000000..83a8460e --- /dev/null +++ b/example/basic-auth/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = basic-auth.la +basic_auth_la_SOURCES = basic-auth.c +basic_auth_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/basic-auth.so diff --git a/example/basic-auth/Makefile.in b/example/basic-auth/Makefile.in new file mode 100644 index 00000000..51b6de19 --- /dev/null +++ b/example/basic-auth/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/basic-auth +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +basic_auth_la_LIBADD = +am_basic_auth_la_OBJECTS = basic-auth.lo +basic_auth_la_OBJECTS = $(am_basic_auth_la_OBJECTS) +basic_auth_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(basic_auth_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(basic_auth_la_SOURCES) +DIST_SOURCES = $(basic_auth_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = basic-auth.la +basic_auth_la_SOURCES = basic-auth.c +basic_auth_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/basic-auth/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/basic-auth/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +basic-auth.la: $(basic_auth_la_OBJECTS) $(basic_auth_la_DEPENDENCIES) + $(basic_auth_la_LINK) -rpath $(pkglibdir) $(basic_auth_la_OBJECTS) $(basic_auth_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basic-auth.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/basic-auth.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/basic-auth/basic-auth.c b/example/basic-auth/basic-auth.c new file mode 100644 index 00000000..b931ce7d --- /dev/null +++ b/example/basic-auth/basic-auth.c @@ -0,0 +1,315 @@ +/** @file + + A plugin that performs basic HTTP proxy authentication + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include +#include + +#if !defined (_WIN32) +#include +#else +#include +#endif + +#include + + +static char base64_codes[256]; + + +static char * +base64_decode(const char *input) +{ +#define decode(A) ((unsigned int) base64_codes[(int) input[A]]) + + char *output; + char *obuf; + int len; + + for (len = 0; (input[len] != '\0') && (input[len] != '='); len++); + + output = obuf = (char *) TSmalloc((len * 6) / 8 + 3); + + while (len > 0) { + *output++ = decode(0) << 2 | decode(1) >> 4; + *output++ = decode(1) << 4 | decode(2) >> 2; + *output++ = decode(2) << 6 | decode(3); + len -= 4; + input += 4; + } + + /* + * We don't need to worry about leftover bits because + * we've allocated a few extra characters and if there + * are leftover bits they will be zeros because the extra + * inputs will be '='s and '=' decodes to 0. + */ + + *output = '\0'; + return obuf; + +#undef decode +} + +static int +authorized(char *user, char *password) +{ + /* + * This routine checks the validity of the user name and + * password. Sample NT code is provided for illustration. + * For UNIX systems, enter your own authorization code + * here. + */ + +#if !defined (_WIN32) + +#else + // LogonUser() will work only if the account is set with + // SE_TCB_NAME privilege. If SE_TCB_NAME is missing, + // Traffic server will attempt to add this privilege to + // the running account, but may fail depending on the access + // levels provided to the said account. In such a case, an + // NT systems administrator will have to set the privilege + // "Act as part of the operating system" from the NT user manager. + // + int nErr = 0; + HANDLE hToken = 0; + BOOL bRet = LogonUser(user, NULL, password, LOGON32_LOGON_NETWORK, + LOGON32_PROVIDER_DEFAULT, &hToken); + + if (FALSE == bRet) { + nErr = GetLastError(); + return 0; + } + + CloseHandle(hToken); +#endif + return 1; +} + +static void +handle_dns(TSHttpTxn txnp, TSCont contp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc field_loc; + const char *val; + const char *ptr; + + char *user, *password; + int authval_length; + + if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client request header\n"); + goto done; + } + + field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_PROXY_AUTHORIZATION, TS_MIME_LEN_PROXY_AUTHORIZATION); + if (!field_loc) { + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + TSError("no Proxy-Authorization field\n"); + goto done; + } + + val = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, &authval_length); + if (NULL == val) { + TSError("no value in Proxy-Authorization field\n"); + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + ptr = val; + if (strncmp(ptr, "Basic", 5) != 0) { + TSError("no Basic auth type in Proxy-Authorization\n"); + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + ptr += 5; + while ((*ptr == ' ') || (*ptr == '\t')) { + ptr += 1; + } + + user = base64_decode(ptr); + password = strchr(user, ':'); + if (!password) { + TSError("no password in authorization information\n"); + TSfree(user); + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + *password = '\0'; + password += 1; + + if (!authorized(user, password)) { + TSError("%s:%s not authorized\n", user, password); + TSfree(user); + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + TSfree(user); + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); + return; + +done: + TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp); + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); +} + +static void +handle_response(TSHttpTxn txnp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc field_loc; + const char *insert = "Basic realm=\"proxy\""; + int len = strlen(insert); + + if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client response header\n"); + goto done; + } + + TSHttpHdrStatusSet(bufp, hdr_loc, TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED); + TSHttpHdrReasonSet(bufp, hdr_loc, + TSHttpHdrReasonLookup(TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED), + strlen(TSHttpHdrReasonLookup(TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED))); + + TSMimeHdrFieldCreate(bufp, hdr_loc, &field_loc); // Probably should check for errors + TSMimeHdrFieldNameSet(bufp, hdr_loc, field_loc, TS_MIME_FIELD_PROXY_AUTHENTICATE, TS_MIME_LEN_PROXY_AUTHENTICATE); + TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, field_loc, -1, insert, len); + TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); + + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + +done: + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + +static int +auth_plugin(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = (TSHttpTxn) edata; + + switch (event) { + case TS_EVENT_HTTP_OS_DNS: + handle_dns(txnp, contp); + return 0; + case TS_EVENT_HTTP_SEND_RESPONSE_HDR: + handle_response(txnp); + return 0; + default: + break; + } + + return 0; +} + +int +check_ts_version() +{ + + const char *ts_version = TSTrafficServerVersionGet(); + int result = 0; + + if (ts_version) { + int major_ts_version = 0; + int minor_ts_version = 0; + int patch_ts_version = 0; + + if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) { + return 0; + } + + /* Need at least TS 2.0 */ + if (major_ts_version >= 2) { + result = 1; + } + + } + + return result; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + int i, cc; + TSPluginRegistrationInfo info; + + info.plugin_name = "basic-authorization"; + info.vendor_name = "MyCompany"; + info.support_email = "ts-api-support@MyCompany.com"; + + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + TSError("Plugin registration failed.\n"); + } + + if (!check_ts_version()) { + TSError("Plugin requires Traffic Server 3.0 or later\n"); + return; + } + + /* Build translation table */ + for (i = 0, cc = 0; i < 256; i++) { + base64_codes[i] = 0; + } + for (i = 'A'; i <= 'Z'; i++) { + base64_codes[i] = cc++; + } + for (i = 'a'; i <= 'z'; i++) { + base64_codes[i] = cc++; + } + for (i = '0'; i <= '9'; i++) { + base64_codes[i] = cc++; + } + base64_codes['+'] = cc++; + base64_codes['/'] = cc++; + + TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(auth_plugin, NULL)); +} + + +#if defined (_WIN32) +BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +#endif + diff --git a/example/basic-auth/readme.txt b/example/basic-auth/readme.txt new file mode 100644 index 00000000..62fe3e78 --- /dev/null +++ b/example/basic-auth/readme.txt @@ -0,0 +1,58 @@ +The basic-auth.c plugin performs basic HTTP proxy authentication. + +-- The plugin checks all client request headers for the Proxy-Authorization + MIME field, which should contain the user name and password. + + TSPluginInit sets up a global HTTP hook that calls the plugin + whenever there is a host DNS lookup. The plugin's continuation + handler, auth-plugin, calls handle_dns to check the + Proxy-Authorization field. + + handle_dns uses TSHttpTxnClientReqGet and TSMimeHdrFieldFind + to obtain the Proxy-Authorization field. + +-- If the request does not have the Proxy-Authorization field, + the plugin sends the 407 Proxy authorization required status + code back to the client. (The client should then prompt the + user for a user name and password, and resend the request + with the Proxy-Authorization field filled in.) + + If handle_dns does not find a Proxy-Authorization field, + it adds a SEND_RESPONSE_HDR_HOOK to the transaction being + processed; this means that Traffic Server will call the + plugin back when sending the client response. + + handle_dns also reenables the transaction with + TS_EVENT_HTTP_ERROR, which means that the plugin wants + Traffic Server to terminate the transaction. + + When Traffic Server terminates the transaction, it + sends the client an error message. Because of the + SEND_RESPONSE_HDR_HOOK, Traffic Server calls the plugin + back. The auth-plugin routine calls handle_response to + send the client a 407 status code. + + When the client resends the request with the Proxy- + Authorization field, a new transaction begins. + +-- If the Proxy-Authorization MIME field is present, the plugin + checks that the authentication scheme is "Basic". + + handle_dns uses TSMimeFieldValueStringGet to get the value + of the Proxy-Authorization field. + +-- The plugin then obtains the base64-encoded user name and password + from the Proxy-Authorization MIME field. + + handle_dns calls base64_decode to decode the user name + and password. + +-- This plugin checks the validity of the user name and password. + If the client is authenticated, the transaction proceeds. If + the client is not authenticated, the plugin sends the client + a 407 status code and terminates the transaction. + + handle_dns calls authorized to validate the user name and + password. In this plugin, sample NT code is provided for + password validation. Unix programmers can supply their own + validation mechanism. diff --git a/example/blacklist-0/Makefile.am b/example/blacklist-0/Makefile.am new file mode 100644 index 00000000..127ba8ad --- /dev/null +++ b/example/blacklist-0/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = blacklist-0.la +blacklist_0_la_SOURCES = blacklist-0.c +blacklist_0_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/blacklist-0.so diff --git a/example/blacklist-0/Makefile.in b/example/blacklist-0/Makefile.in new file mode 100644 index 00000000..600cb6ae --- /dev/null +++ b/example/blacklist-0/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/blacklist-0 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +blacklist_0_la_LIBADD = +am_blacklist_0_la_OBJECTS = blacklist-0.lo +blacklist_0_la_OBJECTS = $(am_blacklist_0_la_OBJECTS) +blacklist_0_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(blacklist_0_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(blacklist_0_la_SOURCES) +DIST_SOURCES = $(blacklist_0_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = blacklist-0.la +blacklist_0_la_SOURCES = blacklist-0.c +blacklist_0_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/blacklist-0/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/blacklist-0/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +blacklist-0.la: $(blacklist_0_la_OBJECTS) $(blacklist_0_la_DEPENDENCIES) + $(blacklist_0_la_LINK) -rpath $(pkglibdir) $(blacklist_0_la_OBJECTS) $(blacklist_0_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blacklist-0.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/blacklist-0.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/blacklist-0/blacklist-0.c b/example/blacklist-0/blacklist-0.c new file mode 100644 index 00000000..a493277b --- /dev/null +++ b/example/blacklist-0/blacklist-0.c @@ -0,0 +1,206 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * blacklist-0.c: + * original version of blacklist-1, now used for internal testing + * + * + * Usage: + * + */ + +#include +#include +#include + +static char **sites; +static int nsites; + +static void +handle_dns(TSHttpTxn txnp, TSCont contp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc url_loc; + const char *host; + int i; + int host_length; + + if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client request header\n"); + goto done; + } + + if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) { + TSError("couldn't retrieve request url\n"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + host = TSUrlHostGet(bufp, url_loc, &host_length); + if (!host) { + TSError("couldn't retrieve request hostname\n"); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + for (i = 0; i < nsites; i++) { + if (strncmp(host, sites[i], host_length) == 0) { + printf("blacklisting site: %s\n", sites[i]); + TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc); + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); + return; + } + } + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + +done: + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + +static void +handle_response(TSHttpTxn txnp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc url_loc; + char *url_str; + char *buf; + int url_length; + + if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client response header\n"); + goto done; + } + + TSHttpHdrStatusSet(bufp, hdr_loc, TS_HTTP_STATUS_FORBIDDEN); + TSHttpHdrReasonSet(bufp, hdr_loc, + TSHttpHdrReasonLookup(TS_HTTP_STATUS_FORBIDDEN), + strlen(TSHttpHdrReasonLookup(TS_HTTP_STATUS_FORBIDDEN))); + + if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client request header\n"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + if (!TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) { + TSError("couldn't retrieve request url\n"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + buf = TSmalloc(4096); + + url_str = TSUrlStringGet(bufp, url_loc, &url_length); + sprintf(buf, "You are forbidden from accessing \"%s\"\n", url_str); + TSfree(url_str); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + + TSHttpTxnErrorBodySet(txnp, buf, strlen(buf), NULL); + +done: + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + +static int +blacklist_plugin(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = (TSHttpTxn) edata; + + switch (event) { + case TS_EVENT_HTTP_OS_DNS: + handle_dns(txnp, contp); + return 0; + case TS_EVENT_HTTP_SEND_RESPONSE_HDR: + handle_response(txnp); + return 0; + default: + break; + } + return 0; +} + +int +check_ts_version() +{ + + const char *ts_version = TSTrafficServerVersionGet(); + int result = 0; + + if (ts_version) { + int major_ts_version = 0; + int minor_ts_version = 0; + int patch_ts_version = 0; + + if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) { + return 0; + } + + /* Need at least TS 2.0 */ + if (major_ts_version >= 2) { + result = 1; + } + + } + + return result; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + int i; + TSPluginRegistrationInfo info; + + info.plugin_name = "blacklist-0"; + info.vendor_name = "MyCompany"; + info.support_email = "ts-api-support@MyCompany.com"; + + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + TSError("Plugin registration failed.\n"); + + } + + if (!check_ts_version()) { + TSError("Plugin requires Traffic Server 3.0 or later\n"); + return; + } + + + nsites = argc - 1; + if (nsites > 0) { + sites = (char **) TSmalloc(sizeof(char *) * nsites); + + for (i = 0; i < nsites; i++) { + sites[i] = TSstrdup(argv[i + 1]); + } + + TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(blacklist_plugin, NULL)); + } +} diff --git a/example/blacklist-1/Makefile.am b/example/blacklist-1/Makefile.am new file mode 100644 index 00000000..1b0a5c51 --- /dev/null +++ b/example/blacklist-1/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = blacklist-1.la +blacklist_1_la_SOURCES = blacklist-1.c +blacklist_1_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/blacklist-1.so diff --git a/example/blacklist-1/Makefile.in b/example/blacklist-1/Makefile.in new file mode 100644 index 00000000..bf020a35 --- /dev/null +++ b/example/blacklist-1/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/blacklist-1 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +blacklist_1_la_LIBADD = +am_blacklist_1_la_OBJECTS = blacklist-1.lo +blacklist_1_la_OBJECTS = $(am_blacklist_1_la_OBJECTS) +blacklist_1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(blacklist_1_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(blacklist_1_la_SOURCES) +DIST_SOURCES = $(blacklist_1_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = blacklist-1.la +blacklist_1_la_SOURCES = blacklist-1.c +blacklist_1_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/blacklist-1/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/blacklist-1/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +blacklist-1.la: $(blacklist_1_la_OBJECTS) $(blacklist_1_la_DEPENDENCIES) + $(blacklist_1_la_LINK) -rpath $(pkglibdir) $(blacklist_1_la_OBJECTS) $(blacklist_1_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blacklist-1.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/blacklist-1.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/blacklist-1/blacklist-1.c b/example/blacklist-1/blacklist-1.c new file mode 100644 index 00000000..e470d945 --- /dev/null +++ b/example/blacklist-1/blacklist-1.c @@ -0,0 +1,371 @@ +/** @file + + An example plugin that denies client access to blacklisted sites (blacklist.txt). + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include + +#define MAX_NSITES 500 +#define RETRY_TIME 10 + +static char *sites[MAX_NSITES]; +static int nsites; +static TSMutex sites_mutex; +static TSTextLogObject log; +static TSCont global_contp; + +static void handle_txn_start(TSCont contp, TSHttpTxn txnp); + +typedef struct contp_data +{ + + enum calling_func + { + HANDLE_DNS, + HANDLE_RESPONSE, + READ_BLACKLIST + } cf; + + TSHttpTxn txnp; + +} cdata; + +static void +destroy_continuation(TSHttpTxn txnp, TSCont contp) +{ + cdata *cd = NULL; + + cd = (cdata *) TSContDataGet(contp); + if (cd != NULL) { + TSfree(cd); + } + TSContDestroy(contp); + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); + return; +} + + +static void +handle_dns(TSHttpTxn txnp, TSCont contp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc url_loc; + const char *host; + int i; + int host_length; + + if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client request header\n"); + goto done; + } + + if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) { + TSError("couldn't retrieve request url\n"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + host = TSUrlHostGet(bufp, url_loc, &host_length); + if (!host) { + TSError("couldn't retrieve request hostname\n"); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + /* We need to lock the sites_mutex as that is the mutex that is + protecting the global list of all blacklisted sites. */ + if (TSMutexLockTry(sites_mutex) != TS_SUCCESS) { + TSDebug("blacklist-1", "Unable to get lock. Will retry after some time"); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + TSContSchedule(contp, RETRY_TIME, TS_THREAD_POOL_DEFAULT); + return; + } + + for (i = 0; i < nsites; i++) { + if (strncmp(host, sites[i], host_length) == 0) { + if (log) { + TSTextLogObjectWrite(log, "blacklisting site: %s", sites[i]); + } else { + TSDebug("blacklist-1", "blacklisting site: %s\n", sites[i]); + } + TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); + TSMutexUnlock(sites_mutex); + return; + } + } + + TSMutexUnlock(sites_mutex); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + +done: + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + +static void +handle_response(TSHttpTxn txnp, TSCont contp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSMLoc url_loc; + char *url_str; + char *buf; + int url_length; + + if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client response header\n"); + goto done; + } + + TSHttpHdrStatusSet(bufp, hdr_loc, TS_HTTP_STATUS_FORBIDDEN); + TSHttpHdrReasonSet(bufp, hdr_loc, + TSHttpHdrReasonLookup(TS_HTTP_STATUS_FORBIDDEN), + strlen(TSHttpHdrReasonLookup(TS_HTTP_STATUS_FORBIDDEN))); + + if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + TSError("couldn't retrieve client request header\n"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) { + TSError("couldn't retrieve request url\n"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + goto done; + } + + buf = (char *) TSmalloc(4096); + + url_str = TSUrlStringGet(bufp, url_loc, &url_length); + sprintf(buf, "You are forbidden from accessing \"%s\"\n", url_str); + TSfree(url_str); + TSHandleMLocRelease(bufp, hdr_loc, url_loc); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + + TSHttpTxnErrorBodySet(txnp, buf, strlen(buf), NULL); + +done: + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + +static void +read_blacklist(TSCont contp) +{ + char blacklist_file[1024]; + TSFile file; + + sprintf(blacklist_file, "%s/blacklist.txt", TSPluginDirGet()); + file = TSfopen(blacklist_file, "r"); + nsites = 0; + + /* If the Mutext lock is not successful try again in RETRY_TIME */ + if (TSMutexLockTry(sites_mutex) != TS_SUCCESS) { + TSContSchedule(contp, RETRY_TIME, TS_THREAD_POOL_DEFAULT); + return; + } + + if (file != NULL) { + char buffer[1024]; + + while (TSfgets(file, buffer, sizeof(buffer) - 1) != NULL && nsites < MAX_NSITES) { + char *eol; + if ((eol = strstr(buffer, "\r\n")) != NULL) { + /* To handle newlines on Windows */ + *eol = '\0'; + } else if ((eol = strchr(buffer, '\n')) != NULL) { + *eol = '\0'; + } else { + /* Not a valid line, skip it */ + continue; + } + if (sites[nsites] != NULL) { + TSfree(sites[nsites]); + } + sites[nsites] = TSstrdup(buffer); + nsites++; + } + + TSfclose(file); + } else { + TSError("unable to open %s\n", blacklist_file); + TSError("all sites will be allowed\n", blacklist_file); + } + + TSMutexUnlock(sites_mutex); + +} + +static int +blacklist_plugin(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp; + cdata *cd; + + switch (event) { + case TS_EVENT_HTTP_TXN_START: + txnp = (TSHttpTxn) edata; + handle_txn_start(contp, txnp); + return 0; + case TS_EVENT_HTTP_OS_DNS: + if (contp != global_contp) { + cd = (cdata *) TSContDataGet(contp); + cd->cf = HANDLE_DNS; + handle_dns(cd->txnp, contp); + return 0; + } else { + break; + } + case TS_EVENT_HTTP_TXN_CLOSE: + txnp = (TSHttpTxn) edata; + if (contp != global_contp) { + destroy_continuation(txnp, contp); + } + break; + case TS_EVENT_HTTP_SEND_RESPONSE_HDR: + if (contp != global_contp) { + cd = (cdata *) TSContDataGet(contp); + cd->cf = HANDLE_RESPONSE; + handle_response(cd->txnp, contp); + return 0; + } else { + break; + } + case TS_EVENT_TIMEOUT: + /* when mutex lock is not acquired and continuation is rescheduled, + the plugin is called back with TS_EVENT_TIMEOUT with a NULL + edata. We need to decide, in which function did the MutexLock + failed and call that function again */ + if (contp != global_contp) { + cd = (cdata *) TSContDataGet(contp); + switch (cd->cf) { + case HANDLE_DNS: + handle_dns(cd->txnp, contp); + return 0; + case HANDLE_RESPONSE: + handle_response(cd->txnp, contp); + return 0; + default: + TSDebug("blacklist_plugin", "This event was unexpected: %d\n", event); + break; + } + } else { + read_blacklist(contp); + return 0; + } + default: + break; + } + return 0; +} + +static void +handle_txn_start(TSCont contp, TSHttpTxn txnp) +{ + TSCont txn_contp; + cdata *cd; + + txn_contp = TSContCreate((TSEventFunc) blacklist_plugin, TSMutexCreate()); + /* create the data that'll be associated with the continuation */ + cd = (cdata *) TSmalloc(sizeof(cdata)); + TSContDataSet(txn_contp, cd); + + cd->txnp = txnp; + + TSHttpTxnHookAdd(txnp, TS_HTTP_OS_DNS_HOOK, txn_contp); + TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp); + + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); +} + + +int +check_ts_version() +{ + + const char *ts_version = TSTrafficServerVersionGet(); + int result = 0; + + if (ts_version) { + int major_ts_version = 0; + int minor_ts_version = 0; + int patch_ts_version = 0; + + if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) { + return 0; + } + + /* Need at least TS 2.0 */ + if (major_ts_version >= 2) { + result = 1; + } + + } + + return result; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + int i; + TSPluginRegistrationInfo info; + TSReturnCode error; + + info.plugin_name = "blacklist-1"; + info.vendor_name = "MyCompany"; + info.support_email = "ts-api-support@MyCompany.com"; + + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + TSError("Plugin registration failed.\n"); + } + + if (!check_ts_version()) { + TSError("Plugin requires Traffic Server 3.0 or later\n"); + return; + } + + /* create an TSTextLogObject to log blacklisted requests to */ + error = TSTextLogObjectCreate("blacklist", TS_LOG_MODE_ADD_TIMESTAMP, &log); + if (!log || error == TS_ERROR) { + TSDebug("blacklist-1", "error while creating log"); + } + + sites_mutex = TSMutexCreate(); + + nsites = 0; + for (i = 0; i < MAX_NSITES; i++) { + sites[i] = NULL; + } + + global_contp = TSContCreate(blacklist_plugin, sites_mutex); + read_blacklist(global_contp); + + /*TSHttpHookAdd (TS_HTTP_OS_DNS_HOOK, contp); */ + TSHttpHookAdd(TS_HTTP_TXN_START_HOOK, global_contp); +} diff --git a/example/blacklist-1/blacklist.txt b/example/blacklist-1/blacklist.txt new file mode 100644 index 00000000..575cd181 --- /dev/null +++ b/example/blacklist-1/blacklist.txt @@ -0,0 +1,2 @@ +www.example.com + diff --git a/example/blacklist-1/readme.txt b/example/blacklist-1/readme.txt new file mode 100644 index 00000000..b8241c57 --- /dev/null +++ b/example/blacklist-1/readme.txt @@ -0,0 +1,17 @@ +How to run the blacklist plugin +=============================== + +1. Modify blacklist.cgi to specify the location of perl and traffic server. +2. Copy blacklist.cgi, blacklist-1.so, PoweredByInktomi.gif to the directory + specified by the variable proxy.config.plugin.plugin_dir. +3. Modify plugin.config to load the blacklist plugin. + + + +About the blacklist plugin +========================== + +The blacklist plugin allows Traffic Server to compare all incoming request +origin servers with a blacklisted set of web servers. If the requested origin +server is blacklisted, Traffic Server sends the client a message saying that +access is denied. diff --git a/example/bnull-transform/Makefile.am b/example/bnull-transform/Makefile.am new file mode 100644 index 00000000..0f30c3e3 --- /dev/null +++ b/example/bnull-transform/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = bnull-transform.la +bnull_transform_la_SOURCES = bnull-transform.c +bnull_transform_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/bnull-transform.so diff --git a/example/bnull-transform/Makefile.in b/example/bnull-transform/Makefile.in new file mode 100644 index 00000000..3ac2c946 --- /dev/null +++ b/example/bnull-transform/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/bnull-transform +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +bnull_transform_la_LIBADD = +am_bnull_transform_la_OBJECTS = bnull-transform.lo +bnull_transform_la_OBJECTS = $(am_bnull_transform_la_OBJECTS) +bnull_transform_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(bnull_transform_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(bnull_transform_la_SOURCES) +DIST_SOURCES = $(bnull_transform_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = bnull-transform.la +bnull_transform_la_SOURCES = bnull-transform.c +bnull_transform_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/bnull-transform/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/bnull-transform/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +bnull-transform.la: $(bnull_transform_la_OBJECTS) $(bnull_transform_la_DEPENDENCIES) + $(bnull_transform_la_LINK) -rpath $(pkglibdir) $(bnull_transform_la_OBJECTS) $(bnull_transform_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bnull-transform.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/bnull-transform.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/bnull-transform/bnull-transform.c b/example/bnull-transform/bnull-transform.c new file mode 100644 index 00000000..950ecf53 --- /dev/null +++ b/example/bnull-transform/bnull-transform.c @@ -0,0 +1,362 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* bnull-transform.c: an example program that illustrates a buffered + * null transform. + * + * + * + * Usage: + * (NT): BNullTransform.dll + * (Solaris): bnull-transform.so + * + * + */ + +/* set tab stops to four. */ + +#include +#include + +#define TS_NULL_MUTEX NULL +#define STATE_BUFFER_DATA 0 +#define STATE_OUTPUT_DATA 1 + +typedef struct +{ + int state; + TSVIO output_vio; + TSIOBuffer output_buffer; + TSIOBufferReader output_reader; +} MyData; + +static MyData * +my_data_alloc() +{ + MyData *data; + + data = (MyData *) TSmalloc(sizeof(MyData)); + data->state = STATE_BUFFER_DATA; + data->output_vio = NULL; + data->output_buffer = NULL; + data->output_reader = NULL; + + return data; +} + +static void +my_data_destroy(MyData * data) +{ + if (data) { + if (data->output_buffer) { + TSIOBufferDestroy(data->output_buffer); + } + TSfree(data); + } +} + +static int +handle_buffering(TSCont contp, MyData * data) +{ + TSVIO write_vio; + int towrite; + int avail; + + /* Get the write VIO for the write operation that was performed on + ourself. This VIO contains the buffer that we are to read from + as well as the continuation we are to call when the buffer is + empty. */ + write_vio = TSVConnWriteVIOGet(contp); + + /* Create the output buffer and its associated reader */ + if (!data->output_buffer) { + data->output_buffer = TSIOBufferCreate(); + TSAssert(data->output_buffer); + data->output_reader = TSIOBufferReaderAlloc(data->output_buffer); + TSAssert(data->output_reader); + } + + /* We also check to see if the write VIO's buffer is non-NULL. A + NULL buffer indicates that the write operation has been + shutdown and that the continuation does not want us to send any + more WRITE_READY or WRITE_COMPLETE events. For this buffered + transformation that means we're done buffering data. */ + + if (!TSVIOBufferGet(write_vio)) { + data->state = STATE_OUTPUT_DATA; + return 0; + } + + /* Determine how much data we have left to read. For this bnull + transform plugin this is also the amount of data we have left + to write to the output connection. */ + + towrite = TSVIONTodoGet(write_vio); + if (towrite > 0) { + /* The amount of data left to read needs to be truncated by + the amount of data actually in the read buffer. */ + + avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio)); + if (towrite > avail) { + towrite = avail; + } + + if (towrite > 0) { + /* Copy the data from the read buffer to the input buffer. */ + TSIOBufferCopy(data->output_buffer, TSVIOReaderGet(write_vio), towrite, 0); + + /* Tell the read buffer that we have read the data and are no + longer interested in it. */ + TSIOBufferReaderConsume(TSVIOReaderGet(write_vio), towrite); + + /* Modify the write VIO to reflect how much data we've + completed. */ + TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite); + } + } + + /* Now we check the write VIO to see if there is data left to read. */ + if (TSVIONTodoGet(write_vio) > 0) { + if (towrite > 0) { + /* Call back the write VIO continuation to let it know that we + are ready for more data. */ + TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio); + } + } else { + data->state = STATE_OUTPUT_DATA; + + /* Call back the write VIO continuation to let it know that we + have completed the write operation. */ + TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio); + } + + return 1; + + /* If we are in this code path then something is seriously wrong. */ + TSError("[bnull-transform] Fatal error in plugin"); + TSReleaseAssert(!"[bnull-transform] Fatal error in plugin\n"); + return 0; +} + +static int +handle_output(TSCont contp, MyData * data) +{ + /* Check to see if we need to initiate the output operation. */ + if (!data->output_vio) { + TSVConn output_conn; + + /* Get the output connection where we'll write data to. */ + output_conn = TSTransformOutputVConnGet(contp); + + data->output_vio = + TSVConnWrite(output_conn, contp, data->output_reader, TSIOBufferReaderAvail(data->output_reader)); + + TSAssert(data->output_vio); + } + return 1; +} + +static void +handle_transform(TSCont contp) +{ + MyData *data; + int done; + + /* Get our data structure for this operation. The private data + structure contains the output VIO and output buffer. If the + private data structure pointer is NULL, then we'll create it + and initialize its internals. */ + + data = TSContDataGet(contp); + if (!data) { + data = my_data_alloc(); + TSContDataSet(contp, data); + } + + do { + switch (data->state) { + case STATE_BUFFER_DATA: + done = handle_buffering(contp, data); + break; + case STATE_OUTPUT_DATA: + done = handle_output(contp, data); + break; + default: + done = 1; + break; + } + } while (!done); +} + +static int +bnull_transform(TSCont contp, TSEvent event, void *edata) +{ + /* Check to see if the transformation has been closed by a + call to TSVConnClose. */ + + if (TSVConnClosedGet(contp)) { + my_data_destroy(TSContDataGet(contp)); + TSContDestroy(contp); + } else { + switch (event) { + case TS_EVENT_ERROR:{ + TSVIO write_vio; + + /* Get the write VIO for the write operation that was + performed on ourself. This VIO contains the continuation of + our parent transformation. */ + write_vio = TSVConnWriteVIOGet(contp); + + /* Call back the write VIO continuation to let it know that we + have completed the write operation. */ + TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio); + break; + } + + case TS_EVENT_VCONN_WRITE_COMPLETE: + /* When our output connection says that it has finished + reading all the data we've written to it then we should + shutdown the write portion of its connection to + indicate that we don't want to hear about it anymore. */ + + TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1); + break; + + case TS_EVENT_VCONN_WRITE_READY: + default: + /* If we get a WRITE_READY event or any other type of event + (sent, perhaps, because we were reenabled) then we'll attempt + to transform more data. */ + handle_transform(contp); + break; + } + } + + return 0; +} + +static int +transformable(TSHttpTxn txnp) +{ + TSMBuffer bufp; + TSMLoc hdr_loc; + TSHttpStatus resp_status; + int retv; + + /* We are only interested in transforming "200 OK" responses. */ + + TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc); + resp_status = TSHttpHdrStatusGet(bufp, hdr_loc); + retv = (resp_status == TS_HTTP_STATUS_OK); + + if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) == TS_ERROR) { + TSError("[bnull-transform] Error releasing MLOC while checking " "header status\n"); + } + + return retv; +} + +static void +transform_add(TSHttpTxn txnp) +{ + TSVConn connp; + + connp = TSTransformCreate(bnull_transform, txnp); + TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp); + return; +} + +static int +transform_plugin(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = (TSHttpTxn) edata; + + switch (event) { + case TS_EVENT_HTTP_READ_RESPONSE_HDR: + if (transformable(txnp)) { + transform_add(txnp); + } + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); + return 0; + default: + break; + } + + return 0; +} + +int +check_ts_version() +{ + const char *ts_version = TSTrafficServerVersionGet(); + int result = 0; + + if (ts_version) { + + int major_ts_version = 0; + int minor_ts_version = 0; + int patch_ts_version = 0; + + if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) { + return 0; + } + + /* Need at least TS 2.0 */ + if (major_ts_version >= 2) { + result = 1; + } + + } + + return result; +} + +void +TSPluginInit(int argc, const char *argv[]) +{ + TSPluginRegistrationInfo info; + TSMutex mutex = TS_NULL_MUTEX; + + info.plugin_name = "buffered-null-transform"; + info.vendor_name = "MyCompany"; + info.support_email = "ts-api-support@MyCompany.com"; + + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + TSError("[bnull-transform] Plugin registration failed.\n"); + goto Lerror; + } + + if (!check_ts_version()) { + TSError("[bnull-transform] Plugin requires Traffic Server 3.0" " or later\n"); + goto Lerror; + } + + /* This is call we could use if we need to protect global data */ + /* TSReleaseAssert ((mutex = TSMutexCreate()) != TS_NULL_MUTEX); */ + + TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, mutex)); + return; + +Lerror: + TSError("[bnull-transform] Plugin disabled\n"); +} diff --git a/example/cache_scan/Makefile.am b/example/cache_scan/Makefile.am new file mode 100644 index 00000000..4828f92e --- /dev/null +++ b/example/cache_scan/Makefile.am @@ -0,0 +1,25 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CXXFLAGS+=-I$(top_srcdir)/proxy/api + +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = cache_scan.la +cache_scan_la_SOURCES = cache_scan.cc +cache_scan_la_LDFLAGS = -module -avoid-version -shared + +all: + ln -sf .libs/cache_scan.so diff --git a/example/cache_scan/Makefile.in b/example/cache_scan/Makefile.in new file mode 100644 index 00000000..d429626f --- /dev/null +++ b/example/cache_scan/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = example/cache_scan +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +cache_scan_la_LIBADD = +am_cache_scan_la_OBJECTS = cache_scan.lo +cache_scan_la_OBJECTS = $(am_cache_scan_la_OBJECTS) +cache_scan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(cache_scan_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(cache_scan_la_SOURCES) +DIST_SOURCES = $(cache_scan_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = ${pkglibexecdir} +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ -I$(top_srcdir)/proxy/api +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +pkglib_LTLIBRARIES = cache_scan.la +cache_scan_la_SOURCES = cache_scan.cc +cache_scan_la_LDFLAGS = -module -avoid-version -shared +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/cache_scan/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign example/cache_scan/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +cache_scan.la: $(cache_scan_la_OBJECTS) $(cache_scan_la_DEPENDENCIES) + $(cache_scan_la_LINK) -rpath $(pkglibdir) $(cache_scan_la_OBJECTS) $(cache_scan_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache_scan.Plo@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES + + +all: + ln -sf .libs/cache_scan.so + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/example/cache_scan/cache_scan.cc b/example/cache_scan/cache_scan.cc new file mode 100644 index 00000000..638dbdb6 --- /dev/null +++ b/example/cache_scan/cache_scan.cc @@ -0,0 +1,496 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * cache_scan.cc: use TSCacheScan to print URLs and headers for objects in + * the cache when endpoint /show-cache is requested + */ +#include +#include +#include +#include +#define __STDC_LIMIT_MACROS +#include +#include + +static TSCont global_contp; + +struct cache_scan_state_t +{ + TSVConn net_vc; + TSVConn cache_vc; + TSVIO read_vio; + TSVIO write_vio; + + TSIOBuffer req_buffer; + TSIOBuffer resp_buffer; + TSIOBufferReader resp_reader; + + TSHttpTxn http_txnp; + TSAction pending_action; + TSCacheKey key_to_delete; + + int64_t total_bytes; + int total_items; + int done; + + bool write_pending; +}; + +typedef struct cache_scan_state_t cache_scan_state; + + +//---------------------------------------------------------------------------- +static int +handle_scan(TSCont contp, TSEvent event, void *edata) +{ + TSCacheHttpInfo cache_infop; + cache_scan_state *cstate = (cache_scan_state *) TSContDataGet(contp); + + if (event == TS_EVENT_CACHE_REMOVE) { + cstate->done = 1; + const char error[] = "Cache remove operation succeeded"; + cstate->cache_vc = (TSVConn) edata; + cstate->write_vio = TSVConnWrite(cstate->net_vc, contp, cstate->resp_reader, INT64_MAX); + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, error, sizeof(error) - 1); + TSVIONBytesSet(cstate->write_vio, cstate->total_bytes); + TSVIOReenable(cstate->write_vio); + return 0; + } + + if (event == TS_EVENT_CACHE_REMOVE_FAILED) { + cstate->done = 1; + const char error[] = "Cache remove operation failed error="; + char rc[12]; + snprintf(rc, 12, "%p", edata); + cstate->cache_vc = (TSVConn) edata; + cstate->write_vio = TSVConnWrite(cstate->net_vc, contp, cstate->resp_reader, INT64_MAX); + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, error, sizeof(error) - 1); + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, rc, strlen(rc)); + + TSVIONBytesSet(cstate->write_vio, cstate->total_bytes); + TSVIOReenable(cstate->write_vio); + return 0; + } + + //first scan event, save vc and start write + if (event == TS_EVENT_CACHE_SCAN) { + cstate->cache_vc = (TSVConn) edata; + cstate->write_vio = TSVConnWrite(cstate->net_vc, contp, cstate->resp_reader, INT64_MAX); + return TS_EVENT_CONTINUE; + } + //just stop scanning if blocked or failed + if (event == TS_EVENT_CACHE_SCAN_FAILED || + event == TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED || event == TS_EVENT_CACHE_SCAN_OPERATION_FAILED) { + cstate->done = 1; + if (cstate->resp_buffer) { + const char error[] = "Cache scan operation blocked or failed"; + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, error, sizeof(error) - 1); + } + if (cstate->write_vio) { + TSVIONBytesSet(cstate->write_vio, cstate->total_bytes); + TSVIOReenable(cstate->write_vio); + } + return TS_CACHE_SCAN_RESULT_DONE; + } + + //grab header and print url to outgoing vio + if (event == TS_EVENT_CACHE_SCAN_OBJECT) { + if (cstate->done) { + return TS_CACHE_SCAN_RESULT_DONE; + } + cache_infop = (TSCacheHttpInfo) edata; + + TSMBuffer req_bufp, resp_bufp; + TSMLoc req_hdr_loc, resp_hdr_loc; + TSMLoc url_loc; + + char *url; + int url_len; + const char s1[] = "URL: ", s2[] = "\n"; + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, s1, sizeof(s1) - 1); + TSCacheHttpInfoReqGet(cache_infop, &req_bufp, &req_hdr_loc); + TSHttpHdrUrlGet(req_bufp, req_hdr_loc, &url_loc); + url = TSUrlStringGet(req_bufp, url_loc, &url_len); + + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, url, url_len); + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, s2, sizeof(s2) - 1); + + TSfree(url); + TSHandleMLocRelease(req_bufp, req_hdr_loc, url_loc); + TSHandleMLocRelease(req_bufp, TS_NULL_MLOC, req_hdr_loc); + + + //print the response headers + TSCacheHttpInfoRespGet(cache_infop, &resp_bufp, &resp_hdr_loc); + cstate->total_bytes += TSMimeHdrLengthGet(resp_bufp, resp_hdr_loc); + TSMimeHdrPrint(resp_bufp, resp_hdr_loc, cstate->resp_buffer); + TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_hdr_loc); + + + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, s2, sizeof(s2) - 1); + if (!cstate->write_pending) { + cstate->write_pending = 1; + TSVIOReenable(cstate->write_vio); + } + + cstate->total_items++; + return TS_CACHE_SCAN_RESULT_CONTINUE; + } + //CACHE_SCAN_DONE: ready to close the vc on the next write reenable + if (event == TS_EVENT_CACHE_SCAN_DONE) { + cstate->done = 1; + char s[512]; + int s_len = snprintf(s, sizeof(s), + "

\n

%d total objects in cache

\n" + "
" + "Enter URL to delete: " + "", + cstate->total_items); + cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, s, s_len); + TSVIONBytesSet(cstate->write_vio, cstate->total_bytes); + if (!cstate->write_pending) { + cstate->write_pending = 1; + TSVIOReenable(cstate->write_vio); + } + return TS_CACHE_SCAN_RESULT_DONE; + } + + TSError("Unknown event in handle_scan: %d", event); + return -1; +} + +//---------------------------------------------------------------------------- +static int +handle_accept(TSCont contp, TSEvent event, TSVConn vc) +{ + cache_scan_state *cstate = (cache_scan_state *) TSContDataGet(contp); + + if (event == TS_EVENT_NET_ACCEPT) { + if (cstate) { + //setup vc, buffers + cstate->net_vc = vc; + + cstate->req_buffer = TSIOBufferCreate(); + cstate->resp_buffer = TSIOBufferCreate(); + cstate->resp_reader = TSIOBufferReaderAlloc(cstate->resp_buffer); + + cstate->read_vio = TSVConnRead(cstate->net_vc, contp, cstate->req_buffer, INT64_MAX); + } else { + TSVConnClose(vc); + TSContDestroy(contp); + } + } else { + //net_accept failed + if (cstate) { + TSfree(cstate); + } + TSContDestroy(contp); + } + + return 0; +} + +//---------------------------------------------------------------------------- +static void +cleanup(TSCont contp) +{ + + //shutdown vc and free memory + cache_scan_state *cstate = (cache_scan_state *) TSContDataGet(contp); + + if (cstate) { + // cancel any pending cache scan actions, since we will be destroying the + // continuation + if (cstate->pending_action) + TSActionCancel(cstate->pending_action); + + if (cstate->net_vc) + TSVConnShutdown(cstate->net_vc, 1, 1); + + if (cstate->req_buffer) { + TSIOBufferDestroy(cstate->req_buffer); + cstate->req_buffer = NULL; + } + + if (cstate->key_to_delete) { + if (TSCacheKeyDestroy(cstate->key_to_delete) == TS_ERROR) { + TSError("failed to destroy cache key"); + } + cstate->key_to_delete = NULL; + } + + if (cstate->resp_buffer) { + TSIOBufferDestroy(cstate->resp_buffer); + cstate->resp_buffer = NULL; + } + + TSVConnClose(cstate->net_vc); + TSfree(cstate); + } + TSContDestroy(contp); +} + +//---------------------------------------------------------------------------- +static int +handle_io(TSCont contp, TSEvent event, void *edata) +{ + cache_scan_state *cstate = (cache_scan_state *) TSContDataGet(contp); + + switch (event) { + case TS_EVENT_VCONN_READ_READY: + case TS_EVENT_VCONN_READ_COMPLETE: + { + //we don't care about the request, so just shut down the read vc + TSVConnShutdown(cstate->net_vc, 1, 0); + //setup the response headers so we are ready to write body + char hdrs[] = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"; + cstate->total_bytes = TSIOBufferWrite(cstate->resp_buffer, hdrs, sizeof(hdrs) - 1); + + if (cstate->key_to_delete) { + TSAction actionp = TSCacheRemove(contp, cstate->key_to_delete); + if (!TSActionDone(actionp)) { + cstate->pending_action = actionp; + } + } else { + char head[] = "

Cache Contents:

\n

\n";
+        cstate->total_bytes += TSIOBufferWrite(cstate->resp_buffer, head, sizeof(head) - 1);
+        //start scan
+        TSAction actionp = TSCacheScan(contp, 0, 512000);
+        if (!TSActionDone(actionp)) {
+          cstate->pending_action = actionp;
+        }
+      }
+
+      return 0;
+    }
+  case TS_EVENT_VCONN_WRITE_READY:
+    {
+      TSDebug("cache_iter", "ndone: %d total_bytes: %d", TSVIONDoneGet(cstate->write_vio), cstate->total_bytes);
+      cstate->write_pending = 0;
+      // the cache scan handler should call vio reenable when there is
+      // available data
+      //TSVIOReenable(cstate->write_vio);
+      return 0;
+    }
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    TSDebug("cache_iter", "write complete");
+  case TS_EVENT_VCONN_EOS:
+  default:
+    cstate->done = 1;
+    cleanup(contp);
+  }
+
+  return 0;
+}
+
+
+//----------------------------------------------------------------------------
+// handler for VConnection and CacheScan events
+static int
+cache_intercept(TSCont contp, TSEvent event, void *edata)
+{
+  TSDebug("cache_iter", "cache_intercept event: %d", event);
+
+  switch (event) {
+  case TS_EVENT_NET_ACCEPT:
+  case TS_EVENT_NET_ACCEPT_FAILED:
+    return handle_accept(contp, event, (TSVConn) edata);
+  case TS_EVENT_VCONN_READ_READY:
+  case TS_EVENT_VCONN_READ_COMPLETE:
+  case TS_EVENT_VCONN_WRITE_READY:
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+  case TS_EVENT_VCONN_EOS:
+    return handle_io(contp, event, edata);
+  case TS_EVENT_CACHE_SCAN:
+  case TS_EVENT_CACHE_SCAN_FAILED:
+  case TS_EVENT_CACHE_SCAN_OBJECT:
+  case TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED:
+  case TS_EVENT_CACHE_SCAN_OPERATION_FAILED:
+  case TS_EVENT_CACHE_SCAN_DONE:
+  case TS_EVENT_CACHE_REMOVE:
+  case TS_EVENT_CACHE_REMOVE_FAILED:
+    return handle_scan(contp, event, edata);
+  case TS_EVENT_ERROR:
+    cleanup(contp);
+    return 0;
+  default:
+    TSError("Unknown event in cache_intercept: %d", event);
+    cleanup(contp);
+    return 0;
+  }
+}
+
+// int unescapifyStr(char* buffer)
+//
+//   Unescapifies a URL without a making a copy.
+//    The passed in string is modified
+//
+int
+unescapifyStr(char *buffer)
+{
+  char *read = buffer;
+  char *write = buffer;
+  char subStr[3];
+
+  subStr[2] = '\0';
+  while (*read != '\0') {
+    if (*read == '%' && *(read + 1) != '\0' && *(read + 2) != '\0') {
+      subStr[0] = *(++read);
+      subStr[1] = *(++read);
+      *write = (char)strtol(subStr, (char **) NULL, 16);
+      read++;
+      write++;
+    } else if (*read == '+') {
+      *write = ' ';
+      write++;
+      read++;
+    } else {
+      *write = *read;
+      write++;
+      read++;
+    }
+  }
+  *write = '\0';
+
+  return (write - buffer);
+}
+
+//----------------------------------------------------------------------------
+static int
+setup_request(TSCont contp, TSHttpTxn txnp)
+{
+
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSMLoc url_loc;
+  TSCont scan_contp;
+  const char *path, *query;
+  cache_scan_state *cstate;
+  int path_len, query_len;
+
+  TSAssert(contp == global_contp);
+
+  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+    TSError("couldn't retrieve client request header");
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    return TS_SUCCESS;
+  }
+
+  if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
+    TSError("couldn't retrieve request url");
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    return TS_SUCCESS;
+  }
+
+  path = TSUrlPathGet(bufp, url_loc, &path_len);
+  if (!path) {
+    TSError("couldn't retrieve request path");
+    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    return TS_SUCCESS;
+  }
+
+  query = TSUrlHttpQueryGet(bufp, url_loc, &query_len);
+
+  if (path_len == 10 && !strncmp(path, "show-cache", 10)) {
+    scan_contp = TSContCreate(cache_intercept, TSMutexCreate());
+    TSHttpTxnIntercept(scan_contp, txnp);
+    cstate = (cache_scan_state *) TSmalloc(sizeof(cache_scan_state));
+    memset(cstate, 0, sizeof(cache_scan_state));
+    cstate->http_txnp = txnp;
+
+    if (query && query_len > 11) {
+
+      char querybuf[2048];
+      query_len = (unsigned) query_len > sizeof(querybuf) - 1 ? sizeof(querybuf) - 1 : query_len;
+      char *start = querybuf, *end = querybuf + query_len;
+      size_t del_url_len;
+      memcpy(querybuf, query, query_len);
+      *end = '\0';
+      start = strstr(querybuf, "remove_url=");
+      if (start && (start == querybuf || *(start - 1) == '&')) {
+        start += 11;
+        if ((end = strstr(start, "&")) != NULL)
+          *end = '\0';
+        del_url_len = unescapifyStr(start);
+        end = start + del_url_len;
+
+        cstate->key_to_delete = TSCacheKeyCreate();
+        TSDebug("cache_iter", "deleting url: %s", start);
+
+        TSMBuffer urlBuf = TSMBufferCreate();
+        TSMLoc urlLoc;
+
+        TSUrlCreate(urlBuf, &urlLoc);
+        if (TSUrlParse(urlBuf, urlLoc, (const char **) &start, end) != TS_PARSE_DONE ||
+            TSCacheKeyDigestFromUrlSet(cstate->key_to_delete, urlLoc) != TS_SUCCESS) {
+          TSError("CacheKeyDigestFromUrlSet failed");
+          TSfree(cstate);
+          TSUrlDestroy(urlBuf, urlLoc);
+          TSHandleMLocRelease(urlBuf, NULL, urlLoc);
+          TSCacheKeyDestroy(cstate->key_to_delete);
+          goto Ldone;
+        }
+        TSUrlDestroy(urlBuf, urlLoc);
+        TSHandleMLocRelease(urlBuf, NULL, urlLoc);
+      }
+    }
+
+    TSContDataSet(scan_contp, cstate);
+    TSDebug("cache_iter", "setup cache intercept");
+  } else {
+    TSDebug("cache_iter", "not a cache iter request");
+  }
+
+Ldone:
+  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return TS_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+// handler for http txn events
+static int
+cache_print_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+    return setup_request(contp, (TSHttpTxn) edata);
+  default:
+    break;
+  }
+  TSHttpTxnReenable((TSHttpTxn) edata, TS_EVENT_HTTP_CONTINUE);
+  return TS_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  global_contp = TSContCreate(cache_print_plugin, TSMutexCreate());
+  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, global_contp);
+}
diff --git a/example/file-1/Makefile.am b/example/file-1/Makefile.am
new file mode 100644
index 00000000..ab546c16
--- /dev/null
+++ b/example/file-1/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = file-1.la
+file_1_la_SOURCES = file-1.c
+file_1_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/file-1.so
diff --git a/example/file-1/Makefile.in b/example/file-1/Makefile.in
new file mode 100644
index 00000000..841078ec
--- /dev/null
+++ b/example/file-1/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/file-1
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+file_1_la_LIBADD =
+am_file_1_la_OBJECTS = file-1.lo
+file_1_la_OBJECTS = $(am_file_1_la_OBJECTS)
+file_1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(file_1_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(file_1_la_SOURCES)
+DIST_SOURCES = $(file_1_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = file-1.la
+file_1_la_SOURCES = file-1.c
+file_1_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/file-1/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/file-1/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+file-1.la: $(file_1_la_OBJECTS) $(file_1_la_DEPENDENCIES) 
+	$(file_1_la_LINK) -rpath $(pkglibdir) $(file_1_la_OBJECTS) $(file_1_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file-1.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/file-1.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/file-1/file-1.c b/example/file-1/file-1.c
new file mode 100644
index 00000000..9c859f5e
--- /dev/null
+++ b/example/file-1/file-1.c
@@ -0,0 +1,99 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* file-1.c:  an example program that opens files and reads them
+ *            into a buffer
+ *
+ *
+ *	Usage:
+ *	(NT): File.dll   ...
+ *	(Solaris): file-1.so   ...
+ *
+ *               is the name of the ith file to
+ *              be read.
+ *
+ */
+
+#include 
+#include 
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSFile filep;
+  char buf[4096];
+  int i;
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "file_plugin";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  for (i = 1; i < argc; i++) {
+    filep = TSfopen(argv[i], "r");
+    if (!filep) {
+      continue;
+    }
+
+    while (TSfgets(filep, buf, 4096)) {
+      TSDebug("debug-file", "%s", buf);
+    }
+
+    TSfclose(filep);
+  }
+}
+
diff --git a/example/file-1/readme.txt b/example/file-1/readme.txt
new file mode 100644
index 00000000..0eeba603
--- /dev/null
+++ b/example/file-1/readme.txt
@@ -0,0 +1,36 @@
+About file-plugin.c
+
+This plugin simply reads a file and writes its contents to
+a buffer. 
+
+In a typical Traffic Server installation, this buffer is 
+written to traffic.out.
+
+A similar function is used in the append-transform plugin 
+which reads in text from a file, and appends the text to the 
+bodies of html response documents. (See the load function in
+append-transform.c).
+
+To use this plugin, you would need a line like this in  
+plugin.config:
+
+	On NT:	File.dll path/to/file.text
+	On Solaris: file-1.so path/to/file.text
+
+Enter either an absolute or a relative pathname for the file.  
+If you use a relative pathname, the path must be specified with 
+respect to the Traffic Server install directory.  (That is, the path 
+contained in /etc/traffic_server.)
+
+The only function defined is TSPluginInit.
+
+It does the following:
+
+- opens the file specified in plugin.config, using
+	TSfopen
+
+- reads the content of the file into a buffer using 
+	TSfgets
+
+- closes the file using 
+	TSfclose
diff --git a/example/gzip-transform/Makefile.am b/example/gzip-transform/Makefile.am
new file mode 100644
index 00000000..277bdcd2
--- /dev/null
+++ b/example/gzip-transform/Makefile.am
@@ -0,0 +1,29 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = gzip.la gunzip.la
+gzip_la_SOURCES = gzip.c
+gzip_la_LDFLAGS = -module -avoid-version -shared
+
+gunzip_la_SOURCES = gunzip.c
+gunzip_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/gzip.so
+	ln -sf .libs/gunzip.so
diff --git a/example/gzip-transform/Makefile.in b/example/gzip-transform/Makefile.in
new file mode 100644
index 00000000..4b0a334c
--- /dev/null
+++ b/example/gzip-transform/Makefile.in
@@ -0,0 +1,749 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/gzip-transform
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+gunzip_la_LIBADD =
+am_gunzip_la_OBJECTS = gunzip.lo
+gunzip_la_OBJECTS = $(am_gunzip_la_OBJECTS)
+gunzip_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(gunzip_la_LDFLAGS) $(LDFLAGS) -o $@
+gzip_la_LIBADD =
+am_gzip_la_OBJECTS = gzip.lo
+gzip_la_OBJECTS = $(am_gzip_la_OBJECTS)
+gzip_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(gzip_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(gunzip_la_SOURCES) $(gzip_la_SOURCES)
+DIST_SOURCES = $(gunzip_la_SOURCES) $(gzip_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = gzip.la gunzip.la
+gzip_la_SOURCES = gzip.c
+gzip_la_LDFLAGS = -module -avoid-version -shared
+gunzip_la_SOURCES = gunzip.c
+gunzip_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/gzip-transform/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/gzip-transform/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+gunzip.la: $(gunzip_la_OBJECTS) $(gunzip_la_DEPENDENCIES) 
+	$(gunzip_la_LINK) -rpath $(pkglibdir) $(gunzip_la_OBJECTS) $(gunzip_la_LIBADD) $(LIBS)
+gzip.la: $(gzip_la_OBJECTS) $(gzip_la_DEPENDENCIES) 
+	$(gzip_la_LINK) -rpath $(pkglibdir) $(gzip_la_OBJECTS) $(gzip_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gunzip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gzip.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/gzip.so
+	ln -sf .libs/gunzip.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/gzip-transform/README.txt b/example/gzip-transform/README.txt
new file mode 100644
index 00000000..dce6c4c7
--- /dev/null
+++ b/example/gzip-transform/README.txt
@@ -0,0 +1,12 @@
+Gzip / Gunzip plugins
+---------------------
+
+These plugins work only in conjunction and should not be used
+separately to compress or uncompress data.
+For instance a TS child runs gunzip and parent runs gzip.
+Gzip compresses on one side and gunzip decompresses on the other.
+
+Note that gzip plugin produces a compressed file slightly different
+from what the gzip utility does (the header is different). 
+Thus, file compressed by gzip utility can not be uncompressed by gunzip. 
+ 
diff --git a/example/gzip-transform/gunzip.c b/example/gzip-transform/gunzip.c
new file mode 100644
index 00000000..f4db0401
--- /dev/null
+++ b/example/gzip-transform/gunzip.c
@@ -0,0 +1,545 @@
+/** @file
+
+  Transforms content using gzip
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DICT_PATH_MAX 512
+#define DICT_ENTRY_MAX 2048
+
+typedef struct
+{
+  TSHttpTxn txn;
+  TSVIO output_vio;
+  TSIOBuffer output_buffer;
+  TSIOBufferReader output_reader;
+  int output_length;
+  z_stream zstrm;
+  uLong crc;
+  int state;
+  int flag;
+} GzipData;
+
+char preload_file[1024];
+uLong dictId;
+int preload = 0;
+char dictionary[800000];
+
+
+void
+load_dictionary(char *dict, uLong * adler)
+{
+  FILE *fp;
+  int i = 0;
+
+  fp = fopen(preload_file, "r");
+  if (!fp) {
+    TSError("gunzip-transform: ERROR: Unable to open dict file %s\n", preload_file);
+    exit(0);
+  }
+
+  i = 0;
+  while (!feof(fp)) {
+    if (fscanf(fp, "%s\n", dict + i) == 1) {
+      i = strlen(dict);
+      strcat(dict + i, " ");
+      i++;
+    }
+  }
+  dict[i - 1] = '\0';
+
+  /* TODO figure out the right way to do the adler -- this one is all messed up */
+  *adler = adler32(*adler, (Byte *) dict, strlen(dict));
+}
+
+static voidpf
+gzip_alloc(voidpf opaque, uInt items, uInt size)
+{
+  return (voidpf) TSmalloc(items * size);
+}
+
+
+static void
+gzip_free(voidpf opaque, voidpf address)
+{
+  TSfree(address);
+}
+
+
+static GzipData *
+gzip_data_alloc()
+{
+  GzipData *data;
+
+  data = (GzipData *) TSmalloc(sizeof(GzipData));
+  data->output_vio = NULL;
+  data->output_buffer = NULL;
+  data->output_reader = NULL;
+  data->output_length = 0;
+  data->state = 0;
+  data->flag = 1;
+  data->crc = crc32(0L, Z_NULL, 0);
+
+  data->zstrm.next_in = Z_NULL;
+  data->zstrm.avail_in = 0;
+  data->zstrm.total_in = 0;
+  data->zstrm.next_out = Z_NULL;
+  data->zstrm.avail_out = 0;
+  data->zstrm.total_out = 0;
+  data->zstrm.zalloc = gzip_alloc;
+  data->zstrm.zfree = gzip_free;
+  data->zstrm.opaque = (voidpf) 0;      /* Z_NULL */
+  data->zstrm.data_type = Z_ASCII;
+
+  dictId = adler32(0L, Z_NULL, 0);
+
+  return data;
+}
+
+
+static void
+gzip_data_destroy(GzipData * data)
+{
+  int err;
+
+  if (data) {
+    err = inflateEnd(&data->zstrm);
+    if (err != Z_OK) {
+      TSError("gunzip-transform: ERROR: inflateEnd (%d)!", err);
+    }
+
+    if (data->output_buffer)
+      TSIOBufferDestroy(data->output_buffer);
+    TSfree(data);
+  }
+}
+
+
+static void
+gzip_transform_init(TSCont contp, GzipData * data)
+{
+  TSVConn output_conn;
+
+  data->state = 1;
+
+  /* Get the output connection where we'll write data to. */
+  output_conn = TSTransformOutputVConnGet(contp);
+
+  data->output_buffer = TSIOBufferCreate();
+  data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
+  data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
+}
+
+
+static void
+gzip_transform_one(GzipData * data, TSIOBufferReader input_reader, int amount)
+{
+  TSIOBufferBlock blkp;
+  const char *ibuf;
+  char *obuf;
+  int64_t ilength, olength;
+  int err = Z_OK;
+
+  while (amount > 0) {
+    blkp = TSIOBufferReaderStart(input_reader);
+    ibuf = TSIOBufferBlockReadStart(blkp, input_reader, &ilength);
+
+    if (ilength > amount) {
+      ilength = amount;
+    }
+
+    data->zstrm.next_in = (unsigned char *) ibuf;
+    data->zstrm.avail_in = ilength;
+
+    if (data->flag) {
+      err = inflateInit(&data->zstrm);
+      data->flag = 0;
+      if (err != Z_OK) {
+        TSError("gunzip-transform: ERROR: inflateInit (%d)!", err);
+        exit(1);
+      }
+    }
+
+    while (data->zstrm.avail_in > 0 && err != Z_STREAM_END) {
+      blkp = TSIOBufferStart(data->output_buffer);
+
+      obuf = TSIOBufferBlockWriteStart(blkp, &olength);
+
+      data->zstrm.next_out = (unsigned char *) obuf;
+      data->zstrm.avail_out = olength;
+
+      /* Uncompress */
+      err = inflate(&data->zstrm, Z_NO_FLUSH);
+/*
+	    assert( (err == Z_OK) || (err = Z_STREAM_END) || (err = Z_NEED_DICT));
+*/
+      if (err == Z_NEED_DICT) {
+        assert(preload);
+        TSDebug("gunzip-transform", "Transform needs dictionary");
+        /* TODO assert encoding dict is same as the decoding one, else send an error page */
+        /* Dont send the user binary junk! */
+
+        err = inflateSetDictionary(&data->zstrm, (Bytef *) dictionary, strlen(dictionary));
+        if (err != Z_OK) {
+          TSError("gunzip-transform: ERROR: inflateSetDictionary (%d)!", err);
+        }
+      }
+
+      if (olength > data->zstrm.avail_out) {
+        TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
+        data->output_length += (olength - data->zstrm.avail_out);
+      }
+
+    }
+
+    /* TODO compute crc */
+
+    TSIOBufferReaderConsume(input_reader, ilength);
+    amount -= ilength;
+  }
+}
+
+
+static void
+gzip_transform_finish(GzipData * data)
+{
+  if (data->state == 1) {
+    TSIOBufferBlock blkp;
+    char *obuf;
+    int64_t olength;
+    int err;
+
+    data->state = 2;
+
+    for (;;) {
+      blkp = TSIOBufferStart(data->output_buffer);
+
+      obuf = TSIOBufferBlockWriteStart(blkp, &olength);
+      data->zstrm.next_out = (unsigned char *) obuf;
+      data->zstrm.avail_out = olength;
+
+      /* Uncompress remaining data */
+      err = inflate(&data->zstrm, Z_FINISH);
+
+      if (olength > data->zstrm.avail_out) {
+        TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
+        data->output_length += (olength - data->zstrm.avail_out);
+      }
+
+      if (err == Z_OK) {        /* more to uncompress */
+        continue;
+      }
+      /* done! */
+      break;
+    }
+
+    if (data->output_length != (data->zstrm.total_out)) {
+      TSError("gunzip-transform: ERROR: output lengths don't match (%d, %ld)", data->output_length,
+               data->zstrm.total_out);
+    }
+
+    /* TODO crc checks */
+  }
+}
+
+
+static void
+gzip_transform_do(TSCont contp)
+{
+  TSVIO write_vio;
+  GzipData *data;
+  int towrite;
+  int avail;
+  int length;
+
+  /* Get our data structure for this operation. The private data
+     structure contains the output vio and output buffer. If the
+     private data structure pointer is NULL, then we'll create it
+     and initialize its internals. */
+  data = TSContDataGet(contp);
+  if (data->state == 0) {
+    gzip_transform_init(contp, data);
+  }
+
+  /* Get the write vio for the write operation that was performed on
+     ourself. This vio contains the buffer that we are to read from
+     as well as the continuation we are to call when the buffer is
+     empty. */
+  write_vio = TSVConnWriteVIOGet(contp);
+  length = data->output_length;
+
+  /* We also check to see if the write vio's buffer is non-NULL. A
+     NULL buffer indicates that the write operation has been
+     shutdown and that the continuation does not want us to send any
+     more WRITE_READY or WRITE_COMPLETE events. For this simplistic
+     transformation that means we're done. In a more complex
+     transformation we might have to finish writing the transformed
+     data to our output connection. */
+  if (!TSVIOBufferGet(write_vio)) {
+
+    gzip_transform_finish(data);
+
+    TSVIONBytesSet(data->output_vio, data->output_length);
+
+    TSVIOReenable(data->output_vio);
+    return;
+  }
+
+  /* Determine how much data we have left to read. For this gzip
+     transform plugin this is also the amount of data we have left
+     to write to the output connection. */
+  towrite = TSVIONTodoGet(write_vio);
+  if (towrite > 0) {
+    /* The amount of data left to read needs to be truncated by
+       the amount of data actually in the read buffer. */
+    avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
+    if (towrite > avail) {
+      towrite = avail;
+    }
+
+    if (towrite > 0) {
+      gzip_transform_one(data, TSVIOReaderGet(write_vio), towrite);
+
+      /* Modify the write vio to reflect how much data we've
+         completed. */
+      TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
+    }
+  }
+
+  /* Now we check the write vio to see if there is data left to
+     read. */
+  if (TSVIONTodoGet(write_vio) > 0) {
+    if (towrite > 0) {
+      /* If we output some data then we reenable the output
+         connection by reenabling the output vio. This will wakeup
+         the output connection and allow it to consume data from the
+         output buffer. */
+      if (data->output_length > length) {
+        TSVIOReenable(data->output_vio);
+      }
+
+      /* Call back the write vio continuation to let it know that we
+         are ready for more data. */
+      TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
+    }
+  } else {
+    /* If there is no data left to read, then we modify the output
+       vio to reflect how much data the output connection should
+       expect. This allows the output connection to know when it
+       is done reading. We then reenable the output connection so
+       that it can consume the data we just gave it. */
+    gzip_transform_finish(data);
+
+    TSVIONBytesSet(data->output_vio, data->output_length);
+
+    if (data->output_length > length) {
+      TSVIOReenable(data->output_vio);
+    }
+
+    /* Call back the write vio continuation to let it know that we
+       have completed the write operation. */
+    TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
+  }
+}
+
+
+static int
+gzip_transform(TSCont contp, TSEvent event, void *edata)
+{
+  /* Check to see if the transformation has been closed by a call to
+     TSVConnClose. */
+  if (TSVConnClosedGet(contp)) {
+    gzip_data_destroy(TSContDataGet(contp));
+    TSContDestroy(contp);
+    return 0;
+  } else {
+    switch (event) {
+    case TS_EVENT_ERROR:
+      {
+        TSVIO write_vio;
+
+        /* Get the write vio for the write operation that was
+           performed on ourself. This vio contains the continuation of
+           our parent transformation. */
+        write_vio = TSVConnWriteVIOGet(contp);
+
+        /* Call back the write vio continuation to let it know that we
+           have completed the write operation. */
+        TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio);
+      }
+      break;
+    case TS_EVENT_VCONN_WRITE_COMPLETE:
+    case TS_EVENT_VCONN_EOS:
+      /* When our output connection says that it has finished
+         reading all the data we've written to it then we should
+         shutdown the write portion of its connection to
+         indicate that we don't want to hear about it anymore. */
+      TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
+      break;
+    case TS_EVENT_VCONN_WRITE_READY:
+    default:
+      /* If we get a WRITE_READY event or any other type of
+         event (sent, perhaps, because we were reenabled) then
+         we'll attempt to transform more data. */
+      gzip_transform_do(contp);
+      break;
+    }
+  }
+
+  return 0;
+}
+
+static int
+gzip_transformable(TSHttpTxn txnp, int server)
+{
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSMLoc field_loc;
+  const char *value;
+
+  if (server) {
+    TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
+  } else {
+    TSHttpTxnCachedRespGet(txnp, &bufp, &hdr_loc);
+  }
+
+  /* We only want to do gunzip(inflate) on documents that have a
+     content-encoding "deflate". */
+
+  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, "Content-Encoding", -1);
+  if (!field_loc) {
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return -4;
+  }
+
+  value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, NULL);
+  if (value && (strncasecmp(value, "deflate", sizeof("deflate") - 1) == 0)) {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return 0;
+  } else {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return -5;
+  }
+}
+
+
+static void
+gzip_transform_add(TSHttpTxn txnp, int flag)
+{
+  TSVConn connp;
+  GzipData *data;
+
+  data = gzip_data_alloc();
+  data->txn = txnp;
+
+  connp = TSTransformCreate(gzip_transform, txnp);
+  TSContDataSet(connp, data);
+  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
+}
+
+
+static int
+transform_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+  int reason;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+    {
+      TSMBuffer bufp;
+      TSMLoc hdr_loc;
+      TSMLoc ae_loc;           /* for the accept encoding mime field */
+
+      TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc);
+      TSMimeHdrFieldCreate(bufp, hdr_loc, &ae_loc); /* Probably should check for errors */
+      TSMimeHdrFieldNameSet(bufp, hdr_loc, ae_loc, "Accept-Encoding", -1);
+      TSMimeHdrFieldValueAppend(bufp, hdr_loc, ae_loc, -1, "deflate", -1);
+      TSMimeHdrFieldAppend(bufp, hdr_loc, ae_loc);
+      TSHandleMLocRelease(bufp, hdr_loc, ae_loc);
+      TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+
+      TSDebug("gunzip-transform", "Changed request header to accept deflate encoding");
+      TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+      break;
+    }
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    reason = gzip_transformable(txnp, 1);
+    if (reason >= 0) {
+      TSMBuffer bufp;
+      TSMLoc hdr_loc;
+      TSMLoc field_loc;
+
+      TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
+      field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, "Content-Encoding", -1);
+      TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc);
+      TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+
+      TSDebug("gunzip-transform", "server content transformable");
+      gzip_transform_add(txnp, 1);
+    } else {
+      TSDebug("gunzip-transform", "server content NOT transformable [%d]", reason);
+    }
+
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+
+  case TS_EVENT_HTTP_READ_CACHE_HDR:
+
+    TSDebug("gunzip-transform", "Cached data");
+
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+
+  default:
+    exit(1);
+  }
+
+  return 0;
+}
+
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  if (argc == 2) {
+    strcpy(preload_file, argv[1]);
+    preload = 1;
+    load_dictionary(dictionary, &dictId);
+  }
+
+  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(transform_plugin, NULL));
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
+  TSHttpHookAdd(TS_HTTP_READ_CACHE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
+}
diff --git a/example/gzip-transform/gzip.c b/example/gzip-transform/gzip.c
new file mode 100644
index 00000000..225e9966
--- /dev/null
+++ b/example/gzip-transform/gzip.c
@@ -0,0 +1,631 @@
+/** @file
+
+  Transforms content using gzip
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DICT_PATH_MAX 512
+#define DICT_ENTRY_MAX 2048
+
+typedef struct
+{
+  TSHttpTxn txn;
+  TSVIO output_vio;
+  TSIOBuffer output_buffer;
+  TSIOBufferReader output_reader;
+  int output_length;
+  z_stream zstrm;
+  uLong crc;
+  int state;
+} GzipData;
+
+
+char preload_file[1024];
+uLong dictId;
+int preload = 0;
+char dictionary[800000];
+
+void
+load_dictionary(char *dict, uLong * adler)
+{
+  FILE *fp;
+  int i = 0;
+
+  fp = fopen(preload_file, "r");
+  if (!fp) {
+    TSError("gzip-transform: ERROR: Unable to open dict file %s\n", preload_file);
+    exit(0);
+  }
+
+  /* dict = (char *) calloc(8000,sizeof(char)); */
+
+  i = 0;
+  while (!feof(fp)) {
+    if (fscanf(fp, "%s\n", dict + i) == 1) {
+      i = strlen(dict);
+      strcat(dict + i, " ");
+      i++;
+    }
+  }
+  dict[i - 1] = '\0';
+
+  /* TODO get the adler compute right */
+  *adler = adler32(*adler, (const Byte *) dict, sizeof(dict));
+}
+
+static voidpf
+gzip_alloc(voidpf opaque, uInt items, uInt size)
+{
+  return (voidpf) TSmalloc(items * size);
+}
+
+
+static void
+gzip_free(voidpf opaque, voidpf address)
+{
+  TSfree(address);
+}
+
+
+static GzipData *
+gzip_data_alloc()
+{
+  GzipData *data;
+  int err;
+
+  data = (GzipData *) TSmalloc(sizeof(GzipData));
+  data->output_vio = NULL;
+  data->output_buffer = NULL;
+  data->output_reader = NULL;
+  data->output_length = 0;
+  data->state = 0;
+  data->crc = crc32(0L, Z_NULL, 0);
+
+  data->zstrm.next_in = Z_NULL;
+  data->zstrm.avail_in = 0;
+  data->zstrm.total_in = 0;
+  data->zstrm.next_out = Z_NULL;
+  data->zstrm.avail_out = 0;
+  data->zstrm.total_out = 0;
+  data->zstrm.zalloc = gzip_alloc;
+  data->zstrm.zfree = gzip_free;
+  data->zstrm.opaque = (voidpf) 0;
+  data->zstrm.data_type = Z_ASCII;
+
+  err = deflateInit(&data->zstrm, Z_BEST_COMPRESSION);
+
+  if (err != Z_OK) {
+    TSError("gzip-transform: ERROR: deflateInit (%d)!", err);
+    exit(1);
+  }
+
+  if (preload) {
+    assert(&data->zstrm);
+    err = deflateSetDictionary(&data->zstrm, (const Bytef *) dictionary, strlen(dictionary));
+    if (err != Z_OK) {
+      TSError("gzip-transform: ERROR: deflateSetDictionary (%d)!", err);
+    }
+  }
+
+  return data;
+}
+
+
+static void
+gzip_data_destroy(GzipData * data)
+{
+  int err;
+
+  if (data) {
+    err = deflateEnd(&data->zstrm);
+    if (err != Z_OK) {
+      TSError("gzip-transform: ERROR: deflateEnd (%d)!", err);
+    }
+
+    if (data->output_buffer)
+      TSIOBufferDestroy(data->output_buffer);
+    TSfree(data);
+  }
+}
+
+
+static void
+gzip_transform_init(TSCont contp, GzipData * data)
+{
+  TSVConn output_conn;
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSMLoc ce_loc;               /* for the content encoding mime field */
+
+  data->state = 1;
+
+  /*
+   * Mark the output data as having gzip content encoding
+   */
+  TSHttpTxnTransformRespGet(data->txn, &bufp, &hdr_loc);
+  TSMimeHdrFieldCreate(bufp, hdr_loc, &ce_loc); /* Probably should check for errors */
+  TSMimeHdrFieldNameSet(bufp, hdr_loc, ce_loc, "Content-Encoding", -1);
+  TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, ce_loc, -1, "deflate", -1);
+  TSMimeHdrFieldAppend(bufp, hdr_loc, ce_loc);
+  TSHandleMLocRelease(bufp, hdr_loc, ce_loc);
+  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+
+
+  /* Get the output connection where we'll write data to. */
+  output_conn = TSTransformOutputVConnGet(contp);
+
+  data->output_buffer = TSIOBufferCreate();
+  data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
+  data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
+}
+
+
+static void
+gzip_transform_one(GzipData * data, TSIOBufferReader input_reader, int amount)
+{
+  TSIOBufferBlock blkp;
+  const char *ibuf;
+  char *obuf;
+  int64_t ilength, olength;
+  int err;
+
+  while (amount > 0) {
+    blkp = TSIOBufferReaderStart(input_reader);
+    ibuf = TSIOBufferBlockReadStart(blkp, input_reader, &ilength);
+
+    if (ilength > amount) {
+      ilength = amount;
+    }
+
+    data->zstrm.next_in = (unsigned char *) ibuf;
+    data->zstrm.avail_in = ilength;
+
+    while (data->zstrm.avail_in > 0) {
+      blkp = TSIOBufferStart(data->output_buffer);
+
+      obuf = TSIOBufferBlockWriteStart(blkp, &olength);
+
+      data->zstrm.next_out = (unsigned char *) obuf;
+      data->zstrm.avail_out = olength;
+
+      /* Encode */
+      err = deflate(&data->zstrm, Z_NO_FLUSH);
+
+      if (olength > data->zstrm.avail_out) {
+        TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
+        data->output_length += (olength - data->zstrm.avail_out);
+      }
+
+      if (data->zstrm.avail_out > 0) {
+        if (data->zstrm.avail_in != 0) {
+          TSError("gzip-transform: ERROR: avail_in is (%d): should be 0", data->zstrm.avail_in);
+        }
+      }
+    }
+
+    /* compute CRC for error checking at client */
+    data->crc = crc32(data->crc, (unsigned char *) ibuf, ilength);
+
+    TSIOBufferReaderConsume(input_reader, ilength);
+    amount -= ilength;
+  }
+}
+
+
+static void
+gzip_transform_finish(GzipData * data)
+{
+  if (data->state == 1) {
+    TSIOBufferBlock blkp;
+    char *obuf;
+    int64_t olength;
+    int err;
+
+    data->state = 2;
+
+    for (;;) {
+      blkp = TSIOBufferStart(data->output_buffer);
+
+      obuf = TSIOBufferBlockWriteStart(blkp, &olength);
+      data->zstrm.next_out = (unsigned char *) obuf;
+      data->zstrm.avail_out = olength;
+
+      /* Encode remaining data */
+      err = deflate(&data->zstrm, Z_FINISH);
+
+      if (olength > data->zstrm.avail_out) {
+        TSIOBufferProduce(data->output_buffer, olength - data->zstrm.avail_out);
+        data->output_length += (olength - data->zstrm.avail_out);
+      }
+
+      if (err == Z_OK) {        /* some more data to encode */
+        continue;
+      }
+      /* done! */
+      if (err != Z_STREAM_END) {
+        TSDebug("gzip-transform", "deflate should report Z_STREAM_END\n");
+      }
+      break;
+    }
+
+    if (data->output_length != (data->zstrm.total_out)) {
+      TSError("gzip-transform: ERROR: output lengths don't match (%d, %ld)", data->output_length,
+               data->zstrm.total_out);
+    }
+
+    /* compute/append crc to end of stream */
+
+    /*
+       blkp = TSIOBufferStart (data->output_buffer);
+
+       tmp = data->crc;
+       buf[0] = tmp & 0xff; tmp >>= 8;
+       buf[1] = tmp & 0xff; tmp >>= 8;
+       buf[2] = tmp & 0xff; tmp >>= 8;
+       buf[3] = tmp & 0xff;
+
+       tmp = data->zstrm.total_in;
+       buf[4] = tmp & 0xff; tmp >>= 8;
+       buf[5] = tmp & 0xff; tmp >>= 8;
+       buf[6] = tmp & 0xff; tmp >>= 8;
+       buf[7] = tmp & 0xff;
+
+       p = buf;
+       length = 8;
+
+       while (length > 0) {
+       obuf = TSIOBufferBlockWriteStart (blkp, &olength);
+       if (olength > length) {
+       olength = length;
+       }
+
+       memcpy (obuf, p, olength);
+       p += olength;
+       length -= olength;
+
+       TSIOBufferProduce (data->output_buffer, olength);
+       }
+
+       data->output_length += 8;
+     */
+  }
+}
+
+
+static void
+gzip_transform_do(TSCont contp)
+{
+  TSVIO write_vio;
+  GzipData *data;
+  int towrite;
+  int avail;
+  int length;
+
+  /* Get our data structure for this operation. The private data
+     structure contains the output vio and output buffer. If the
+     private data structure pointer is NULL, then we'll create it
+     and initialize its internals. */
+  data = TSContDataGet(contp);
+  if (data->state == 0) {
+    gzip_transform_init(contp, data);
+  }
+
+  /* Get the write vio for the write operation that was performed on
+     ourself. This vio contains the buffer that we are to read from
+     as well as the continuation we are to call when the buffer is
+     empty. */
+  write_vio = TSVConnWriteVIOGet(contp);
+
+  length = data->output_length;
+
+  /* We also check to see if the write vio's buffer is non-NULL. A
+     NULL buffer indicates that the write operation has been
+     shutdown and that the continuation does not want us to send any
+     more WRITE_READY or WRITE_COMPLETE events. For this simplistic
+     transformation that means we're done. In a more complex
+     transformation we might have to finish writing the transformed
+     data to our output connection. */
+  if (!TSVIOBufferGet(write_vio)) {
+    gzip_transform_finish(data);
+
+    TSVIONBytesSet(data->output_vio, data->output_length);
+    TSDebug("gzip-transform", "Compressed size %d (bytes)", data->output_length);
+
+    if (data->output_length > length) {
+      TSVIOReenable(data->output_vio);
+    }
+    return;
+  }
+
+  /* Determine how much data we have left to read. For this gzip
+     transform plugin this is also the amount of data we have left
+     to write to the output connection. */
+  towrite = TSVIONTodoGet(write_vio);
+  if (towrite > 0) {
+    /* The amount of data left to read needs to be truncated by
+       the amount of data actually in the read buffer. */
+    avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
+    if (towrite > avail) {
+      towrite = avail;
+    }
+
+    if (towrite > 0) {
+      gzip_transform_one(data, TSVIOReaderGet(write_vio), towrite);
+
+      /* Modify the write vio to reflect how much data we've
+         completed. */
+      TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
+    }
+  }
+
+  /* Now we check the write vio to see if there is data left to
+     read. */
+  if (TSVIONTodoGet(write_vio) > 0) {
+    if (towrite > 0) {
+      /* If we output some data then we reenable the output
+         connection by reenabling the output vio. This will wakeup
+         the output connection and allow it to consume data from the
+         output buffer. */
+      if (data->output_length > length) {
+        TSVIOReenable(data->output_vio);
+      }
+
+      /* Call back the write vio continuation to let it know that we
+         are ready for more data. */
+      TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
+    }
+  } else {
+    /* If there is no data left to read, then we modify the output
+       vio to reflect how much data the output connection should
+       expect. This allows the output connection to know when it
+       is done reading. We then reenable the output connection so
+       that it can consume the data we just gave it. */
+    gzip_transform_finish(data);
+
+    TSVIONBytesSet(data->output_vio, data->output_length);
+    TSDebug("gzip-transform", "Compressed size %d (bytes)", data->output_length);
+
+    if (data->output_length > length) {
+      TSVIOReenable(data->output_vio);
+    }
+
+    /* Call back the write vio continuation to let it know that we
+       have completed the write operation. */
+    TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
+  }
+}
+
+
+static int
+gzip_transform(TSCont contp, TSEvent event, void *edata)
+{
+  /* Check to see if the transformation has been closed by a call to
+     TSVConnClose. */
+  if (TSVConnClosedGet(contp)) {
+    gzip_data_destroy(TSContDataGet(contp));
+    TSContDestroy(contp);
+    return 0;
+  } else {
+    switch (event) {
+    case TS_EVENT_ERROR:
+      {
+        TSVIO write_vio;
+
+        /* Get the write vio for the write operation that was
+           performed on ourself. This vio contains the continuation of
+           our parent transformation. */
+        write_vio = TSVConnWriteVIOGet(contp);
+
+        /* Call back the write vio continuation to let it know that we
+           have completed the write operation. */
+        TSContCall(TSVIOContGet(write_vio), TS_EVENT_ERROR, write_vio);
+      }
+      break;
+    case TS_EVENT_VCONN_WRITE_COMPLETE:
+      /* When our output connection says that it has finished
+         reading all the data we've written to it then we should
+         shutdown the write portion of its connection to
+         indicate that we don't want to hear about it anymore. */
+      TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
+      break;
+    case TS_EVENT_VCONN_WRITE_READY:
+    default:
+      /* If we get a WRITE_READY event or any other type of
+         event (sent, perhaps, because we were reenabled) then
+         we'll attempt to transform more data. */
+      gzip_transform_do(contp);
+      break;
+    }
+  }
+
+  return 0;
+}
+
+
+static int
+gzip_transformable(TSHttpTxn txnp, int server)
+{
+  /* Server response header */
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSMLoc field_loc;
+
+  /* Client request header */
+  TSMBuffer cbuf;
+  TSMLoc chdr;
+  TSMLoc cfield;
+
+  const char *value;
+  int nvalues;
+  int i, deflate_flag;
+
+  TSHttpTxnClientReqGet(txnp, &cbuf, &chdr);
+
+  /* check if client accepts "deflate" */
+
+  cfield = TSMimeHdrFieldFind(cbuf, chdr, TS_MIME_FIELD_ACCEPT_ENCODING, -1);
+  if (TS_NULL_MLOC != cfield) {
+    nvalues = TSMimeHdrFieldValuesCount(cbuf, chdr, cfield);
+    value = TSMimeHdrFieldValueStringGet(cbuf, chdr, cfield, 0, NULL);
+    deflate_flag = 0;
+    i = 0;
+    while (nvalues > 0) {
+      if (value && (strncasecmp(value, "deflate", sizeof("deflate") - 1) == 0)) {
+        deflate_flag = 1;
+        break;
+      }
+      i++;
+      value = TSMimeHdrFieldValueStringGet(cbuf, chdr, cfield, i, NULL);
+      nvalues--;
+    }
+    if (!deflate_flag) {
+      return -7;
+    }
+    TSHandleMLocRelease(cbuf, chdr, cfield);
+    TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr);
+  } else {
+    TSHandleMLocRelease(cbuf, chdr, cfield);
+    TSHandleMLocRelease(cbuf, TS_NULL_MLOC, chdr);
+    return -6;
+  }
+
+  if (server) {
+    TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
+  } else {
+    TSHttpTxnCachedRespGet(txnp, &bufp, &hdr_loc);
+  }
+
+  /* If there already exists a content encoding then we don't want
+     to do anything. */
+  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_ENCODING, -1);
+  if (field_loc) {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return -3;
+  }
+  TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+
+  /* We only want to do gzip compression on documents that have a
+     content type of "text/" or "application/x-javascript". */
+
+  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_TYPE, -1);
+  if (!field_loc) {
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return -4;
+  }
+
+  value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, NULL);
+  if (value && (strncasecmp(value, "text/", sizeof("text/") - 1) == 0)) {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return 0;
+  } else if (value && (strncasecmp(value, "application/x-javascript", (sizeof("application/x-javascript") - 1)) == 0)) {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return 0;
+  } else {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return -5;
+  }
+}
+
+
+static void
+gzip_transform_add(TSHttpTxn txnp, int server)
+{
+  TSVConn connp;
+  GzipData *data;
+
+  connp = TSTransformCreate(gzip_transform, txnp);
+
+  data = gzip_data_alloc();
+  data->txn = txnp;
+  TSContDataSet(connp, data);
+
+  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
+}
+
+
+static int
+transform_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+  int reason;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    reason = gzip_transformable(txnp, 1);
+    if (reason >= 0) {
+      TSDebug("gzip-transform", "server content transformable");
+      gzip_transform_add(txnp, 1);
+    } else {
+      TSDebug("gzip-transform", "server content NOT transformable [%d]", reason);
+    }
+
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+
+  case TS_EVENT_HTTP_READ_CACHE_HDR:
+
+    reason = gzip_transformable(txnp, 0);
+    if (reason >= 0) {
+      TSDebug("gzip-transform", "cached content transformable");
+      gzip_transform_add(txnp, 1);
+    } else {
+      TSDebug("gzip-transform", "cached data:  forwarding unchanged (%d)", reason);
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+
+  default:
+    exit(1);
+  }
+
+  return 0;
+}
+
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  dictId = adler32(0L, Z_NULL, 0);
+  if (argc == 2) {
+    strcpy(preload_file, argv[1]);
+    preload = 1;
+    load_dictionary(dictionary, &dictId);
+  }
+
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
+  TSHttpHookAdd(TS_HTTP_READ_CACHE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
+}
+
diff --git a/example/hello/Makefile.am b/example/hello/Makefile.am
new file mode 100644
index 00000000..ea0294f5
--- /dev/null
+++ b/example/hello/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = hello.la
+hello_la_SOURCES = hello.c
+hello_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/hello.so
diff --git a/example/hello/Makefile.in b/example/hello/Makefile.in
new file mode 100644
index 00000000..a6a889a9
--- /dev/null
+++ b/example/hello/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/hello
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+hello_la_LIBADD =
+am_hello_la_OBJECTS = hello.lo
+hello_la_OBJECTS = $(am_hello_la_OBJECTS)
+hello_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(hello_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(hello_la_SOURCES)
+DIST_SOURCES = $(hello_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = hello.la
+hello_la_SOURCES = hello.c
+hello_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/hello/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/hello/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+hello.la: $(hello_la_OBJECTS) $(hello_la_DEPENDENCIES) 
+	$(hello_la_LINK) -rpath $(pkglibdir) $(hello_la_OBJECTS) $(hello_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hello.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/hello.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/hello/hello.c b/example/hello/hello.c
new file mode 100644
index 00000000..8e44bc90
--- /dev/null
+++ b/example/hello/hello.c
@@ -0,0 +1,71 @@
+/** @file
+
+  an example hello world plugin
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include 
+#include 
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "hello-world";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed. \n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  TSDebug("debug-hello", "Hello World!\n");
+}
diff --git a/example/include_other/macro.h b/example/include_other/macro.h
new file mode 100644
index 00000000..6c0a2dd0
--- /dev/null
+++ b/example/include_other/macro.h
@@ -0,0 +1,75 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#ifndef _MACRO_H_
+#define _MACRO_H_
+
+#define LOG_SET_FUNCTION_NAME(NAME) const char * FUNCTION_NAME = NAME
+
+#define LOG_AUTO_ERROR(API_NAME, COMMENT) \
+{ \
+    TSDebug(PLUGIN_NAME, "%s %s [%s: line %d] (%s)", API_NAME, "AUTO_FAIL", \
+            FUNCTION_NAME, __LINE__, COMMENT); \
+}
+#define LOG_API_ERROR(API_NAME) { \
+    TSDebug(DEBUG_TAG, "%s: %s %s [%s] File %s, line number %d", PLUGIN_NAME, API_NAME, "APIFAIL", \
+	     FUNCTION_NAME, __FILE__, __LINE__); \
+}
+
+#define LOG_API_ERROR_COMMENT(API_NAME, COMMENT) { \
+    TSDebug(DEBUG_TAG, "%s: %s %s [%s] File %s, line number %d (%s)", PLUGIN_NAME, API_NAME, "APIFAIL", \
+	     FUNCTION_NAME, __FILE__, __LINE__, COMMENT); \
+}
+
+#define LOG_ERROR_AND_RETURN(API_NAME) \
+{ \
+    LOG_API_ERROR(API_NAME); \
+    return -1; \
+}
+#define LOG_ERROR_AND_CLEANUP(API_NAME) \
+{ \
+    LOG_API_ERROR(API_NAME); \
+    goto done; \
+}
+#define LOG_ERROR_AND_REENABLE(API_NAME) \
+{ \
+    LOG_API_ERROR(API_NAME); \
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); \
+}
+
+/* added by nkale for internal plugins */
+#define LOG_NEG_ERROR(API_NAME) { \
+    TSDebug(NEG_ERROR_TAG, "%s: %s %s %s File %s, line number %d",PLUGIN_NAME, API_NAME, "NEGAPIFAIL", \
+             FUNCTION_NAME, __FILE__, __LINE__); \
+}
+
+/* Release macros */
+#define VALID_PTR(X) (X != NULL))
+
+#define FREE(X) \
+{ \
+    if (VALID_PTR(X)) { \
+        TSfree((void *)X); \
+        X = NULL; \
+    } \
+} \
diff --git a/example/null-transform/Makefile.am b/example/null-transform/Makefile.am
new file mode 100644
index 00000000..56bb3388
--- /dev/null
+++ b/example/null-transform/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = null-transform.la
+null_transform_la_SOURCES = null-transform.c
+null_transform_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/null-transform.so
diff --git a/example/null-transform/Makefile.in b/example/null-transform/Makefile.in
new file mode 100644
index 00000000..abc7f535
--- /dev/null
+++ b/example/null-transform/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/null-transform
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+null_transform_la_LIBADD =
+am_null_transform_la_OBJECTS = null-transform.lo
+null_transform_la_OBJECTS = $(am_null_transform_la_OBJECTS)
+null_transform_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(null_transform_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(null_transform_la_SOURCES)
+DIST_SOURCES = $(null_transform_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = null-transform.la
+null_transform_la_SOURCES = null-transform.c
+null_transform_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/null-transform/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/null-transform/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+null-transform.la: $(null_transform_la_OBJECTS) $(null_transform_la_DEPENDENCIES) 
+	$(null_transform_la_LINK) -rpath $(pkglibdir) $(null_transform_la_OBJECTS) $(null_transform_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/null-transform.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/null-transform.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/null-transform/null-transform.c b/example/null-transform/null-transform.c
new file mode 100644
index 00000000..cc7897a9
--- /dev/null
+++ b/example/null-transform/null-transform.c
@@ -0,0 +1,362 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* null-transform.c:  an example program that does a null transform
+ *                    of response body content
+ *
+ *
+ *
+ *	Usage:
+ * 	(NT): NullTransform.dll
+ *	(Solaris): null-transform.so
+ *
+ *
+ */
+
+#include 
+#include 
+#include 
+
+// This gets the PRI*64 types
+# define __STDC_FORMAT_MACROS 1
+# include 
+
+typedef struct
+{
+  TSVIO output_vio;
+  TSIOBuffer output_buffer;
+  TSIOBufferReader output_reader;
+} MyData;
+
+static MyData *
+my_data_alloc()
+{
+  MyData *data;
+
+  data = (MyData *) TSmalloc(sizeof(MyData));
+  data->output_vio = NULL;
+  data->output_buffer = NULL;
+  data->output_reader = NULL;
+
+  return data;
+}
+
+static void
+my_data_destroy(MyData * data)
+{
+  if (data) {
+    if (data->output_buffer)
+      TSIOBufferDestroy(data->output_buffer);
+    TSfree(data);
+  }
+}
+
+static void
+handle_transform(TSCont contp)
+{
+  TSVConn output_conn;
+  TSIOBuffer buf_test;
+  TSVIO input_vio;
+  MyData *data;
+  int64_t towrite;
+  int64_t avail;
+
+  TSDebug("null-transform", "Entering handle_transform()");
+  /* Get the output (downstream) vconnection where we'll write data to. */
+
+  output_conn = TSTransformOutputVConnGet(contp);
+
+  /* Get the write VIO for the write operation that was performed on
+   * ourself. This VIO contains the buffer that we are to read from
+   * as well as the continuation we are to call when the buffer is
+   * empty. This is the input VIO (the write VIO for the upstream
+   * vconnection).
+   */
+  input_vio = TSVConnWriteVIOGet(contp);
+
+  /* Get our data structure for this operation. The private data
+   * structure contains the output VIO and output buffer. If the
+   * private data structure pointer is NULL, then we'll create it
+   * and initialize its internals.
+   */
+  data = TSContDataGet(contp);
+  if (!data) {
+    data = my_data_alloc();
+    data->output_buffer = TSIOBufferCreate();
+    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
+    TSDebug("null-transform", "\tWriting %d bytes on VConn", TSVIONBytesGet(input_vio));
+    //data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT32_MAX);
+    data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
+    // data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, TSVIONBytesGet(input_vio));
+    TSContDataSet(contp, data);
+  }
+
+  /* We also check to see if the input VIO's buffer is non-NULL. A
+   * NULL buffer indicates that the write operation has been
+   * shutdown and that the upstream continuation does not want us to send any
+   * more WRITE_READY or WRITE_COMPLETE events. For this simplistic
+   * transformation that means we're done. In a more complex
+   * transformation we might have to finish writing the transformed
+   * data to our output connection.
+   */
+  buf_test = TSVIOBufferGet(input_vio);
+
+  if (!buf_test) {
+    TSVIONBytesSet(data->output_vio, TSVIONDoneGet(input_vio));
+    TSVIOReenable(data->output_vio);
+    return;
+  }
+
+  /* Determine how much data we have left to read. For this null
+   * transform plugin this is also the amount of data we have left
+   * to write to the output connection.
+   */
+  towrite = TSVIONTodoGet(input_vio);
+  TSDebug("null-transform", "\ttoWrite is %" PRId64 "", towrite);
+
+  if (towrite > 0) {
+    /* The amount of data left to read needs to be truncated by
+     * the amount of data actually in the read buffer.
+     */
+    avail = TSIOBufferReaderAvail(TSVIOReaderGet(input_vio));
+    TSDebug("null-transform", "\tavail is %" PRId64 "", avail);
+    if (towrite > avail) {
+      towrite = avail;
+    }
+
+    if (towrite > 0) {
+      /* Copy the data from the read buffer to the output buffer. */
+      TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(input_vio), towrite, 0);
+
+      /* Tell the read buffer that we have read the data and are no
+       * longer interested in it.
+       */
+      TSIOBufferReaderConsume(TSVIOReaderGet(input_vio), towrite);
+
+      /* Modify the input VIO to reflect how much data we've
+       * completed.
+       */
+      TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + towrite);
+    }
+  }
+
+  /* Now we check the input VIO to see if there is data left to
+   * read.
+   */
+  if (TSVIONTodoGet(input_vio) > 0) {
+    if (towrite > 0) {
+      /* If there is data left to read, then we reenable the output
+       * connection by reenabling the output VIO. This will wake up
+       * the output connection and allow it to consume data from the
+       * output buffer.
+       */
+      TSVIOReenable(data->output_vio);
+
+      /* Call back the input VIO continuation to let it know that we
+       * are ready for more data.
+       */
+      TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
+    }
+  } else {
+    /* If there is no data left to read, then we modify the output
+     * VIO to reflect how much data the output connection should
+     * expect. This allows the output connection to know when it
+     * is done reading. We then reenable the output connection so
+     * that it can consume the data we just gave it.
+     */
+    TSVIONBytesSet(data->output_vio, TSVIONDoneGet(input_vio));
+    TSVIOReenable(data->output_vio);
+
+    /* Call back the input VIO continuation to let it know that we
+     * have completed the write operation.
+     */
+    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
+  }
+}
+
+static int
+null_transform(TSCont contp, TSEvent event, void *edata)
+{
+  /* Check to see if the transformation has been closed by a call to
+   * TSVConnClose.
+   */
+  TSDebug("null-transform", "Entering null_transform()");
+
+  if (TSVConnClosedGet(contp)) {
+    TSDebug("null-transform", "\tVConn is closed");
+    my_data_destroy(TSContDataGet(contp));
+    TSContDestroy(contp);
+    return 0;
+  } else {
+    switch (event) {
+    case TS_EVENT_ERROR:
+      {
+        TSVIO input_vio;
+
+        TSDebug("null-transform", "\tEvent is TS_EVENT_ERROR");
+        /* Get the write VIO for the write operation that was
+         * performed on ourself. This VIO contains the continuation of
+         * our parent transformation. This is the input VIO.
+         */
+        input_vio = TSVConnWriteVIOGet(contp);
+
+        /* Call back the write VIO continuation to let it know that we
+         * have completed the write operation.
+         */
+        TSContCall(TSVIOContGet(input_vio), TS_EVENT_ERROR, input_vio);
+      }
+      break;
+    case TS_EVENT_VCONN_WRITE_COMPLETE:
+      TSDebug("null-transform", "\tEvent is TS_EVENT_VCONN_WRITE_COMPLETE");
+      /* When our output connection says that it has finished
+       * reading all the data we've written to it then we should
+       * shutdown the write portion of its connection to
+       * indicate that we don't want to hear about it anymore.
+       */
+      TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
+      break;
+    case TS_EVENT_VCONN_WRITE_READY:
+      TSDebug("null-transform", "\tEvent is TS_EVENT_VCONN_WRITE_READY");
+    default:
+      TSDebug("null-transform", "\t(event is %d)", event);
+      /* If we get a WRITE_READY event or any other type of
+       * event (sent, perhaps, because we were reenabled) then
+       * we'll attempt to transform more data.
+       */
+      handle_transform(contp);
+      break;
+    }
+  }
+
+  return 0;
+}
+
+static int
+transformable(TSHttpTxn txnp)
+{
+  /*
+   *  We are only interested in transforming "200 OK" responses.
+   */
+
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSHttpStatus resp_status;
+  int retv;
+
+  TSDebug("null-transform", "Entering transformable()");
+
+  TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
+  resp_status = TSHttpHdrStatusGet(bufp, hdr_loc);
+  retv = (resp_status == TS_HTTP_STATUS_OK);
+
+  if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) == TS_ERROR) {
+    TSError("[null-transform] Error releasing MLOC while checking " "header status\n");
+  }
+
+  TSDebug("null-transform", "Exiting transformable with return %d", retv);
+  return retv;
+}
+
+static void
+transform_add(TSHttpTxn txnp)
+{
+  TSVConn connp;
+
+  TSDebug("null-transform", "Entering transform_add()");
+  connp = TSTransformCreate(null_transform, txnp);
+  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, connp);
+}
+
+static int
+transform_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  TSDebug("null-transform", "Entering transform_plugin()");
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    TSDebug("null-transform", "\tEvent is TS_EVENT_HTTP_READ_RESPONSE_HDR");
+    if (transformable(txnp)) {
+      transform_add(txnp);
+    }
+
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    return 0;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "null-transform";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("[null-transform] Plugin registration failed.\n");
+    goto Lerror;
+  }
+
+  if (!check_ts_version()) {
+    TSError("[null-transform] Plugin requires Traffic Server 3.0 " "or later\n");
+    goto Lerror;
+  }
+
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(transform_plugin, NULL));
+  return;
+
+Lerror:
+  TSError("[null-tranform] Unable to initialize plugin (disabled).\n");
+}
diff --git a/example/null-transform/readme.txt b/example/null-transform/readme.txt
new file mode 100644
index 00000000..c22446a5
--- /dev/null
+++ b/example/null-transform/readme.txt
@@ -0,0 +1,112 @@
+The null-transform.c plugin performs a null transformation
+on response content. 
+
+The plugin is called each time Traffic Server reads an HTTP 
+response header.
+
+  --  The TSPluginInit function has a global hook
+      set up for the READ RESPONSE HDR event.
+
+This plugin follows the default behavior for transforms: 
+transformed content is cached. Therefore the transformation 
+of the response need happen only once, when the content is
+received from the origin server. To make sure this happens,
+the plugin checks for a "200 OK" server response header
+before transforming. 
+
+  -- This check is done in the subroutine called "transformable". 
+
+If the response is transformable, the plugin creates a 
+transformation, and adds it to the response transform
+hook. 
+
+  -- This is done in "transform_add" using 
+     TSTransformCreate and TSHttpTxnHookAdd.
+
+  -- The handler function for the transformation is
+     null_transform.
+
+When it is time to transform the response data, the 
+null_transform function is called. 
+
+The transformation acts as a one-way data pipe: response
+data comes in from an upstream vconnection (which could be
+an HTTP state machine or itself another transformation) and
+goes out to the downstream vconnection, whatever that might
+be. The transformation has to:
+
+(a)  Write transformed data to the downstream vconnection. 
+
+(b)  Copy data from the upstream vconnection's output buffer
+     to the downstream vconnection's input buffer. 
+
+(c)  Clean up when the transformation is complete (either if
+     it stopped because of an error or it finished transforming).
+
+Here is how this is implemented: the null_transform function
+(the transformation's handler function) first checks to make
+sure the transformation has not been closed (null_transform
+destroys itself if it finds out the transformation has been 
+closed). Then null_transform has a switch statement that 
+handles the following events: 
+
+  -- TS_EVENT_ERROR: if there is an error, null_transform
+     lets the downstream vconnection know that the write
+     operation is terminated (the downstream vconnection
+     should not expect any more data). 
+
+  -- TS_EVENT_VCONN_WRITE_COMPLETE: the downstream vconnection
+     has read all the data written to it. null_transform 
+     shuts down the write portion of the downstream vconnection,
+     meaning that the transformation does not want any more 
+     WRITE events from the downstream vconnection. 
+
+  -- TS_EVENT_VCONN_WRITE_READY: null_transform calls 
+     handle_transform to transform data.
+
+  -- All other events: call handle_transform. 
+
+In the handle_transform function, the transformation vconnection
+takes the role of the "vconnection user" (see the SDK Programmer's
+Guide).  
+
+handle_transform needs to initiate the transformation by a call
+to TSVConnWrite on the output vconnection. To do this, handle_transform
+has to:
+
+ -- get the output vconnection using TSTransformOutputVConnGet
+
+ -- get the input vio using TSVConnWriteVIOGet (the input vio
+    contains the total number of bytes to be written, and keeps
+    track of the number of bytes that the upstream vconnection
+    has written to the input buffer. When the transformation has
+    consumed data from the input buffer, it has to modify the 
+    input vio.)
+
+After calling TSVConnWrite, the transformation can expect to 
+receive WRITE_READY and WRITE_COMPLETE events from the downstream
+vconnection. 
+
+If there is data to read, handle_transform copies it over using
+TSIOBufferCopy. When done with the buffer, it calls
+TSIOBufferReaderConsume. If there is more data to read (than one
+buffer's worth), two things happen:
+
+ -- handle_transform wakes up the downstream vconnection using
+    TSVIOReenable
+
+ -- handle_transform wakes up the upstream vconnection, asking it
+    for more data, by using TSContCall and sending it a 
+    WRITE_READY event
+
+If there is no more data to read, handle_transform informs the 
+downstream vconnection using TSVIONBytesSet and TSVIOReenable.
+Then handle_transform sends the upstream vconnection the
+WRITE_COMPLETE event using TSContCall. 
+
+This is how the transformation receives the WRITE_COMPLETE event:
+when the downstream vconnection learns through the downstream
+(output) vio that there is no more data left to read (nbytes=ndone),
+the downstream vconnection sends WRITE_COMPLETE upstream.  
+
+
diff --git a/example/output-header/Makefile.am b/example/output-header/Makefile.am
new file mode 100644
index 00000000..a9421645
--- /dev/null
+++ b/example/output-header/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = output-header.la
+output_header_la_SOURCES = output-header.c
+output_header_la_LDFLAGS =  -module -avoid-version -shared
+
+all:
+	ln -sf .libs/output-header.so
diff --git a/example/output-header/Makefile.in b/example/output-header/Makefile.in
new file mode 100644
index 00000000..7c522460
--- /dev/null
+++ b/example/output-header/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/output-header
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+output_header_la_LIBADD =
+am_output_header_la_OBJECTS = output-header.lo
+output_header_la_OBJECTS = $(am_output_header_la_OBJECTS)
+output_header_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(output_header_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(output_header_la_SOURCES)
+DIST_SOURCES = $(output_header_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = output-header.la
+output_header_la_SOURCES = output-header.c
+output_header_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/output-header/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/output-header/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+output-header.la: $(output_header_la_OBJECTS) $(output_header_la_DEPENDENCIES) 
+	$(output_header_la_LINK) -rpath $(pkglibdir) $(output_header_la_OBJECTS) $(output_header_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output-header.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/output-header.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/output-header/output-header.c b/example/output-header/output-header.c
new file mode 100644
index 00000000..c2601048
--- /dev/null
+++ b/example/output-header/output-header.c
@@ -0,0 +1,208 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* output_hdr.c: a plugin prints out the client request header
+ *                 fields to stdout
+ * A sample internal plugin to use the HdrPrint functions and the TSIOBuffers
+ * that the functions untilize.
+ *
+ * The plugin simply prints all the incoming request headers
+ *
+ *
+ *
+ *   Note: tested on Solaris only.  Probably doesn't compile
+ *    on NT.
+ */
+
+#include 
+#include 
+
+#if !defined (_WIN32)
+#include 
+#else
+#include 
+#endif
+
+#include 
+
+#define DEBUG_TAG "output-header"
+
+static void
+handle_dns(TSHttpTxn txnp, TSCont contp)
+{
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+
+  TSIOBuffer output_buffer;
+  TSIOBufferReader reader;
+  int total_avail;
+
+  TSIOBufferBlock block;
+  const char *block_start;
+  int64_t block_avail;
+
+  char *output_string;
+  int64_t output_len;
+
+  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+    TSDebug(DEBUG_TAG, "couldn't retrieve client request header");
+    TSError("couldn't retrieve client request header\n");
+    goto done;
+  }
+
+  output_buffer = TSIOBufferCreate();
+  reader = TSIOBufferReaderAlloc(output_buffer);
+
+  /* This will print  just MIMEFields and not
+     the http request line */
+  TSDebug(DEBUG_TAG, "Printing the hdrs ... ");
+  TSMimeHdrPrint(bufp, hdr_loc, output_buffer);
+
+  if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) == TS_ERROR) {
+    TSDebug(DEBUG_TAG, "non-fatal: error releasing MLoc");
+    TSError("non-fatal: error releasing MLoc\n");
+  }
+
+  /* Find out how the big the complete header is by
+     seeing the total bytes in the buffer.  We need to
+     look at the buffer rather than the first block to
+     see the size of the entire header */
+  total_avail = TSIOBufferReaderAvail(reader);
+
+  /* Allocate the string with an extra byte for the string
+     terminator */
+  output_string = (char *) TSmalloc(total_avail + 1);
+  output_len = 0;
+
+  /* We need to loop over all the buffer blocks to make
+     sure we get the complete header since the header can
+     be in multiple blocks */
+  block = TSIOBufferReaderStart(reader);
+  while (block) {
+    block_start = TSIOBufferBlockReadStart(block, reader, &block_avail);
+
+    /* We'll get a block pointer back even if there is no data
+       left to read so check for this condition and break out of
+       the loop. A block with no data to read means we've exhausted
+       buffer of data since if there was more data on a later
+       block in the chain, this block would have been skipped over */
+    if (block_avail == 0) {
+      break;
+    }
+
+    memcpy(output_string + output_len, block_start, block_avail);
+    output_len += block_avail;
+
+    /* Consume the data so that we get to the next block */
+    TSIOBufferReaderConsume(reader, block_avail);
+
+    /* Get the next block now that we've consumed the
+       data off the last block */
+    block = TSIOBufferReaderStart(reader);
+  }
+
+  /* Terminate the string */
+  output_string[output_len] = '\0';
+  output_len++;
+
+  /* Free up the TSIOBuffer that we used to print out the header */
+  TSIOBufferReaderFree(reader);
+  TSIOBufferDestroy(output_buffer);
+
+  /* Although I'd never do this a production plugin, printf
+     the header so that we can see it's all there */
+  TSDebug("debug-output-header", "%s", output_string);
+
+  TSfree(output_string);
+
+done:
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+}
+
+static int
+hdr_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_OS_DNS:
+    handle_dns(txnp, contp);
+    return 0;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "output-header";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("[PluginInit] Plugin registration failed.\n");
+    goto error;
+  }
+
+  if (!check_ts_version()) {
+    TSError("[PluginInit] Plugin requires Traffic Server 3.0 or later\n");
+    goto error;
+  }
+
+
+  TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(hdr_plugin, NULL));
+
+error:
+  TSError("[PluginInit] Plugin not initialized");
+}
+
diff --git a/example/output-header/readme b/example/output-header/readme
new file mode 100644
index 00000000..96ee2329
--- /dev/null
+++ b/example/output-header/readme
@@ -0,0 +1,5 @@
+A sample internal plugin to use the HdrPrint functions and the TSIOBuffers 
+that the functions untilize.  
+
+The plugin simply prints all the incoming request headers
+
diff --git a/example/prefetch/Makefile.am b/example/prefetch/Makefile.am
new file mode 100644
index 00000000..143e2bb1
--- /dev/null
+++ b/example/prefetch/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = prefetch.la
+prefetch_la_SOURCES = prefetch.c
+prefetch_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/prefetch.so
diff --git a/example/prefetch/Makefile.in b/example/prefetch/Makefile.in
new file mode 100644
index 00000000..c3b8f63e
--- /dev/null
+++ b/example/prefetch/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/prefetch
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+prefetch_la_LIBADD =
+am_prefetch_la_OBJECTS = prefetch.lo
+prefetch_la_OBJECTS = $(am_prefetch_la_OBJECTS)
+prefetch_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(prefetch_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(prefetch_la_SOURCES)
+DIST_SOURCES = $(prefetch_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = prefetch.la
+prefetch_la_SOURCES = prefetch.c
+prefetch_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/prefetch/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/prefetch/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+prefetch.la: $(prefetch_la_OBJECTS) $(prefetch_la_DEPENDENCIES) 
+	$(prefetch_la_LINK) -rpath $(pkglibdir) $(prefetch_la_OBJECTS) $(prefetch_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prefetch.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/prefetch.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/prefetch/prefetch-plugin-eg1.c b/example/prefetch/prefetch-plugin-eg1.c
new file mode 100644
index 00000000..47d87400
--- /dev/null
+++ b/example/prefetch/prefetch-plugin-eg1.c
@@ -0,0 +1,90 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+  prefetch-plugin-eg1.c : an example plugin which interacts with
+                          Traffic Server's prefetch feature
+
+*/
+
+#include 
+#include 
+#include 
+#include 
+
+/* We will register the following two hooks */
+
+int my_preparse_hook(int hook, TSPrefetchInfo * info);
+int my_embedded_url_hook(int hook, TSPrefetchInfo * info);
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "prefetch_plugin_eg1";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  /* register our hooks */
+  TSPrefetchHookSet(TS_PREFETCH_PRE_PARSE_HOOK, &my_preparse_hook);
+  TSPrefetchHookSet(TS_PREFETCH_EMBEDDED_URL_HOOK, &my_embedded_url_hook);
+}
+
+int
+my_preparse_hook(int hook, TSPrefetchInfo * info)
+{
+  unsigned char *ip = (unsigned char *) &info->client_ip;
+
+  printf("preparse hook (%d): request from child %u.%u.%u.%u\n", hook, ip[0], ip[1], ip[2], ip[3]);
+
+
+  /* we will let TS parse the page */
+  return TS_PREFETCH_CONTINUE;
+}
+
+int
+my_embedded_url_hook(int hook, TSPrefetchInfo * info)
+{
+
+  unsigned char *ip = (unsigned char *) &info->client_ip;
+
+  printf("url hook (%d): url: %s %s child: %u.%u.%u.%u\n",
+         hook, info->embedded_url, (info->present_in_cache) ? "(present in cache)" : "", ip[0], ip[1], ip[2], ip[3]);
+
+  /*
+     We will select UDP for sending url and TCP for sending object
+   */
+
+  info->url_proto = TS_PREFETCH_PROTO_UDP;
+  info->url_response_proto = TS_PREFETCH_PROTO_TCP;
+
+  /* we can return TS_PREFETCH_DISCONTINUE if we dont want TS to prefetch
+     this url */
+
+  return TS_PREFETCH_CONTINUE;
+}
diff --git a/example/prefetch/readme.txt b/example/prefetch/readme.txt
new file mode 100644
index 00000000..f7d1d8a5
--- /dev/null
+++ b/example/prefetch/readme.txt
@@ -0,0 +1,26 @@
+The test-hns-plugin tests the Parent Traffic Server handling of parse/prefetch
+rules. It prints information to 'stdout' at various stages to verify the
+correctness of the parse/prefetch module. It has the following options:
+
+-p. If 0, the plugin returns INK_PREFETCH_DISCONTINUE when called at the 
+    INK_PREFETCH_PRE_PARSE_HOOK. If 1, the plugin returns
+    INK_PREFETCH_CONTINUE.
+
+-u. If 0, the plugin returns INK_PREFETCH_DISCONTINUE when called at the 
+    INK_PREFETCH_EMBEDDED_URL_HOOK. If 1, the plugin returns
+    INK_PREFETCH_CONTINUE.
+
+-o. If 1, the plugin sets 'object_buf_status' field in the INKPrefetchInfo to
+    INK_PREFETCH_OBJ_BUF_NEEDED and expects to be called back with the object.
+
+-i. If 0, the plugin sets the 'url_response_proto' field in the 
+    INKPrefetchInfo to INK_PREFETCH_PROTO_UDP. If 1, it sets the 
+    'url_response_proto' field to INK_PREFETCH_PROTO_TCP.
+
+-d. Specifies the directory where the plugin will store all the prefetched
+    objects. All prefetched objects are stored in the PkgPreload format in 
+    the 'prefetched.objects' file in this directory.
+
+
+
+ 
diff --git a/example/prefetch/test-hns-plugin.c b/example/prefetch/test-hns-plugin.c
new file mode 100644
index 00000000..5c344e70
--- /dev/null
+++ b/example/prefetch/test-hns-plugin.c
@@ -0,0 +1,253 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+  prefetch-plugin-eg1.c : an example plugin which interacts with
+                          Traffic Server's prefetch feature
+
+*/
+
+/*
+This plugin tests the Parent Traffic Server handling of parse/prefetch
+rules. It prints information to 'stdout' at various stages to verify the
+correctness of the parse/prefetch module. It has the following options:
+
+-p. If 0, the plugin returns TS_PREFETCH_DISCONTINUE when called at the
+    TS_PREFETCH_PRE_PARSE_HOOK. If 1, the plugin returns
+    TS_PREFETCH_CONTINUE.
+
+-u. If 0, the plugin returns TS_PREFETCH_DISCONTINUE when called at the
+    TS_PREFETCH_EMBEDDED_URL_HOOK. If 1, the plugin returns
+    TS_PREFETCH_CONTINUE.
+
+-o. If 1, the plugin sets 'object_buf_status' field in the TSPrefetchInfo to
+    TS_PREFETCH_OBJ_BUF_NEEDED and expects to be called back with the object.
+    If 2, this field is set to TS_PREFETCH_OBJ_BUF_NEEDED_N_TRANSMITTED
+    which implies the object is transmitted to the child as well.
+
+-i. If 0, the plugin sets the 'url_response_proto' field in the
+    TSPrefetchInfo to TS_PREFETCH_PROTO_UDP. If 1, it sets the
+    'url_response_proto' field to TS_PREFETCH_PROTO_TCP.
+
+-d. Specifies the directory where the plugin will store all the prefetched
+    objects. All prefetched objects are stored in the PkgPreload format in
+    the 'prefetched.objects' file in this directory.
+
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* We will register the following two hooks */
+
+#define TAG "test-hns-plugin"
+
+TSFile filep1 = NULL;
+static int pre_parse_cont = 0;
+static int embedded_url_cont = 0;
+static int url_proto = 0;
+static int embedded_object = 0;
+
+static TSMutex file_write_mutex;
+
+int pre_parse_hook(int hook, TSPrefetchInfo * info);
+int embedded_url_hook(int hook, TSPrefetchInfo * info);
+int embedded_object_hook(int hook, TSPrefetchInfo * info);
+
+
+int
+embedded_object_hook(int hook, TSPrefetchInfo * info)
+{
+  int total_avail;
+
+  TSIOBufferBlock block;
+  const char *block_start;
+  int block_avail;
+
+  TSMutexLock(file_write_mutex);
+
+  printf("(%s) >>> TS_PREFETCH_EMBEDDED_OBJECT_HOOK (%d)\n", TAG, hook);
+
+  printf("(%s) \tobject size for: %s is %d\n",
+         TAG, info->embedded_url, TSIOBufferReaderAvail(info->object_buf_reader));
+
+  /* Get the embedded objects here */
+  total_avail = TSIOBufferReaderAvail(info->object_buf_reader);
+
+
+  block = TSIOBufferReaderStart(info->object_buf_reader);
+  while (block) {
+    block_start = TSIOBufferBlockReadStart(block, info->object_buf_reader, &block_avail);
+
+    if (block_avail == 0) {
+      break;
+    }
+
+    /* Put the object fragment into the file */
+    TSfwrite(filep1, block_start, block_avail);
+    TSfflush(filep1);
+    TSIOBufferReaderConsume(info->object_buf_reader, block_avail);
+    block = TSIOBufferReaderStart(info->object_buf_reader);
+  }
+
+
+  TSIOBufferDestroy(info->object_buf);
+
+  TSMutexUnlock(file_write_mutex);
+
+  return 0;
+}
+
+int
+embedded_url_hook(int hook, TSPrefetchInfo * info)
+{
+
+  unsigned char *ip = (unsigned char *) &info->client_ip;
+
+  printf("(%s) >>> TS_PREFETCH_EMBEDDED_URL_HOOK (%d)\n", TAG, hook);
+
+  printf("(%s) \tURL: %s %s Child IP: %u.%u.%u.%u\n",
+         TAG, info->embedded_url, (info->present_in_cache) ? "(present in cache)" : "", ip[0], ip[1], ip[2], ip[3]);
+
+  /* We will select UDP for sending url and TCP for sending object */
+  if (embedded_object)
+    info->object_buf_status = (embedded_object == 1)
+      ? TS_PREFETCH_OBJ_BUF_NEEDED : TS_PREFETCH_OBJ_BUF_NEEDED_N_TRANSMITTED;
+  if (url_proto)
+    info->url_response_proto = TS_PREFETCH_PROTO_TCP;
+  else
+    info->url_response_proto = TS_PREFETCH_PROTO_UDP;
+
+
+  if (!embedded_url_cont) {
+    /* This will cause parent TS not to parse the HTML page */
+    printf("(%s) \tPlugin returns - TS_PREFETCH_DISCONTINUE\n", TAG);
+    return TS_PREFETCH_DISCONTINUE;
+
+  } else {
+    /* This will cause TS (MDE plugin) to prefetch the URL */
+    printf("(%s) \tURL Response Protocol: %s\n", TAG,
+           (info->url_response_proto == TS_PREFETCH_PROTO_TCP) ? "TS_PREFETCH_PROTO_TCP" : "TS_PREFETCH_PROTO_UDP");
+    printf("(%s) \tPlugin returns - TS_PREFETCH_CONTINUE\n", TAG);
+    return TS_PREFETCH_CONTINUE;
+  }
+}
+
+
+int
+pre_parse_hook(int hook, TSPrefetchInfo * info)
+{
+  unsigned char *ip = (unsigned char *) &info->client_ip;
+
+  printf("(%s) >>> TS_PREFETCH_PRE_PARSE_HOOK (%d)\n", TAG, hook);
+
+  printf("(%s) \tChild IP : %u.%u.%u.%u\n", TAG, ip[0], ip[1], ip[2], ip[3]);
+
+  if (!pre_parse_cont) {
+    /* This will cause parent TS not to parse the HTML page */
+    printf("(%s) \tPlugin returns - TS_PREFETCH_DISCONTINUE\n", TAG);
+    return TS_PREFETCH_DISCONTINUE;
+
+  } else {
+    /* we will let TS parse the page */
+    printf("(%s) \tPlugin returns - TS_PREFETCH_CONTINUE\n", TAG);
+    return TS_PREFETCH_CONTINUE;
+  }
+}
+
+
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  int c, arg;
+  extern char *optarg;
+  extern int optind, opterr, optopt;
+  TSPluginRegistrationInfo plugin_info;
+  char file_name[512] = { 0 };
+  plugin_info.plugin_name = "test-prefetch";
+  plugin_info.vendor_name = "MyCompany";
+  plugin_info.support_email = "ts-api-support@MyCompany.com";
+
+  if (!TSPluginRegister(TS_SDK_VERSION_3_0, &plugin_info)) {
+    TSError("Plugin registration failed.\n");
+    return;
+  }
+
+  while ((c = getopt(argc, (char *const *) argv, "p:u:i:o:d:")) != EOF) {
+    switch (c) {
+    case 'p':
+    case 'u':
+    case 'i':
+    case 'o':
+      if (!strcmp(optarg, "0"))
+        arg = 0;
+      else if (!strcmp(optarg, "1"))
+        arg = 1;
+      else if (!strcmp(optarg, "2"))
+        arg = 2;
+      else {
+        TSError("Invalid argument specified for option: %c\n", c);
+        return;
+      }
+      if (c == 'p')
+        pre_parse_cont = arg;
+      else if (c == 'u')
+        embedded_url_cont = arg;
+      else if (c == 'i')
+        url_proto = arg;
+      else
+        embedded_object = arg;
+      break;
+
+    case 'd':
+      sprintf(file_name, "%s/prefetched.objects", optarg);
+      break;
+    case '?':
+      TSError("Invalid argument specified\n");
+      return;
+    }
+  }
+
+  if (embedded_object) {
+    filep1 = TSfopen(file_name, "w");
+    if (!filep1) {
+      TSError("Cannot open file %d for writing\n", file_name);
+      return;
+    }
+    TSfwrite(filep1, "", 1);
+    TSfflush(filep1);
+
+    file_write_mutex = TSMutexCreate();
+  }
+
+  /* register our hooks */
+  TSPrefetchHookSet(TS_PREFETCH_PRE_PARSE_HOOK, &pre_parse_hook);
+  TSPrefetchHookSet(TS_PREFETCH_EMBEDDED_URL_HOOK, &embedded_url_hook);
+  TSPrefetchHookSet(TS_PREFETCH_EMBEDDED_OBJECT_HOOK, &embedded_object_hook);
+}
diff --git a/example/protocol/Makefile.am b/example/protocol/Makefile.am
new file mode 100644
index 00000000..b5df01ce
--- /dev/null
+++ b/example/protocol/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = protocol.la
+protocol_la_SOURCES = Protocol.c TxnSM.c
+protocol_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/protocol.so
diff --git a/example/protocol/Makefile.in b/example/protocol/Makefile.in
new file mode 100644
index 00000000..180ab3d5
--- /dev/null
+++ b/example/protocol/Makefile.in
@@ -0,0 +1,738 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/protocol
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+protocol_la_LIBADD =
+am_protocol_la_OBJECTS = Protocol.lo TxnSM.lo
+protocol_la_OBJECTS = $(am_protocol_la_OBJECTS)
+protocol_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(protocol_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(protocol_la_SOURCES)
+DIST_SOURCES = $(protocol_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = protocol.la
+protocol_la_SOURCES = Protocol.c TxnSM.c
+protocol_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/protocol/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/protocol/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+protocol.la: $(protocol_la_OBJECTS) $(protocol_la_DEPENDENCIES) 
+	$(protocol_la_LINK) -rpath $(pkglibdir) $(protocol_la_OBJECTS) $(protocol_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Protocol.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TxnSM.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/protocol.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/protocol/Protocol.c b/example/protocol/Protocol.c
new file mode 100644
index 00000000..0dd1bec6
--- /dev/null
+++ b/example/protocol/Protocol.c
@@ -0,0 +1,180 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "Protocol.h"
+#include "TxnSM.h"
+#include 
+
+/* global variable */
+TSTextLogObject protocol_plugin_log;
+
+/* static variable */
+static TSAction pending_action;
+static int accept_port;
+static int server_port;
+
+/* Functions only seen in this file, should be static. */
+static void protocol_init(int accept_port, int server_port);
+static int accept_handler(TSCont contp, TSEvent event, void *edata);
+
+
+/* When the handle is called, the net_vc is returned. */
+static int
+accept_handler(TSCont contp, TSEvent event, void *edata)
+{
+  TSCont txn_sm;
+  TSMutex pmutex;
+
+  switch (event) {
+  case TS_EVENT_NET_ACCEPT:
+    /* Create a new mutex for the TxnSM, which is going
+       to handle the incoming request. */
+    pmutex = (TSMutex) TSMutexCreate();
+    txn_sm = (TSCont) TxnSMCreate(pmutex, (TSVConn) edata, server_port);
+
+    /* This is no reason for not grabbing the lock.
+       So skip the routine which handle LockTry failure case. */
+    TSMutexLockTry(pmutex); // TODO: why should it not check if we got the lock??
+    TSContCall(txn_sm, 0, NULL);
+    TSMutexUnlock(pmutex);
+    break;
+
+  default:
+    /* Something wrong with the network, if there are any
+       pending NetAccept, cancel them. */
+    if (pending_action && !TSActionDone(pending_action))
+      TSActionCancel(pending_action);
+
+    TSContDestroy(contp);
+    break;
+  }
+
+  return TS_EVENT_NONE;
+}
+
+static void
+protocol_init(int accept_port, int server_port)
+{
+  TSCont contp;
+  int ret_val;
+
+  /* create customized log */
+  ret_val = TSTextLogObjectCreate("protocol", TS_LOG_MODE_ADD_TIMESTAMP, &protocol_plugin_log);
+  if (ret_val != TS_SUCCESS) {
+    TSError("failed to create log");
+  }
+
+  /* format of the log entries, for caching_status, 1 for HIT and 0 for MISS */
+  ret_val = TSTextLogObjectWrite(protocol_plugin_log, "timestamp filename servername caching_status\n\n");
+  if (ret_val != TS_SUCCESS) {
+    TSError("failed to write into log");
+  }
+
+  contp = TSContCreate(accept_handler, TSMutexCreate());
+
+  /* Accept network traffic from the accept_port.
+     When there are requests coming in, contp's handler
+     should be called, in this case, contp's handler
+     is accept_event, see AcceptSM.c */
+  pending_action = TSNetAccept(contp, accept_port, -1, 1);
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "output-header";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("[PluginInit] Plugin registration failed.\n");
+    goto error;
+  }
+
+  if (!check_ts_version()) {
+    TSError("[PluginInit] Plugin requires Traffic Server 3.0 or later\n");
+    goto error;
+  }
+
+
+  /* default value */
+  accept_port = 4666;
+  server_port = 4666;
+
+  if (argc < 3) {
+    TSDebug("protocol", "Usage: protocol.so accept_port server_port");
+    printf("[protocol_plugin] Usage: protocol.so accept_port server_port\n");
+    printf("[protocol_plugin] Wrong arguments. Using deafult ports.\n");
+  } else {
+    if (!isnan(atoi(argv[1]))) {
+      accept_port = atoi(argv[1]);
+      TSDebug("protocol", "using accept_port %d", accept_port);
+      printf("[protocol_plugin] using accept_port %d\n", accept_port);
+    } else {
+      printf("[protocol_plugin] Wrong argument for accept_port.");
+      printf("Using deafult port %d\n", accept_port);
+    }
+
+    if (!isnan(atoi(argv[2]))) {
+      server_port = atoi(argv[2]);
+      TSDebug("protocol", "using server_port %d", server_port);
+      printf("[protocol_plugin] using server_port %d\n", server_port);
+    } else {
+      printf("[protocol_plugin] Wrong argument for server_port.");
+      printf("Using deafult port %d\n", server_port);
+    }
+  }
+
+  protocol_init(accept_port, server_port);
+
+error:
+  TSError("[PluginInit] Plugin not initialized");
+}
diff --git a/example/protocol/Protocol.h b/example/protocol/Protocol.h
new file mode 100644
index 00000000..aeddd0d4
--- /dev/null
+++ b/example/protocol/Protocol.h
@@ -0,0 +1,47 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#define MAX_SERVER_NAME_LENGTH 1024
+#define MAX_FILE_NAME_LENGTH 1024
+
+/* MAX_SERVER_NAME_LENGTH + MAX_FILE_NAME_LENGTH + strlen("\n\n") */
+#define MAX_REQUEST_LENGTH 2050
+
+#define set_handler(_d, _s) {_d = _s;}
+
+
+#endif /* PROTOCOL_H */
diff --git a/example/protocol/README.txt b/example/protocol/README.txt
new file mode 100644
index 00000000..5535fa02
--- /dev/null
+++ b/example/protocol/README.txt
@@ -0,0 +1,52 @@
+
+Protocol plugin example for SDK 3.0
+
+List of files
+-------------
+
+ - Protocol.c : Accept client requests and generate transaction state machines for each client request.
+ - TxnSM.c    : Implementation of handling a transaction.
+
+ - Protocol.h : Header file.
+ - TxnSM.h    : Header file.
+
+ - test/ProtocolServerTest.java : Synthetic server.
+ - test/ProtocolClientTest.java : Synthetic client.
+ - test/file_gen.sh : shell script to generate file list for testing.
+
+Protocol
+--------
+
+ - Request  : [server_name][space][file_name][space][\r\n]
+ - Response : File (if file is found)
+              Nothing (if file is not found)
+
+How to run proxy
+----------------
+
+ - Compile protocol.so and copy it under plugins directory.
+ - In plugin.config: 
+   protocol.so  
+   accept_port is the port to listen to client requests.
+   server_port is the port to connect to origin server.
+ - Debug tag: -T"protocol".
+
+How to run synthetic server
+---------------------------
+
+ - Compile ProtocolServerTest.java and get ProtocolServerTest.class.
+ - Run: java ProtocolServerTest 
+   server_port is the port synthetic server listens to requests.
+   server_port should match "server_port" argument passed to the plugin.
+
+How to run synthetic client
+---------------------------
+ - Compile ProtocolClientTest.java and get ProtocolClientTest.class.
+ - Run: java ProtocolClientTest -options. 
+ - Options include:
+   "-P" : proxy name (e.g. npdev.example.com)
+   "-p" : proxy port (match "accept_port" argument passed to the plugin)
+   "-s" : origin server name
+   "-f" : file list name (generated by file_gen.sh)
+   "-n" : number of pipelined client requests
+   "-l" : how many times of looping
diff --git a/example/protocol/TxnSM.c b/example/protocol/TxnSM.c
new file mode 100644
index 00000000..9cf20f26
--- /dev/null
+++ b/example/protocol/TxnSM.c
@@ -0,0 +1,969 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "TxnSM.h"
+
+extern TSTextLogObject protocol_plugin_log;
+
+/* Fix me: currently, tunnelling server_response from OS to both cache and
+   client doesn't work for client_vc. So write data first to cache and then
+   write cached data to client. */
+
+/* static functions */
+int main_handler(TSCont contp, TSEvent event, void *data);
+
+/* functions for clients */
+int state_start(TSCont contp, TSEvent event, void *data);
+int state_interface_with_client(TSCont contp, TSEvent event, TSVIO vio);
+int state_read_request_from_client(TSCont contp, TSEvent event, TSVIO vio);
+int state_send_response_to_client(TSCont contp, TSEvent event, TSVIO vio);
+
+/* functions for cache operation */
+int state_handle_cache_lookup(TSCont contp, TSEvent event, TSVConn vc);
+int state_handle_cache_read_response(TSCont contp, TSEvent event, TSVIO vio);
+int state_handle_cache_prepare_for_write(TSCont contp, TSEvent event, TSVConn vc);
+int state_write_to_cache(TSCont contp, TSEvent event, TSVIO vio);
+
+/* functions for servers */
+int state_build_and_send_request(TSCont contp, TSEvent event, void *data);
+int state_dns_lookup(TSCont contp, TSEvent event, TSHostLookupResult host_info);
+int state_connect_to_server(TSCont contp, TSEvent event, TSVConn vc);
+int state_interface_with_server(TSCont contp, TSEvent event, TSVIO vio);
+int state_send_request_to_server(TSCont contp, TSEvent event, TSVIO vio);
+int state_read_response_from_server(TSCont contp, TSEvent event, TSVIO vio);
+
+/* misc functions */
+int state_done(TSCont contp, TSEvent event, TSVIO vio);
+
+int send_response_to_client(TSCont contp);
+int prepare_to_die(TSCont contp);
+
+char *get_info_from_buffer(TSIOBufferReader the_reader);
+int is_request_end(char *buf);
+int parse_request(char *request, char *server_name, char *file_name);
+TSCacheKey CacheKeyCreate(char *file_name);
+
+/* Continuation handler is a function pointer, this function
+   is to assign the continuation handler to a specific function. */
+int
+main_handler(TSCont contp, TSEvent event, void *data)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+  TxnSMHandler q_current_handler = txn_sm->q_current_handler;
+
+  TSDebug("protocol", "main_handler (contp %X event %d)", contp, event);
+
+  /* handle common cases errors */
+  if (event == TS_EVENT_ERROR) {
+    return prepare_to_die(contp);
+  }
+
+  if (q_current_handler != (TxnSMHandler)&state_interface_with_server) {
+    if (event == TS_EVENT_VCONN_EOS) {
+      return prepare_to_die(contp);
+    }
+  }
+
+  TSDebug("protocol", "current_handler (%p)", q_current_handler);
+
+  return (*q_current_handler) (contp, event, data);
+}
+
+/* Create the Txn data structure and the continuation for the Txn. */
+TSCont
+TxnSMCreate(TSMutex pmutex, TSVConn client_vc, int server_port)
+{
+  TSCont contp;
+  TxnSM *txn_sm;
+
+  txn_sm = (TxnSM *) TSmalloc(sizeof(TxnSM));
+
+  txn_sm->q_mutex = pmutex;
+  txn_sm->q_pending_action = NULL;
+
+  /* Txn will use this server port to connect to the origin server. */
+  txn_sm->q_server_port = server_port;
+  /* The client_vc is returned by TSNetAccept, refer to Protocol.c. */
+  txn_sm->q_client_vc = client_vc;
+  /* The server_vc will be created if Txn connects to the origin server. */
+  txn_sm->q_server_vc = NULL;
+
+  txn_sm->q_client_read_vio = NULL;
+  txn_sm->q_client_write_vio = NULL;
+  txn_sm->q_client_request_buffer = NULL;
+  txn_sm->q_client_response_buffer = NULL;
+  txn_sm->q_client_request_buffer_reader = NULL;
+  txn_sm->q_client_response_buffer_reader = NULL;
+
+  txn_sm->q_server_read_vio = NULL;
+  txn_sm->q_server_write_vio = NULL;
+  txn_sm->q_server_request_buffer = NULL;
+  txn_sm->q_server_response_buffer = NULL;
+  txn_sm->q_server_request_buffer_reader = NULL;
+
+  /* Char buffers to store client request and server response. */
+  txn_sm->q_client_request = (char *) TSmalloc(sizeof(char) * (MAX_REQUEST_LENGTH + 1));
+  memset(txn_sm->q_client_request, '\0', (sizeof(char) * (MAX_REQUEST_LENGTH + 1)));
+  txn_sm->q_server_response = NULL;
+  txn_sm->q_server_response_length = 0;
+  txn_sm->q_block_bytes_read = 0;
+  txn_sm->q_cache_vc = NULL;
+  txn_sm->q_cache_response_length = 0;
+  txn_sm->q_cache_read_buffer = NULL;
+  txn_sm->q_cache_read_buffer_reader = NULL;
+
+  txn_sm->q_server_name = (char *) TSmalloc(sizeof(char) * (MAX_SERVER_NAME_LENGTH + 1));
+  txn_sm->q_file_name = (char *) TSmalloc(sizeof(char) * (MAX_FILE_NAME_LENGTH + 1));
+
+  txn_sm->q_key = NULL;
+  txn_sm->q_magic = TXN_SM_ALIVE;
+
+  /* Set the current handler to be state_start. */
+  set_handler(txn_sm->q_current_handler, &state_start);
+
+  contp = TSContCreate(main_handler, txn_sm->q_mutex);
+  TSContDataSet(contp, txn_sm);
+  return contp;
+}
+
+/* This function starts to read incoming client request data from client_vc */
+int
+state_start(TSCont contp, TSEvent event, void *data)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  if (!txn_sm->q_client_vc) {
+    return prepare_to_die(contp);
+  }
+
+  txn_sm->q_client_request_buffer = TSIOBufferCreate();
+  txn_sm->q_client_request_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_client_request_buffer);
+
+  if (!txn_sm->q_client_request_buffer || !txn_sm->q_client_request_buffer_reader) {
+    return prepare_to_die(contp);
+  }
+
+  /* Now the IOBuffer and IOBufferReader is ready, the data from
+     client_vc can be read into the IOBuffer. Since we don't know
+     the size of the client request, set the expecting size to be
+     INT64_MAX, so that we will always get TS_EVENT_VCONN_READ_READY
+     event, but never TS_EVENT_VCONN_READ_COMPLETE event. */
+  set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_interface_with_client);
+  txn_sm->q_client_read_vio = TSVConnRead(txn_sm->q_client_vc, (TSCont) contp, txn_sm->q_client_request_buffer, INT64_MAX);
+
+  return TS_SUCCESS;
+}
+
+/* This function is to call proper functions according to the
+   VIO argument. If it's read_vio, which means reading request from
+   client_vc, call state_read_request_from_client. If it's write_vio,
+   which means sending response to client_vc, call
+   state_send_response_to_client. If the event is TS_EVENT_VCONN_EOS,
+   which means the client closed socket and thus implies the client
+   drop all jobs between TxnSM and the client, so go to die. */
+int
+state_interface_with_client(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_interface_with_client");
+
+  txn_sm->q_pending_action = NULL;
+
+  if (vio == txn_sm->q_client_read_vio)
+    return state_read_request_from_client(contp, event, vio);
+
+  /* vio == txn_sm->q_client_write_vio */
+  return state_send_response_to_client(contp, event, vio);
+}
+
+/* Data is read from client_vc, if all data for the request is in,
+   parse it and do cache lookup. */
+int
+state_read_request_from_client(TSCont contp, TSEvent event, TSVIO vio)
+{
+  int bytes_read, parse_result;
+  char *temp_buf;
+
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_read_request_from_client");
+
+  switch (event) {
+  case TS_EVENT_VCONN_READ_READY:
+    bytes_read = TSIOBufferReaderAvail(txn_sm->q_client_request_buffer_reader);
+
+    if (bytes_read > 0) {
+      temp_buf = (char *) get_info_from_buffer(txn_sm->q_client_request_buffer_reader);
+      strcat(txn_sm->q_client_request, temp_buf);
+      TSfree(temp_buf);
+
+      /* Check if the request is fully read, if so, do cache lookup. */
+      if (strstr(txn_sm->q_client_request, "\r\n\r\n") != NULL) {
+        temp_buf = (char *) TSmalloc(sizeof(char) * (strlen(txn_sm->q_client_request) + 1));
+        memcpy(temp_buf, txn_sm->q_client_request, strlen(txn_sm->q_client_request));
+        temp_buf[strlen(txn_sm->q_client_request)] = '\0';
+        parse_result = parse_request(temp_buf, txn_sm->q_server_name, txn_sm->q_file_name);
+        TSfree(temp_buf);
+
+        if (parse_result != 1)
+          return prepare_to_die(contp);
+
+        /* Start to do cache lookup */
+        TSDebug("protocol", "Key material: file name is %d, %s*****", txn_sm->q_file_name, txn_sm->q_file_name);
+        txn_sm->q_key = (TSCacheKey)CacheKeyCreate(txn_sm->q_file_name);
+
+        set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_lookup);
+        txn_sm->q_pending_action = TSCacheRead(contp, txn_sm->q_key);
+
+        return TS_SUCCESS;
+      }
+    }
+
+    /* The request is not fully read, reenable the read_vio. */
+    TSVIOReenable(txn_sm->q_client_read_vio);
+    break;
+
+  default:                     /* Shouldn't get here, prepare to die. */
+    return prepare_to_die(contp);
+
+  }
+  return TS_SUCCESS;
+}
+
+/* This function handle the cache lookup result. If MISS, try to
+   open cache write_vc for writing. Otherwise, use the vc returned
+   by the cache to read the data from the cache. */
+int
+state_handle_cache_lookup(TSCont contp, TSEvent event, TSVConn vc)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+  int64_t response_size;
+  int ret_val;
+
+  TSDebug("protocol", "enter state_handle_cache_lookup");
+
+  switch (event) {
+  case TS_EVENT_CACHE_OPEN_READ:
+    TSDebug("protocol", "cache hit!!!");
+    /* Cache hit. */
+
+    /* Write log */
+    ret_val = TSTextLogObjectWrite(protocol_plugin_log, "%s %s %d \n", txn_sm->q_file_name, txn_sm->q_server_name, 1);
+    if (ret_val != TS_SUCCESS)
+      TSError("fail to write into log");
+
+    txn_sm->q_cache_vc = vc;
+    txn_sm->q_pending_action = NULL;
+
+    /* Get the size of the cached doc. */
+    response_size = TSVConnCacheObjectSizeGet(txn_sm->q_cache_vc);
+
+    /* Allocate IOBuffer to store data from the cache. */
+    txn_sm->q_client_response_buffer = TSIOBufferCreate();
+    txn_sm->q_client_response_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_client_response_buffer);
+    txn_sm->q_cache_read_buffer = TSIOBufferCreate();
+    txn_sm->q_cache_read_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_cache_read_buffer);
+
+    if (!txn_sm->q_client_response_buffer ||
+        !txn_sm->q_client_response_buffer_reader ||
+        !txn_sm->q_cache_read_buffer || !txn_sm->q_cache_read_buffer_reader) {
+      return prepare_to_die(contp);
+    }
+
+    /* Read doc from the cache. */
+    set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_read_response);
+    txn_sm->q_cache_read_vio = TSVConnRead(txn_sm->q_cache_vc, contp, txn_sm->q_cache_read_buffer, response_size);
+
+    break;
+
+  case TS_EVENT_CACHE_OPEN_READ_FAILED:
+    /* Cache miss or error, open cache write_vc. */
+    TSDebug("protocol", "cache miss or error!!!");
+    /* Write log */
+    ret_val = TSTextLogObjectWrite(protocol_plugin_log, "%s %s %d \n", txn_sm->q_file_name, txn_sm->q_server_name, 0);
+
+    if (ret_val != TS_SUCCESS)
+      TSError("fail to write into log");
+
+    set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_prepare_for_write);
+    txn_sm->q_pending_action = TSCacheWrite(contp, txn_sm->q_key);
+    break;
+
+  default:
+    /* unknown event, abort transaction */
+    return prepare_to_die(contp);
+  }
+
+  return TS_SUCCESS;
+}
+
+static void
+load_buffer_cache_data(TxnSM * txn_sm)
+{
+  /* transfer the data from the cache buffer (which must
+     fully be consumed on a VCONN_READY event, to the
+     server response buffer */
+  int rdr_avail = TSIOBufferReaderAvail(txn_sm->q_cache_read_buffer_reader);
+
+  TSDebug("protocol", "entering buffer_cache_data");
+  TSDebug("protocol", "loading %d bytes to buffer reader", rdr_avail);
+
+  TSAssert(rdr_avail > 0);
+
+  TSIOBufferCopy(txn_sm->q_client_response_buffer,     /* (cache response buffer) */
+                  txn_sm->q_cache_read_buffer_reader,   /* (transient buffer)      */
+                  rdr_avail, 0);
+
+  TSIOBufferReaderConsume(txn_sm->q_cache_read_buffer_reader, rdr_avail);
+}
+
+/* If the document is fully read out of the cache, close the
+   cache read_vc, send the document to the client. Otherwise,
+   reenable the read_vio to read more data out. If some error
+   occurs, close the read_vc, open write_vc for writing the doc
+   into the cache.*/
+int
+state_handle_cache_read_response(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_handle_cache_read_response");
+
+  txn_sm->q_pending_action = NULL;
+
+  switch (event) {
+  case TS_EVENT_VCONN_READ_COMPLETE:
+    load_buffer_cache_data(txn_sm);
+    TSVConnClose(txn_sm->q_cache_vc);
+    txn_sm->q_cache_vc = NULL;
+    txn_sm->q_cache_read_vio = NULL;
+    txn_sm->q_cache_write_vio = NULL;
+    TSIOBufferReaderFree(txn_sm->q_cache_read_buffer_reader);
+    TSIOBufferDestroy(txn_sm->q_cache_read_buffer);
+    txn_sm->q_cache_read_buffer_reader = NULL;
+    txn_sm->q_cache_read_buffer = NULL;
+    return send_response_to_client(contp);
+
+  case TS_EVENT_VCONN_READ_READY:
+    load_buffer_cache_data(txn_sm);
+
+    TSVIOReenable(txn_sm->q_cache_read_vio);
+    break;
+
+  default:
+    /* Error */
+    if (txn_sm->q_cache_vc) {
+      TSVConnClose(txn_sm->q_cache_vc);
+      txn_sm->q_cache_vc = NULL;
+      txn_sm->q_cache_read_vio = NULL;
+      txn_sm->q_cache_write_vio = NULL;
+    }
+
+    /* Open the write_vc, after getting doc from the origin server,
+       write the doc into the cache. */
+    set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_prepare_for_write);
+    TSAssert(txn_sm->q_pending_action == NULL);
+    txn_sm->q_pending_action = TSCacheWrite(contp, txn_sm->q_key);
+    break;
+
+  }
+  return TS_SUCCESS;
+}
+
+/* The cache processor call us back with the vc to use for writing
+   data into the cache.
+   In case of error, abort txn. */
+int
+state_handle_cache_prepare_for_write(TSCont contp, TSEvent event, TSVConn vc)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_handle_cache_prepare_for_write");
+
+  txn_sm->q_pending_action = NULL;
+
+  switch (event) {
+  case TS_EVENT_CACHE_OPEN_WRITE:
+    txn_sm->q_cache_vc = vc;
+    break;
+  default:
+    TSError("can't open cache write_vc, aborting txn");
+    txn_sm->q_cache_vc = NULL;
+    return prepare_to_die(contp);
+    break;
+  }
+  return state_build_and_send_request(contp, 0, NULL);
+}
+
+/* Cache miss or error case. Start the process to send the request
+   the origin server. */
+int
+state_build_and_send_request(TSCont contp, TSEvent event, void *data)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_build_and_send_request");
+
+  txn_sm->q_pending_action = NULL;
+
+  txn_sm->q_server_request_buffer = TSIOBufferCreate();
+  txn_sm->q_server_request_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_server_request_buffer);
+
+  txn_sm->q_server_response_buffer = TSIOBufferCreate();
+  txn_sm->q_cache_response_buffer_reader = TSIOBufferReaderAlloc(txn_sm->q_server_response_buffer);
+
+  if (!txn_sm->q_server_request_buffer ||
+      !txn_sm->q_server_request_buffer_reader ||
+      !txn_sm->q_server_response_buffer || !txn_sm->q_cache_response_buffer_reader) {
+    return prepare_to_die(contp);
+  }
+
+  /* Marshal request */
+  TSIOBufferWrite(txn_sm->q_server_request_buffer, txn_sm->q_client_request, strlen(txn_sm->q_client_request));
+
+  /* First thing to do is to get the server IP from the server host name. */
+  set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_dns_lookup);
+  TSAssert(txn_sm->q_pending_action == NULL);
+  txn_sm->q_pending_action = TSHostLookup(contp, txn_sm->q_server_name, strlen(txn_sm->q_server_name));
+
+  TSAssert(txn_sm->q_pending_action);
+  TSDebug("protocol", "initiating host lookup");
+
+  return TS_SUCCESS;
+}
+
+/* If Host lookup is successfully, connect to that IP. */
+int
+state_dns_lookup(TSCont contp, TSEvent event, TSHostLookupResult host_info)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_dns_lookup");
+
+  /* Can't find the server IP. */
+  if (event != TS_EVENT_HOST_LOOKUP || !host_info) {
+    return prepare_to_die(contp);
+  }
+  txn_sm->q_pending_action = NULL;
+
+  /* Get the server IP from data structure TSHostLookupResult. */
+  txn_sm->q_server_ip = TSHostLookupResultIPGet(host_info);
+
+  /* Connect to the server using its IP. */
+  set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_connect_to_server);
+  TSAssert(txn_sm->q_pending_action == NULL);
+  txn_sm->q_pending_action = TSNetConnect(contp, txn_sm->q_server_ip, txn_sm->q_server_port);
+
+  return TS_SUCCESS;
+}
+
+/* Net Processor calls back, if succeeded, the net_vc is returned.
+   Note here, even if the event is TS_EVENT_NET_CONNECT, it doesn't
+   mean the net connection is set up because TSNetConnect is non-blocking.
+   Do VConnWrite to the net_vc, if fails, that means there is no net
+   connection. */
+int
+state_connect_to_server(TSCont contp, TSEvent event, TSVConn vc)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_connect_to_server");
+
+  /* TSNetConnect failed. */
+  if (event != TS_EVENT_NET_CONNECT) {
+    return prepare_to_die(contp);
+  }
+  txn_sm->q_pending_action = NULL;
+
+  txn_sm->q_server_vc = vc;
+
+  /* server_vc will be used to write request and read response. */
+  set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_send_request_to_server);
+
+  /* Actively write the request to the net_vc. */
+  txn_sm->q_server_write_vio = TSVConnWrite(txn_sm->q_server_vc, contp,
+                                             txn_sm->q_server_request_buffer_reader, strlen(txn_sm->q_client_request));
+  return TS_SUCCESS;
+}
+
+/* Net Processor calls back, if write complete, wait for the response
+   coming in, otherwise, reenable the write_vio. */
+int
+state_send_request_to_server(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_send_request_to_server");
+
+  switch (event) {
+  case TS_EVENT_VCONN_WRITE_READY:
+    TSVIOReenable(vio);
+    break;
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    vio = NULL;
+
+    /* Waiting for the incoming response. */
+    set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_interface_with_server);
+    txn_sm->q_server_read_vio = TSVConnRead(txn_sm->q_server_vc, contp, txn_sm->q_server_response_buffer, INT64_MAX);
+    break;
+
+    /* it could be failure of TSNetConnect */
+  default:
+    return prepare_to_die(contp);
+  }
+  return TS_SUCCESS;
+}
+
+/* Call correct handler according to the vio type. */
+int
+state_interface_with_server(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_interface_with_server");
+
+  txn_sm->q_pending_action = NULL;
+
+  switch (event) {
+    /* This is returned from cache_vc. */
+  case TS_EVENT_VCONN_WRITE_READY:
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    return state_write_to_cache(contp, event, vio);
+    /* Otherwise, handle events from server. */
+  case TS_EVENT_VCONN_READ_READY:
+    /* Actually, we shouldn't get READ_COMPLETE because we set bytes
+       count to be INT64_MAX. */
+  case TS_EVENT_VCONN_READ_COMPLETE:
+    return state_read_response_from_server(contp, event, vio);
+
+    /* all data of the response come in. */
+  case TS_EVENT_VCONN_EOS:
+    TSDebug("protocol", "get server eos");
+    /* There is no more use of server_vc, close it. */
+    if (txn_sm->q_server_vc) {
+      TSVConnClose(txn_sm->q_server_vc);
+      txn_sm->q_server_vc = NULL;
+    }
+    txn_sm->q_server_read_vio = NULL;
+    txn_sm->q_server_write_vio = NULL;
+
+    /* Check if the response is good */
+    if (txn_sm->q_server_response_length == 0) {
+      /* This is the bad response. Close client_vc. */
+      if (txn_sm->q_client_vc) {
+        TSVConnClose(txn_sm->q_client_vc);
+        txn_sm->q_client_vc = NULL;
+      }
+      txn_sm->q_client_read_vio = NULL;
+      txn_sm->q_client_write_vio = NULL;
+
+      /* Close cache_vc as well. */
+      if (txn_sm->q_cache_vc) {
+        TSVConnClose(txn_sm->q_cache_vc);
+        txn_sm->q_cache_vc = NULL;
+      }
+      txn_sm->q_cache_write_vio = NULL;
+      return state_done(contp, 0, NULL);
+    }
+
+    if (txn_sm->q_cache_response_length >= txn_sm->q_server_response_length) {
+      /* Write is complete, close the cache_vc. */
+      TSVConnClose(txn_sm->q_cache_vc);
+      txn_sm->q_cache_vc = NULL;
+      txn_sm->q_cache_write_vio = NULL;
+      TSIOBufferReaderFree(txn_sm->q_cache_response_buffer_reader);
+
+      /* Open cache_vc to read data and send to client. */
+      set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_lookup);
+      txn_sm->q_pending_action = TSCacheRead(contp, txn_sm->q_key);
+    } else {                    /* not done with writing into cache */
+
+      TSDebug("protocol", "cache_response_length is %d, server response length is %d", txn_sm->q_cache_response_length,
+               txn_sm->q_server_response_length);
+      TSVIOReenable(txn_sm->q_cache_write_vio);
+    }
+
+  default:
+    break;
+  }
+
+  return TS_SUCCESS;
+}
+
+/* The response comes in. If the origin server finishes writing, it
+   will close the socket, so the event returned from the net_vc is
+   TS_EVENT_VCONN_EOS. By this event, TxnSM knows all data of the
+   response arrives and so parse it, save a copy in the cache and
+   send the doc to the client. If reading is not done, reenable the
+   read_vio. */
+int
+state_read_response_from_server(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+  int bytes_read = 0;
+
+  TSDebug("protocol", "enter state_read_response_from_server");
+
+  bytes_read = TSIOBufferReaderAvail(txn_sm->q_cache_response_buffer_reader);
+
+  if ((bytes_read > 0) && (txn_sm->q_cache_vc)) {
+    /* If this is the first write, do TSVConnWrite, otherwise, simply
+       reenable q_cache_write_vio. */
+    if (txn_sm->q_server_response_length == 0) {
+      txn_sm->q_cache_write_vio = TSVConnWrite(txn_sm->q_cache_vc,
+                                                contp, txn_sm->q_cache_response_buffer_reader, bytes_read);
+    } else {
+      TSAssert(txn_sm->q_server_response_length > 0);
+      TSVIOReenable(txn_sm->q_cache_write_vio);
+      txn_sm->q_block_bytes_read = bytes_read;
+/*
+	    txn_sm->q_cache_write_vio = TSVConnWrite (txn_sm->q_cache_vc,
+						       contp,
+						       txn_sm->q_cache_response_buffer_reader,
+						       bytes_read);
+						       */
+    }
+  }
+
+  txn_sm->q_server_response_length += bytes_read;
+  TSDebug("protocol", "bytes read is %d, total response length is %d", bytes_read, txn_sm->q_server_response_length);
+
+  return TS_SUCCESS;
+}
+
+/* If the whole doc has been written into the cache, send the response
+   to the client, otherwise, reenable the read_vio. */
+int
+state_write_to_cache(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_write_to_cache");
+
+  switch (event) {
+  case TS_EVENT_VCONN_WRITE_READY:
+    TSVIOReenable(txn_sm->q_cache_write_vio);
+    return TS_SUCCESS;
+
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    TSDebug("protocol", "nbytes %d, ndone %d", TSVIONBytesGet(vio), TSVIONDoneGet(vio));
+    /* Since the first write is through TSVConnWrite, which aleady consume
+       the data in cache_buffer_reader, don't consume it again. */
+    if (txn_sm->q_cache_response_length > 0 && txn_sm->q_block_bytes_read > 0)
+      TSIOBufferReaderConsume(txn_sm->q_cache_response_buffer_reader, txn_sm->q_block_bytes_read);
+
+    txn_sm->q_cache_response_length += TSVIONBytesGet(vio);
+
+    /* If not all data have been read in, we have to reenable the read_vio */
+    if (txn_sm->q_server_vc != NULL) {
+      TSDebug("protocol", "re-enable server_read_vio");
+      TSVIOReenable(txn_sm->q_server_read_vio);
+      return TS_SUCCESS;
+    }
+
+    if (txn_sm->q_cache_response_length >= txn_sm->q_server_response_length) {
+      /* Write is complete, close the cache_vc. */
+      TSDebug("protocol", "close cache_vc, cache_response_length is %d, server_response_lenght is %d",
+               txn_sm->q_cache_response_length, txn_sm->q_server_response_length);
+      TSVConnClose(txn_sm->q_cache_vc);
+      txn_sm->q_cache_vc = NULL;
+      txn_sm->q_cache_write_vio = NULL;
+      TSIOBufferReaderFree(txn_sm->q_cache_response_buffer_reader);
+
+      /* Open cache_vc to read data and send to client. */
+      set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_handle_cache_lookup);
+      txn_sm->q_pending_action = TSCacheRead(contp, txn_sm->q_key);
+    } else {                    /* not done with writing into cache */
+
+      TSDebug("protocol", "re-enable cache_write_vio");
+      TSVIOReenable(txn_sm->q_cache_write_vio);
+    }
+    return TS_SUCCESS;
+  default:
+    break;
+  }
+
+  /* Something wrong if getting here. */
+  return prepare_to_die(contp);
+}
+
+/* If the response has been fully written into the client_vc,
+   which means this txn is done, close the client_vc. Otherwise,
+   reenable the write_vio. */
+int
+state_send_response_to_client(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_send_response_to_client");
+
+  switch (event) {
+  case TS_EVENT_VCONN_WRITE_READY:
+    TSDebug("protocol", " . wr ready");
+    TSDebug("protocol", "write_ready: nbytes %d, ndone %d", TSVIONBytesGet(vio), TSVIONDoneGet(vio));
+    TSVIOReenable(txn_sm->q_client_write_vio);
+    break;
+
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    TSDebug("protocol", " . wr complete");
+    TSDebug("protocol", "write_complete: nbytes %d, ndone %d", TSVIONBytesGet(vio), TSVIONDoneGet(vio));
+    /* Finished sending all data to client, close client_vc. */
+    if (txn_sm->q_client_vc) {
+      TSVConnClose(txn_sm->q_client_vc);
+      txn_sm->q_client_vc = NULL;
+    }
+    txn_sm->q_client_read_vio = NULL;
+    txn_sm->q_client_write_vio = NULL;
+
+    return state_done(contp, 0, NULL);
+
+  default:
+    TSDebug("protocol", " . default handler");
+    return prepare_to_die(contp);
+
+  }
+
+  TSDebug("protocol", "leaving send_response_to_client");
+
+  return TS_SUCCESS;
+}
+
+
+/* There is something wrong, abort client, server and cache vc
+   if they exist. */
+int
+prepare_to_die(TSCont contp)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter prepare_to_die");
+  if (txn_sm->q_client_vc) {
+    TSVConnAbort(txn_sm->q_client_vc, 1);
+    txn_sm->q_client_vc = NULL;
+  }
+  txn_sm->q_client_read_vio = NULL;
+  txn_sm->q_client_write_vio = NULL;
+
+  if (txn_sm->q_server_vc) {
+    TSVConnAbort(txn_sm->q_server_vc, 1);
+    txn_sm->q_server_vc = NULL;
+  }
+  txn_sm->q_server_read_vio = NULL;
+  txn_sm->q_server_write_vio = NULL;
+
+  if (txn_sm->q_cache_vc) {
+    TSVConnAbort(txn_sm->q_cache_vc, 1);
+    txn_sm->q_cache_vc = NULL;
+  }
+  txn_sm->q_cache_read_vio = NULL;
+  txn_sm->q_cache_write_vio = NULL;
+
+  return state_done(contp, 0, NULL);
+}
+
+int
+state_done(TSCont contp, TSEvent event, TSVIO vio)
+{
+  TxnSM *txn_sm = (TxnSM *) TSContDataGet(contp);
+
+  TSDebug("protocol", "enter state_done");
+
+  if (txn_sm->q_pending_action && !TSActionDone(txn_sm->q_pending_action)) {
+    TSDebug("protocol", "cancelling pending action %p", txn_sm->q_pending_action);
+    TSActionCancel(txn_sm->q_pending_action);
+  } else if (txn_sm->q_pending_action) {
+    TSDebug("protocol", "action is done %p", txn_sm->q_pending_action);
+  }
+
+  txn_sm->q_pending_action = NULL;
+  txn_sm->q_mutex = NULL;
+
+  if (txn_sm->q_client_request_buffer) {
+    if (txn_sm->q_client_request_buffer_reader)
+      TSIOBufferReaderFree(txn_sm->q_client_request_buffer_reader);
+    TSIOBufferDestroy(txn_sm->q_client_request_buffer);
+    txn_sm->q_client_request_buffer = NULL;
+    txn_sm->q_client_request_buffer_reader = NULL;
+  }
+
+  if (txn_sm->q_client_response_buffer) {
+    if (txn_sm->q_client_response_buffer_reader)
+      TSIOBufferReaderFree(txn_sm->q_client_response_buffer_reader);
+
+    TSIOBufferDestroy(txn_sm->q_client_response_buffer);
+    txn_sm->q_client_response_buffer = NULL;
+    txn_sm->q_client_response_buffer_reader = NULL;
+  }
+
+  if (txn_sm->q_cache_read_buffer) {
+    if (txn_sm->q_cache_read_buffer_reader)
+      TSIOBufferReaderFree(txn_sm->q_cache_read_buffer_reader);
+    TSIOBufferDestroy(txn_sm->q_cache_read_buffer);
+    txn_sm->q_cache_read_buffer = NULL;
+    txn_sm->q_cache_read_buffer_reader = NULL;
+  }
+
+  if (txn_sm->q_server_request_buffer) {
+    if (txn_sm->q_server_request_buffer_reader)
+      TSIOBufferReaderFree(txn_sm->q_server_request_buffer_reader);
+    TSIOBufferDestroy(txn_sm->q_server_request_buffer);
+    txn_sm->q_server_request_buffer = NULL;
+    txn_sm->q_server_request_buffer_reader = NULL;
+  }
+
+  if (txn_sm->q_server_response_buffer) {
+    TSIOBufferDestroy(txn_sm->q_server_response_buffer);
+    txn_sm->q_server_response_buffer = NULL;
+  }
+
+  if (txn_sm->q_server_name) {
+    TSfree(txn_sm->q_server_name);
+    txn_sm->q_server_name = NULL;
+  }
+
+  if (txn_sm->q_file_name) {
+    TSfree(txn_sm->q_file_name);
+    txn_sm->q_file_name = NULL;
+  }
+
+  if (txn_sm->q_key)
+    TSCacheKeyDestroy(txn_sm->q_key);
+
+  if (txn_sm->q_client_request) {
+    TSfree(txn_sm->q_client_request);
+    txn_sm->q_client_request = NULL;
+  }
+
+  if (txn_sm->q_server_response) {
+    TSfree(txn_sm->q_server_response);
+    txn_sm->q_server_response = NULL;
+  }
+
+  if (txn_sm) {
+    txn_sm->q_magic = TXN_SM_DEAD;
+    TSfree(txn_sm);
+  }
+  TSContDestroy(contp);
+  return TS_EVENT_NONE;
+}
+
+/* Write the data into the client_vc. */
+int
+send_response_to_client(TSCont contp)
+{
+  TxnSM *txn_sm;
+  int response_len;
+
+  TSDebug("protocol", "enter send_response_to_client");
+
+  txn_sm = (TxnSM *) TSContDataGet(contp);
+  response_len = TSIOBufferReaderAvail(txn_sm->q_client_response_buffer_reader);
+
+  TSDebug("protocol", " . resp_len is %d, response_len");
+
+  set_handler(txn_sm->q_current_handler, (TxnSMHandler)&state_interface_with_client);
+  txn_sm->q_client_write_vio = TSVConnWrite(txn_sm->q_client_vc, (TSCont) contp,
+                                             txn_sm->q_client_response_buffer_reader, response_len);
+  return TS_SUCCESS;
+}
+
+/* Read data out through the_reader and save it in a char buffer. */
+char *
+get_info_from_buffer(TSIOBufferReader the_reader)
+{
+  char *info;
+  char *info_start;
+
+  int64_t read_avail, read_done;
+  TSIOBufferBlock blk;
+  char *buf;
+
+  if (!the_reader)
+    return NULL;
+
+  read_avail = TSIOBufferReaderAvail(the_reader);
+
+  info = (char *) TSmalloc(sizeof(char) * read_avail);
+  if (info == NULL)
+    return NULL;
+  info_start = info;
+
+  /* Read the data out of the reader */
+  while (read_avail > 0) {
+    blk = TSIOBufferReaderStart(the_reader);
+    buf = (char *) TSIOBufferBlockReadStart(blk, the_reader, &read_done);
+    memcpy(info, buf, read_done);
+    if (read_done > 0) {
+      TSIOBufferReaderConsume(the_reader, read_done);
+      read_avail -= read_done;
+      info += read_done;
+    }
+  }
+
+  return info_start;
+}
+
+/* Check if the end token is in the char buffer. */
+int
+is_request_end(char *buf)
+{
+  char *temp = strstr(buf, " \n\n");
+  if (!temp)
+    return 0;
+  return 1;
+}
+
+/* Parse the server_name and file name from the request. */
+int
+parse_request(char *request, char *server_name, char *file_name)
+{
+  char *temp = strtok(request, " ");
+  if (temp != NULL)
+    strcpy(server_name, temp);
+  else
+    return 0;
+
+  temp = strtok(NULL, " ");
+  if (temp != NULL)
+    strcpy(file_name, temp);
+  else
+    return 0;
+
+  return 1;
+}
+
+/* Create 128-bit cache key based on the input string, in this case,
+   the file_name of the requested doc. */
+TSCacheKey
+CacheKeyCreate(char *file_name)
+{
+  TSCacheKey key;
+
+  /* TSCacheKeyCreate is to allocate memory space for the key */
+  key = TSCacheKeyCreate();
+
+  /* TSCacheKeyDigestSet is to compute TSCackeKey from the input string */
+  TSCacheKeyDigestSet(key, file_name, strlen(file_name));
+  return key;
+}
diff --git a/example/protocol/TxnSM.h b/example/protocol/TxnSM.h
new file mode 100644
index 00000000..93996636
--- /dev/null
+++ b/example/protocol/TxnSM.h
@@ -0,0 +1,85 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#ifndef TXN_SM_H
+#define TXN_SM_H
+
+#include "Protocol.h"
+
+typedef int (*TxnSMHandler) (TSCont contp, TSEvent event, void *data);
+
+TSCont TxnSMCreate(TSMutex pmutex, TSVConn client_vc, int server_port);
+
+#define TXN_SM_ALIVE 0xAAAA0123
+#define TXN_SM_DEAD  0xFEE1DEAD
+#define TXN_SM_ZERO  0x00001111
+
+/* The Txn State Machine */
+typedef struct _TxnSM
+{
+  unsigned int q_magic;
+
+  TSMutex q_mutex;
+  TSAction q_pending_action;
+  TxnSMHandler q_current_handler;
+
+  TSVConn q_client_vc;
+  TSVConn q_server_vc;
+
+  char *q_client_request;
+  char *q_server_response;
+
+  char *q_file_name;
+  TSCacheKey q_key;
+
+  char *q_server_name;
+  uint32_t q_server_ip;
+  int q_server_port;
+
+  TSVIO q_client_read_vio;
+  TSVIO q_client_write_vio;
+  TSIOBuffer q_client_request_buffer;
+  TSIOBuffer q_client_response_buffer;
+  TSIOBufferReader q_client_request_buffer_reader;
+  TSIOBufferReader q_client_response_buffer_reader;
+
+  TSVIO q_server_read_vio;
+  TSVIO q_server_write_vio;
+  TSIOBuffer q_server_request_buffer;
+  TSIOBuffer q_server_response_buffer;
+  TSIOBufferReader q_server_request_buffer_reader;
+  int q_server_response_length;
+  int q_block_bytes_read;
+  int q_cache_response_length;
+
+  /* Cache related */
+  TSVConn q_cache_vc;
+  TSIOBufferReader q_cache_response_buffer_reader;
+  TSVIO q_cache_read_vio;
+  TSVIO q_cache_write_vio;
+  TSIOBuffer q_cache_read_buffer;
+  TSIOBufferReader q_cache_read_buffer_reader;
+
+} TxnSM;
+
+#endif /* Txn_SM_H */
diff --git a/example/protocol/test/ProtocolClientTest.java b/example/protocol/test/ProtocolClientTest.java
new file mode 100644
index 00000000..71cfecc6
--- /dev/null
+++ b/example/protocol/test/ProtocolClientTest.java
@@ -0,0 +1,198 @@
+//  Licensed to the Apache Software Foundation (ASF) under one
+//  or more contributor license agreements.  See the NOTICE file
+//  distributed with this work for additional information
+//  regarding copyright ownership.  The ASF licenses this file
+//  to you under the Apache License, Version 2.0 (the
+//  "License"); you may not use this file except in compliance
+//  with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
+import java.util.*;
+import java.io.*;
+import java.net.*;
+
+class ProtocolClient
+{
+  protected String host;
+  protected String proxy;
+  protected int port;
+  
+  // Constructor
+  public ProtocolClient(String host, String proxy, int port)
+  {
+    this.host = host;
+    this.proxy = proxy;
+    this.port = port;
+  }// End of constructor
+  
+  // Method connect()
+  public void connect(String fileName)
+  {
+    try
+      {
+	Socket client = new Socket(proxy, port);
+	
+	// Create output stream and input stream
+	BufferedInputStream inStream = new BufferedInputStream(client.getInputStream());
+	BufferedOutputStream outStream = new BufferedOutputStream(client.getOutputStream());
+	
+	// send out request
+	byte[] request = marshalRequest (fileName);
+	outStream.write (request);
+	outStream.flush ();
+
+	// Print out response, actually pattern mapping can be done here
+	// to verify the response is correct.
+	String responseBody = unmarshalResponse (inStream);
+	System.out.println(responseBody);
+	
+	// Close socket
+	client.close();
+      } catch (UnknownHostException uhe) {
+	//System.out.println("Unknown host " + host);
+	uhe.printStackTrace();
+      } catch (IOException ioe) {
+	//System.out.println("IOException " + ioe);
+	ioe.printStackTrace();
+      } catch (Exception e) {
+	e.printStackTrace();
+      }
+      
+  }// End of connect()
+
+  protected byte[] marshalRequest (String fileName) throws Exception
+  {
+    String requestStr = new String();
+    requestStr = requestStr.concat (host);
+    requestStr = requestStr.concat (" ");
+    requestStr = requestStr.concat (fileName);
+    requestStr = requestStr.concat (" \r\n\r\n");
+
+    System.out.println (requestStr);
+
+    byte[] request = requestStr.getBytes();
+    return request;
+  }
+
+  protected String unmarshalResponse (BufferedInputStream responseStream) throws Exception
+  {
+    byte[] newObject = new byte[0];
+    byte[] oldObject = new byte[0];
+    byte[] buffer = new byte[1024];
+    int bytesRead = 0;
+    while ((bytesRead = responseStream.read(buffer)) != -1)
+      {
+	oldObject = newObject;
+	newObject = new byte[oldObject.length + bytesRead];
+	for (int i = 0; i < oldObject.length; i++)
+	  newObject[i] = oldObject[i];
+	for (int i = 0; i < bytesRead; i++)
+	  newObject[oldObject.length + i] = buffer[i];
+      }
+    
+    String responseBody = new String (newObject);
+    return responseBody;
+  }
+
+}// End of class
+
+//*******************************************************
+// Test of ProtocolClient 
+//*******************************************************
+
+public class ProtocolClientTest
+{
+  public static void main(String[] args)
+  {
+    // default setting
+    String host = "localhost";
+    String proxy = "localhost";
+    String fileName = null;
+    int port = 4665;
+    int loop = 1;
+    int pipeline = 1;
+
+
+    for (int i = 0; i < args.length; i++)
+      {
+	if (args[i].equals("-P") == true && (i + 1) < args.length)
+	  {
+	    proxy = args[i + 1];
+	    i ++;
+	  }
+	if (args[i].equals("-p") == true && (i + 1) < args.length)
+	  {
+	    port = Integer.parseInt (args[i + 1]);
+	    i ++;
+	  }
+	if (args[i].equals("-s") == true && (i + 1) < args.length)
+	  {
+	    host = args[i + 1];
+	    i ++;
+	  }
+	if (args[i].equals("-f") == true && (i + 1) < args.length)
+	  {
+	    fileName = args[i + 1];
+	    i ++;
+	  }
+	if (args[i].equals("-c") == true && (i + 1) < args.length)
+	  {
+	    pipeline = Integer.parseInt (args[i + 1]);
+	    i ++;
+	  }
+	if (args[i].equals("-l") == true && (i + 1) < args.length)
+	  {
+	    loop = Integer.parseInt (args[i + 1]);
+	    i ++;
+	  }
+      }
+    
+
+    Vector fileVector = new Vector ();
+    File sourceFile = new File (fileName);
+
+    if (!sourceFile.canRead ())
+      {
+	System.out.println("Usage: input file doesn't exist");
+      }
+    else
+      {
+	try
+	  {
+	    LineNumberReader sourceFileReader = 
+	      new LineNumberReader (new FileReader (sourceFile));
+	    
+	    // Read fileNames from the file.
+	    String currentFileName;
+	    
+	    while ((currentFileName = sourceFileReader.readLine()) != null)
+		fileVector.addElement (currentFileName);
+	  }
+	catch (IOException ioe)
+	  {
+	    ioe.printStackTrace();
+	  }
+	catch (Exception e)
+	  {
+	    e.printStackTrace();
+	  }
+      }
+
+    // Call ProtocolClient and make connection to server through socket.
+    for (int i = 0; i < loop; i++)
+      {
+	for (int j = 0; j < fileVector.size(); j++)
+	  {
+	    ProtocolClient protocolClient = new ProtocolClient(host, proxy, port);
+	    protocolClient.connect(fileVector.elementAt(j).toString());
+	  }
+      }
+  } // End of main function
+}// End of class
diff --git a/example/protocol/test/ProtocolServerTest.java b/example/protocol/test/ProtocolServerTest.java
new file mode 100644
index 00000000..8dd31930
--- /dev/null
+++ b/example/protocol/test/ProtocolServerTest.java
@@ -0,0 +1,181 @@
+//  Licensed to the Apache Software Foundation (ASF) under one
+//  or more contributor license agreements.  See the NOTICE file
+//  distributed with this work for additional information
+//  regarding copyright ownership.  The ASF licenses this file
+//  to you under the Apache License, Version 2.0 (the
+//  "License"); you may not use this file except in compliance
+//  with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+class ProtocolServer extends Thread
+{
+  protected ServerSocket listener = null;
+  protected static ProtocolServer instance = null;
+
+  public ProtocolServer (int port)
+  {
+    try
+      {
+	listener = new ServerSocket(port);
+      }
+    catch(IOException ioe)
+      {
+	ioe.printStackTrace();
+      }
+  }
+  
+  public synchronized void run ()
+  {
+    while (true)
+      {
+	try
+	  {
+	    Socket socket = listener.accept();
+	    new ProtocolRequestHandler(socket).start();
+	  }
+	catch (IOException ioe)
+	  {
+	    ioe.printStackTrace();
+	  }
+      }
+  }
+
+  public static ProtocolServer getInstance (int port)
+  {
+    if (instance == null)
+      {
+	instance = new ProtocolServer (port);
+      }
+    return instance;
+  }
+}// end of class ProtocolServer
+
+class ProtocolRequestHandler extends Thread
+{
+  protected Socket socket = null;
+  protected String requestBody;
+
+  // constructor
+  public ProtocolRequestHandler (Socket socket)
+  {
+    this.socket = socket;
+  }
+
+  public synchronized void run ()
+  {
+    try 
+      {
+	// unmarshal the request
+	System.out.println ("call unmarshalRequest");
+	requestBody = unmarshalRequest();
+
+	// marshal the response
+	System.out.println ("call marshalResponse");
+	byte[] response = marshalResponse (requestBody);
+
+	// send the response
+	if (response != null)
+	  {
+	    BufferedOutputStream responseStream =
+	      new BufferedOutputStream(socket.getOutputStream());
+	    responseStream.write (response);
+	    responseStream.flush ();
+	  }
+	// close the socket
+	System.out.println("close socket");
+	socket.close ();
+      }
+    catch (Exception e)
+      {
+	e.printStackTrace();
+	try
+	  {
+	    socket.close ();
+	  }
+	catch (Exception socke)
+	  {
+	    socke.printStackTrace();
+	  }
+      }
+  }
+
+  protected String unmarshalRequest() throws Exception
+  { 
+    BufferedReader requestReader =
+      new BufferedReader (new InputStreamReader(socket.getInputStream()));
+    
+    String request = requestReader.readLine();
+    requestReader.readLine();
+    System.out.println ("request is " + request);
+
+    StringTokenizer tok = new StringTokenizer (request, " ");
+    String host = tok.nextToken();
+    String fileName = tok.nextToken();
+
+    return fileName;
+  }
+
+  protected byte[] marshalResponse(String requestBody) throws Exception
+  {
+    byte[] responseBody;
+
+    // find the file corresponding to the file name defined in requestBody
+    File responseFile = new File (requestBody);
+    if (responseFile.canRead())
+      {
+	FileInputStream responseFileStream = 
+	  new FileInputStream (responseFile);
+
+	// read data from the file.
+	int bytesRead = 0;
+	byte[] buffer = new byte[1024];
+	responseBody = new byte[0];
+	byte[] temp = new byte[0];
+ 	while ((bytesRead = responseFileStream.read (buffer)) != -1)
+	  {
+	    temp = responseBody;
+	    responseBody = new byte[temp.length + bytesRead];
+	    for (int i = 0; i < temp.length; i++)
+	      responseBody[i] = temp[i];
+	    for (int i = 0; i < bytesRead; i++)
+	      responseBody[temp.length + i] = buffer[i];
+	  }	
+      }
+    else
+      {
+	//String errorMessage = new String ("Error reading " + requestBody);
+	//responseBody = new byte[1024];
+	//responseBody = errorMessage.getBytes();
+	return null;
+      }
+    System.out.println (new String(responseBody));
+    return responseBody;
+  }
+}// end of class ProtocolRequestHandler
+
+
+public class ProtocolServerTest
+{
+    public static void main(String[] args)
+    {
+        int port = 8175;
+        if(args.length > 0)
+            port = Integer.parseInt(args[0]); 
+
+        // Call networkClient and make connection to server through socket.
+        ProtocolServer protocolServer = ProtocolServer.getInstance (port);
+        protocolServer.start();
+    }
+}// End of class
+
diff --git a/example/protocol/test/file_gen.sh b/example/protocol/test/file_gen.sh
new file mode 100644
index 00000000..3a8f523f
--- /dev/null
+++ b/example/protocol/test/file_gen.sh
@@ -0,0 +1,25 @@
+#!/bin/ksh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+#
+# build source list remove "non-source" file types.
+#
+find ../../../../../proxy -depth -type f -print | egrep "Makefile$|\.cpp$|\.cc$|\.c$|\.H$|\.h$|\.java$|\.config$|\.y$" > $1
+
+echo "list created: " $1
diff --git a/example/query_remap/Makefile.am b/example/query_remap/Makefile.am
new file mode 100644
index 00000000..a4b233ae
--- /dev/null
+++ b/example/query_remap/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = query_remap.la
+query_remap_la_SOURCES = query_remap.c
+query_remap_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/query_remap.so
diff --git a/example/query_remap/Makefile.in b/example/query_remap/Makefile.in
new file mode 100644
index 00000000..e564c929
--- /dev/null
+++ b/example/query_remap/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/query_remap
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+query_remap_la_LIBADD =
+am_query_remap_la_OBJECTS = query_remap.lo
+query_remap_la_OBJECTS = $(am_query_remap_la_OBJECTS)
+query_remap_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(query_remap_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(query_remap_la_SOURCES)
+DIST_SOURCES = $(query_remap_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = query_remap.la
+query_remap_la_SOURCES = query_remap.c
+query_remap_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/query_remap/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/query_remap/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+query_remap.la: $(query_remap_la_OBJECTS) $(query_remap_la_DEPENDENCIES) 
+	$(query_remap_la_LINK) -rpath $(pkglibdir) $(query_remap_la_OBJECTS) $(query_remap_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/query_remap.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/query_remap.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/query_remap/query_remap.c b/example/query_remap/query_remap.c
new file mode 100644
index 00000000..5df923a9
--- /dev/null
+++ b/example/query_remap/query_remap.c
@@ -0,0 +1,187 @@
+/** @file
+
+  A sample plugin to remap requests based on a query parameter
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+*/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define PLUGIN_NAME "query_remap"
+
+/* function prototypes */
+uint32_t hash_fnv32(char *buf, size_t len);
+
+typedef struct _query_remap_info {
+  char *param_name;
+  size_t param_len;
+  char **hosts;
+  int num_hosts;
+} query_remap_info;
+
+
+int
+TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
+{
+  /* Called at TS startup. Nothing needed for this plugin */
+  TSDebug(PLUGIN_NAME , "remap plugin initialized");
+  return 0;
+}
+
+
+int
+TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size)
+{
+  /* Called for each remap rule using this plugin. The parameters are parsed here */
+  int i;
+  TSDebug(PLUGIN_NAME, "new instance fromURL: %s toURL: %s", argv[0], argv[1]);
+
+  if (argc < 4) {
+    TSError("Missing parameters for " PLUGIN_NAME);
+    return -1;
+  }
+
+  /* initialize the struct to store info about this remap instance
+     the argv parameters are:
+       0: fromURL
+       1: toURL
+       2: query param to hash
+       3,4,... : server hostnames
+  */
+  query_remap_info *qri = (query_remap_info*) TSmalloc(sizeof(query_remap_info));
+
+  qri->param_name = TSstrdup(argv[2]);
+  qri->param_len = strlen(qri->param_name);
+  qri->num_hosts = argc - 3;
+  qri->hosts = (char**) TSmalloc(qri->num_hosts*sizeof(char*));
+
+  TSDebug(PLUGIN_NAME, " - Hash using query parameter [%s] with %d hosts",
+           qri->param_name, qri->num_hosts);
+
+  for (i=0; i < qri->num_hosts; ++i) {
+    qri->hosts[i] = TSstrdup(argv[i+3]);
+    TSDebug(PLUGIN_NAME, " - Host %d: %s", i, qri->hosts[i]);
+  }
+
+  *ih = (void*)qri;
+  TSDebug(PLUGIN_NAME, "created instance %p", *ih);
+  return 0;
+}
+
+void
+TSRemapDeleteInstance(void* ih)
+{
+  /* Release instance memory allocated in TSRemapNewInstance */
+  int i;
+  TSDebug(PLUGIN_NAME, "deleting instance %p", ih);
+
+  if (ih) {
+    query_remap_info *qri = (query_remap_info*)ih;
+    if (qri->param_name)
+      TSfree(qri->param_name);
+    if (qri->hosts) {
+      for (i=0; i < qri->num_hosts; ++i) {
+        TSfree(qri->hosts[i]);
+      }
+      TSfree(qri->hosts);
+    }
+    TSfree(qri);
+  }
+}
+
+
+TSRemapStatus
+TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
+{
+  int hostidx = -1;
+  query_remap_info *qri = (query_remap_info*)ih;
+
+  if (!qri || !rri) {
+    TSError(PLUGIN_NAME "NULL private data or RRI");
+    return TSREMAP_NO_REMAP;
+  }
+
+  int req_query_len;
+  const char* req_query = TSUrlHttpQueryGet(rri->requestBufp, rri->requestUrl, &req_query_len);
+  
+  if (req_query && req_query_len > 0) {
+    char *q, *key;
+    char *s = NULL;
+
+    /* make a copy of the query, as it is read only */
+    q = (char*) TSmalloc(req_query_len+1);
+    strncpy(q, req_query, req_query_len);
+    q[req_query_len] = '\0';
+
+    /* parse query parameters */
+    for (key = strtok_r(q, "&", &s); key != NULL;) {
+      char *val = strchr(key, '=');
+      if (val && (size_t)(val-key) == qri->param_len &&
+          !strncmp(key, qri->param_name, qri->param_len)) {
+        ++val;
+        /* the param key matched the configured param_name
+           hash the param value to pick a host */
+        hostidx = hash_fnv32(val, strlen(val)) % (uint32_t)qri->num_hosts;
+        TSDebug(PLUGIN_NAME, "modifying host based on %s", key);
+        break;
+      }
+      key = strtok_r(NULL, "&", &s);
+    }
+
+    TSfree(q);
+
+    if (hostidx >= 0) {
+      int req_host_len;
+      /* TODO: Perhaps use TSIsDebugTagSet() before calling TSUrlHostGet()... */
+      const char* req_host = TSUrlHostGet(rri->requestBufp, rri->requestUrl, &req_host_len);
+
+      if (TSUrlHostSet(rri->requestBufp, rri->requestUrl, qri->hosts[hostidx], strlen(qri->hosts[hostidx])) != TS_SUCCESS) {
+        TSDebug(PLUGIN_NAME, "Failed to modify the Host in request URL");
+        return TSREMAP_NO_REMAP;
+      }
+      TSDebug(PLUGIN_NAME, "host changed from [%.*s] to [%s]", req_host_len, req_host, qri->hosts[hostidx]);
+      return TSREMAP_DID_REMAP; /* host has been modified */
+    }
+  }
+
+  /* the request was not modified, TS will use the toURL from the remap rule */
+  TSDebug(PLUGIN_NAME, "request not modified");
+  return TSREMAP_NO_REMAP;
+}
+
+
+/* FNV (Fowler/Noll/Vo) hash
+   (description: http://www.isthe.com/chongo/tech/comp/fnv/index.html) */
+uint32_t
+hash_fnv32(char *buf, size_t len)
+{
+  uint32_t hval = (uint32_t)0x811c9dc5; /* FNV1_32_INIT */
+
+  for (; len > 0; --len) {
+    hval *= (uint32_t)0x01000193;  /* FNV_32_PRIME */
+    hval ^= (uint32_t)*buf++;
+  }
+
+  return hval;
+}
+
diff --git a/example/redirect-1/Makefile.am b/example/redirect-1/Makefile.am
new file mode 100644
index 00000000..804fb056
--- /dev/null
+++ b/example/redirect-1/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = redirect-1.la
+redirect_1_la_SOURCES = redirect-1.c
+redirect_1_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/redirect-1.so
diff --git a/example/redirect-1/Makefile.in b/example/redirect-1/Makefile.in
new file mode 100644
index 00000000..800522c4
--- /dev/null
+++ b/example/redirect-1/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/redirect-1
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+redirect_1_la_LIBADD =
+am_redirect_1_la_OBJECTS = redirect-1.lo
+redirect_1_la_OBJECTS = $(am_redirect_1_la_OBJECTS)
+redirect_1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(redirect_1_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(redirect_1_la_SOURCES)
+DIST_SOURCES = $(redirect_1_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = redirect-1.la
+redirect_1_la_SOURCES = redirect-1.c
+redirect_1_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/redirect-1/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/redirect-1/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+redirect-1.la: $(redirect_1_la_OBJECTS) $(redirect_1_la_DEPENDENCIES) 
+	$(redirect_1_la_LINK) -rpath $(pkglibdir) $(redirect_1_la_OBJECTS) $(redirect_1_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redirect-1.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/redirect-1.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/redirect-1/readme.txt b/example/redirect-1/readme.txt
new file mode 100644
index 00000000..b4bcca26
--- /dev/null
+++ b/example/redirect-1/readme.txt
@@ -0,0 +1,10 @@
+About redirect-1.c
+
+This plugin redirects requests from a specified IP address ("block_ip")
+to a specified URL ("url_redirect").
+
+Specify block_ip and url_redirect int the plugin.config file; for 
+example, enter the following line in plugin.config
+
+	On NT:	Redirect.dll block_ip url_redirect 
+	On Solaris: redirect-1.so block_ip url_redirect 
diff --git a/example/redirect-1/redirect-1.c b/example/redirect-1/redirect-1.c
new file mode 100644
index 00000000..8d40c875
--- /dev/null
+++ b/example/redirect-1/redirect-1.c
@@ -0,0 +1,436 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+ *   redirect-1.c:
+ *	an example program which redirects clients based on the source IP
+ *
+ *
+ *	Usage:
+ * 	(NT): Redirect.dll block_ip url_redirect
+ * 	(Solaris): redirect-1.so block_ip url_redirect
+ *
+ *
+ */
+
+#include 
+#include 
+
+#if !defined (_WIN32)
+#  include 
+#  include 
+#  include 
+#else
+#  include 
+#endif
+
+#include 
+
+#if !defined (_WIN32)
+static in_addr_t ip_deny;
+#else
+static unsigned int ip_deny;
+#endif
+
+/*
+ * uncoupled statistics variables:
+ */
+static INKStat method_count_redirected_connect;
+static INKStat method_count_redirected_delete;
+static INKStat method_count_redirected_get;
+static INKStat method_count_redirected_head;
+static INKStat method_count_redirected_icp_query;
+static INKStat method_count_redirected_options;
+static INKStat method_count_redirected_post;
+static INKStat method_count_redirected_purge;
+static INKStat method_count_redirected_put;
+static INKStat method_count_redirected_trace;
+static INKStat method_count_redirected_unknown;
+
+
+/*
+ *	coupled statistics variables:
+ *		coupled stat category for the following stats
+ *              is request_outcomes. The relationship among the stats is:
+ *		requests_all = requests_redirects + requests_unchanged
+ */
+static INKCoupledStat request_outcomes;
+static INKStat requests_all;
+static INKStat requests_redirects;
+static INKStat requests_unchanged;
+
+
+void update_redirected_method_stats(TSMBuffer bufp, TSMLoc hdr_loc);
+
+static char *url_redirect;
+static char *uri_redirect;
+static char *block_ip;
+
+
+static void
+handle_client_lookup(TSHttpTxn txnp, TSCont contp)
+{
+  TSMBuffer bufp;
+  TSMLoc hdr_loc, url_loc;
+  int host_length;
+
+#if !defined (_WIN32)
+  in_addr_t clientip;
+#else
+  unsigned int clientip;
+#endif
+
+  const char *host;
+  char *clientstring;
+  struct in_addr tempstruct;
+
+  /*
+   * Here we declare local coupled statistics variables:
+   */
+  INKCoupledStat local_request_outcomes;
+  INKStat local_requests_all;
+  INKStat local_requests_redirects;
+  INKStat local_requests_unchanged;
+
+  /*
+   *  Create local copy of the global coupled stat category:
+   */
+  local_request_outcomes = INKStatCoupledLocalCopyCreate("local_request_outcomes", request_outcomes);
+
+
+  /*
+   * Create the local copies of the global coupled stats:
+   */
+  local_requests_all = INKStatCoupledLocalAdd(local_request_outcomes, "requests.all.local", INKSTAT_TYPE_FLOAT);
+  local_requests_redirects = INKStatCoupledLocalAdd(local_request_outcomes,
+                                                    "requests.redirects.local", INKSTAT_TYPE_INT64);
+  local_requests_unchanged = INKStatCoupledLocalAdd(local_request_outcomes,
+                                                    "requests.unchanged.local", INKSTAT_TYPE_INT64);
+
+
+  /*
+   *   Increment the count of total requests:
+   *     (it is more natural to treat the number of requests as an
+   *      integer, but we declare this a FLOAT in order to demonstrate
+   *      how to increment coupled FLOAT stats)
+   */
+  INKStatFloatAddTo(local_requests_all, 1.0);
+
+
+#if !defined (_WIN32)
+  clientip = (in_addr_t) TSHttpTxnClientIPGet(txnp);
+#else
+  clientip = TSHttpTxnClientIPGet(txnp);
+#endif
+
+
+  tempstruct.s_addr = clientip;
+  clientstring = inet_ntoa(tempstruct);
+  TSDebug("redirect", "clientip is %s and block_ip is %s", clientstring, block_ip);
+
+  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+    TSError("couldn't retrieve client request header\n");
+    goto done;
+  }
+
+  if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
+    TSError("couldn't retrieve request url\n");
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    goto done;
+  }
+
+  host = TSUrlHostGet(bufp, url_loc, &host_length);
+  if (!host) {
+    TSError("couldn't retrieve request hostname\n");
+    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    goto done;
+  }
+
+  /*
+   *   Check to see if the client is already headed to the redirect site.
+   */
+  if (strncmp(host, url_redirect, host_length) == 0) {
+    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    goto done;
+  }
+
+  if (ip_deny == clientip) {
+    TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
+
+    update_redirected_method_stats(bufp, hdr_loc);
+
+    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+
+    /*
+     *   Increment the local redirect stat and do global update:
+     */
+    INKStatIncrement(local_requests_redirects);
+    INKStatsCoupledUpdate(local_request_outcomes);
+    INKStatCoupledLocalCopyDestroy(local_request_outcomes);
+
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
+    return;
+  }
+
+done:
+  /*
+   * Increment the local number unchanged stat and do global update:
+   */
+  INKStatIncrement(local_requests_unchanged);
+  INKStatsCoupledUpdate(local_request_outcomes);
+  INKStatCoupledLocalCopyDestroy(local_request_outcomes);
+
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+}
+
+
+
+static void
+handle_response(TSHttpTxn txnp)
+{
+  TSMBuffer bufp;
+  TSMLoc hdr_loc, newfield_loc;
+  char *errormsg_body = "All requests from this IP address are redirected.\n";
+  char *tmp_body;
+
+  if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+    TSError("couldn't retrieve client response header\n");
+    goto done;
+  }
+
+  TSHttpHdrStatusSet(bufp, hdr_loc, TS_HTTP_STATUS_MOVED_PERMANENTLY);
+  TSHttpHdrReasonSet(bufp, hdr_loc,
+                      TSHttpHdrReasonLookup(TS_HTTP_STATUS_MOVED_PERMANENTLY),
+                      strlen(TSHttpHdrReasonLookup(TS_HTTP_STATUS_MOVED_PERMANENTLY)));
+
+  TSMimeHdrFieldCreate(bufp, hdr_loc, &newfield_loc); /* Probably should check for errors ... */
+  TSMimeHdrFieldNameSet(bufp, hdr_loc, newfield_loc, TS_MIME_FIELD_LOCATION, TS_MIME_LEN_LOCATION);
+  TSMimeHdrFieldValueStringInsert(bufp, hdr_loc, newfield_loc, -1, uri_redirect, strlen(uri_redirect));
+  TSMimeHdrFieldAppend(bufp, hdr_loc, newfield_loc);
+
+  /*
+   *  Note that we can't directly use errormsg_body, as TSHttpTxnErrorBodySet()
+   *  will try to free the passed buffer with TSfree().
+   */
+  tmp_body = TSstrdup(errormsg_body);
+  TSHttpTxnErrorBodySet(txnp, tmp_body, strlen(tmp_body), NULL);
+  TSHandleMLocRelease(bufp, hdr_loc, newfield_loc);
+  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+
+
+done:
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+}
+
+
+
+static int
+redirect_plugin(TSCont contp, TSEvent event, void *edata)
+{
+
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+
+    handle_client_lookup(txnp, contp);
+    return 0;
+
+  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
+
+    handle_response(txnp);
+    return 0;
+
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+
+
+/*
+ *  Global statistics functions:
+ */
+
+void
+init_stats(void)
+{
+  /* noncoupled: */
+  method_count_redirected_connect = INKStatCreate("method.count.redirected.connect", INKSTAT_TYPE_INT64);
+  method_count_redirected_delete = INKStatCreate("method.count.redirected.delete", INKSTAT_TYPE_INT64);
+  method_count_redirected_get = INKStatCreate("method.count.redirected.get", INKSTAT_TYPE_INT64);
+  method_count_redirected_head = INKStatCreate("method.count.redirected.head", INKSTAT_TYPE_FLOAT);
+  method_count_redirected_icp_query = INKStatCreate("method.count.redirected.icp_query", INKSTAT_TYPE_FLOAT);
+  method_count_redirected_options = INKStatCreate("method.count.redirected.options", INKSTAT_TYPE_INT64);
+  method_count_redirected_post = INKStatCreate("method.count.redirected.post", INKSTAT_TYPE_INT64);
+  method_count_redirected_purge = INKStatCreate("method.count.redirected.purge", INKSTAT_TYPE_INT64);
+  method_count_redirected_put = INKStatCreate("method.count.redirected.put", INKSTAT_TYPE_INT64);
+  method_count_redirected_trace = INKStatCreate("method.count.redirected.trace", INKSTAT_TYPE_INT64);
+  method_count_redirected_unknown = INKStatCreate("method.count.redirected.unknown", INKSTAT_TYPE_INT64);
+
+  /* coupled: */
+  request_outcomes = INKStatCoupledGlobalCategoryCreate("request_outcomes");
+  requests_all = INKStatCoupledGlobalAdd(request_outcomes, "requests.all", INKSTAT_TYPE_FLOAT);
+  requests_redirects = INKStatCoupledGlobalAdd(request_outcomes, "requests.redirects", INKSTAT_TYPE_INT64);
+  requests_unchanged = INKStatCoupledGlobalAdd(request_outcomes, "requests.unchanged", INKSTAT_TYPE_INT64);
+
+}
+
+/*
+ *	This function is only called for redirected requests.  It illustrates
+ *	several different ways of updating INT64 stats.  Some may consider
+ *	the particular use of TSDecrementStat() shown below somewhat contrived.
+ */
+void
+update_redirected_method_stats(TSMBuffer bufp, TSMLoc hdr_loc)
+{
+  const char *txn_method;
+  int length;
+  int64_t tempint;
+
+  txn_method = TSHttpHdrMethodGet(bufp, hdr_loc, &length);
+
+  if (NULL != txn_method) {
+    if (0 == strncmp(txn_method, TS_HTTP_METHOD_CONNECT, length))
+      INKStatIncrement(method_count_redirected_connect);
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_DELETE, length))
+      INKStatIncrement(method_count_redirected_delete);
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_GET, length))
+      INKStatIncrement(method_count_redirected_get);
+
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_HEAD, length))
+      INKStatFloatAddTo(method_count_redirected_head, 1);
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_ICP_QUERY, length))
+      INKStatFloatAddTo(method_count_redirected_icp_query, 1);
+
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_OPTIONS, length)) {
+      tempint = INKStatIntGet(method_count_redirected_options);
+      tempint++;
+      INKStatIntSet(method_count_redirected_options, tempint);
+    } else if (0 == strncmp(txn_method, TS_HTTP_METHOD_POST, length)) {
+      INKStatDecrement(method_count_redirected_post);
+      INKStatIncrement(method_count_redirected_post);
+      INKStatIncrement(method_count_redirected_post);
+    }
+
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_PURGE, length))
+      INKStatIncrement(method_count_redirected_purge);
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_PUT, length))
+      INKStatIncrement(method_count_redirected_put);
+    else if (0 == strncmp(txn_method, TS_HTTP_METHOD_TRACE, length))
+      INKStatIncrement(method_count_redirected_trace);
+    else
+      INKStatIncrement(method_count_redirected_unknown);
+  }
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  const char prefix[] = "http://";
+  int uri_len;
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "redirect-1";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  if (argc == 3) {
+    block_ip = TSstrdup(argv[1]);
+
+    /*
+     *   The Location header must contain an absolute URI:
+     */
+
+    url_redirect = TSstrdup(argv[2]);
+    uri_len = strlen(prefix) + strlen(url_redirect) + 1;
+    uri_redirect = TSmalloc(uri_len);
+    strcpy(uri_redirect, prefix);
+    strcat(uri_redirect, url_redirect);
+
+  } else {
+    TSError("Incorrect syntax in plugin.conf:  correct usage is" "redirect-1.so ip_deny url_redirect");
+    return;
+  }
+
+  ip_deny = inet_addr(block_ip);
+
+  TSDebug("redirect_init", "initializing stats...");
+  init_stats();
+  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, TSContCreate(redirect_plugin, NULL));
+
+  TSDebug("redirect_init", "block_ip is %s, url_redirect is %s, and uri_redirect is %s",
+           block_ip, url_redirect, uri_redirect);
+  TSDebug("redirect_init", "ip_deny is %ld\n", ip_deny);
+
+  /*
+   *  Demonstrate another tracing function.  This can be used to
+   *  enable debug calculations and other work that should only
+   *  be done in debug mode.
+   */
+
+  if (TSIsDebugTagSet("redirect_demo"))
+    TSDebug("redirect_init", "The redirect_demo tag is set");
+  else
+    TSDebug("redirect_init", "The redirect_demo tag is not set");
+}
diff --git a/example/remap/Makefile.am b/example/remap/Makefile.am
new file mode 100644
index 00000000..038684dc
--- /dev/null
+++ b/example/remap/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CXXFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = remap.la
+remap_la_SOURCES = remap.cc
+remap_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/remap.so
diff --git a/example/remap/Makefile.in b/example/remap/Makefile.in
new file mode 100644
index 00000000..43244f5a
--- /dev/null
+++ b/example/remap/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/remap
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+remap_la_LIBADD =
+am_remap_la_OBJECTS = remap.lo
+remap_la_OBJECTS = $(am_remap_la_OBJECTS)
+remap_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(remap_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(remap_la_SOURCES)
+DIST_SOURCES = $(remap_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@ -I$(top_srcdir)/proxy/api
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = remap.la
+remap_la_SOURCES = remap.cc
+remap_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/remap/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/remap/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+remap.la: $(remap_la_OBJECTS) $(remap_la_DEPENDENCIES) 
+	$(remap_la_LINK) -rpath $(pkglibdir) $(remap_la_OBJECTS) $(remap_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remap.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/remap.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/remap/build.txt b/example/remap/build.txt
new file mode 100644
index 00000000..b5bf31ec
--- /dev/null
+++ b/example/remap/build.txt
@@ -0,0 +1,17 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+g++ -D_FILE_OFFSET_BITS=64 -shared -I../../include -I../../.. -I./ -o remap.so remap.cc
diff --git a/example/remap/remap.cc b/example/remap/remap.cc
new file mode 100644
index 00000000..f15158f2
--- /dev/null
+++ b/example/remap/remap.cc
@@ -0,0 +1,376 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* ------------------------------------------------------------------------- */
+/* -                            remap.cc                                   - */
+/* ------------------------------------------------------------------------- */
+// remap.cc - simple remap plugin for YTS
+// g++ -D_FILE_OFFSET_BITS=64 -shared -I./ -o remap.so remap.cc
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#if __GNUC__ >= 3
+#ifndef likely
+#define likely(x)   __builtin_expect (!!(x),1)
+#endif
+#ifndef unlikely
+#define unlikely(x) __builtin_expect (!!(x),0)
+#endif
+#else
+#ifndef likely
+#define likely(x)   (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+#endif /* #if __GNUC__ >= 3 */
+
+class remap_entry
+{
+public:
+  static remap_entry *active_list;
+  static pthread_mutex_t mutex;
+  remap_entry *next;
+  int argc;
+  char **argv;
+    remap_entry(int _argc, char *_argv[]);
+   ~remap_entry();
+  static void add_to_list(remap_entry *re);
+  static void remove_from_list(remap_entry *re);
+};
+
+static int plugin_init_counter = 0;     /* remap plugin initialization counter */
+static pthread_mutex_t remap_plugin_global_mutex;       /* remap plugin global mutex */
+remap_entry *
+  remap_entry::active_list = 0;
+pthread_mutex_t
+  remap_entry::mutex;           /* remap_entry class mutex */
+
+/* ----------------------- remap_entry::remap_entry ------------------------ */
+remap_entry::remap_entry(int _argc, char *_argv[]):
+  next(NULL), argc(0), argv(NULL)
+{
+  int i;
+
+  if (_argc > 0 && _argv && (argv = (char **) malloc(sizeof(char *) * (_argc + 1))) != 0) {
+    argc = _argc;
+    for (i = 0; i < argc; i++)
+      argv[i] = TSstrdup(_argv[i]);
+    argv[i] = NULL;
+  }
+}
+
+/* ---------------------- remap_entry::~remap_entry ------------------------ */
+remap_entry::~remap_entry()
+{
+  int i;
+
+  if (argc && argv) {
+    for (i = 0; i < argc; i++) {
+      if (argv[i])
+        free(argv[i]);
+    }
+    free(argv);
+  }
+}
+
+/* --------------------- remap_entry::add_to_list -------------------------- */
+void
+remap_entry::add_to_list(remap_entry *re)
+{
+  if (likely(re && plugin_init_counter)) {
+    pthread_mutex_lock(&mutex);
+    re->next = active_list;
+    active_list = re;
+    pthread_mutex_unlock(&mutex);
+  }
+}
+
+/* ------------------ remap_entry::remove_from_list ------------------------ */
+void
+remap_entry::remove_from_list(remap_entry *re)
+{
+  remap_entry **rre;
+  if (likely(re && plugin_init_counter)) {
+    pthread_mutex_lock(&mutex);
+    for (rre = &active_list; *rre; rre = &((*rre)->next)) {
+      if (re == *rre) {
+        *rre = re->next;
+        break;
+      }
+    }
+    pthread_mutex_unlock(&mutex);
+  }
+}
+
+/* ----------------------- store_my_error_message -------------------------- */
+static TSReturnCode
+store_my_error_message(TSReturnCode retcode, char *err_msg_buf, int buf_size, const char *fmt, ...)
+{
+  if (likely(err_msg_buf && buf_size > 0 && fmt)) {
+    va_list ap;
+    va_start(ap, fmt);
+    err_msg_buf[0] = 0;
+    (void) vsnprintf(err_msg_buf, buf_size - 1, fmt, ap);
+    err_msg_buf[buf_size - 1] = 0;
+    va_end(ap);
+  }
+  return retcode;               /* error code here */
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+  info.plugin_name = (char*)"remap_plugin";
+  info.vendor_name = (char*)"Apache";
+  info.support_email = (char*)"";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed. \n");
+  }
+  TSDebug("debug-remap", "TSPluginInit: Remap plugin started\n");
+}
+
+// Plugin initialization code. Called immediately after dlopen() Only once!
+// Can perform internal initialization. For example, pthread_.... initialization.
+/* ------------------------- TSRemapInit ---------------------------------- */
+TSReturnCode
+TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
+{
+  fprintf(stderr, "Remap Plugin: TSRemapInit()\n");
+
+  if (!plugin_init_counter) {
+    if (unlikely(!api_info)) {
+      return store_my_error_message(TS_ERROR, errbuf, errbuf_size, "[TSRemapInit] - Invalid TSRemapInterface argument");
+    }
+    if (unlikely(api_info->size < sizeof(TSRemapInterface))) {
+      return store_my_error_message(TS_ERROR, errbuf, errbuf_size,
+                                    "[TSRemapInit] - Incorrect size of TSRemapInterface structure %d. Should be at least %d bytes",
+                                    (int) api_info->size, (int) sizeof(TSRemapInterface));
+    }
+    if (unlikely(api_info->tsremap_version < TSREMAP_VERSION)) {
+      return store_my_error_message(TS_ERROR, errbuf, errbuf_size,
+                                    "[TSRemapInit] - Incorrect API version %d.%d",
+                                    (api_info->tsremap_version >> 16), (api_info->tsremap_version & 0xffff));
+    }
+
+    if (pthread_mutex_init(&remap_plugin_global_mutex, 0) || pthread_mutex_init(&remap_entry::mutex, 0)) {      /* pthread_mutex_init - always returns 0. :) - impossible error */
+      return store_my_error_message(TS_ERROR, errbuf, errbuf_size, "[TSRemapInit] - Mutex initialization error");
+    }
+    plugin_init_counter++;
+  }
+  return TS_SUCCESS;                     /* success */
+}
+
+// Plugin shutdown
+// Optional function.
+/* -------------------------- TSRemapDone --------------------------------- */
+void
+TSRemapDone(void)
+{
+  fprintf(stderr, "Remap Plugin: TSRemapDone()\n");
+}
+
+
+// Plugin new instance for new remapping rule.
+// This function can be called multiple times (depends on remap.config)
+/* ------------------------ TSRemapNewInstance --------------------------- */
+TSReturnCode
+TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size)
+{
+  remap_entry *ri;
+  int i;
+
+
+  fprintf(stderr, "Remap Plugin: TSRemapNewInstance()\n");
+
+  if (argc < 2) {
+    return store_my_error_message(TS_ERROR, errbuf, errbuf_size,
+                                  "[TSRemapNewInstance] - Incorrect number of arguments - %d", argc);
+  }
+  if (!argv || !ih) {
+    return store_my_error_message(TS_ERROR, errbuf, errbuf_size, "[TSRemapNewInstance] - Invalid argument(s)");
+  }
+  // print all arguments for this particular remapping
+  for (i = 0; i < argc; i++) {
+    fprintf(stderr, "[TSRemapNewInstance] - argv[%d] = \"%s\"\n", i, argv[i]);
+  }
+
+  ri = new remap_entry(argc, argv);
+
+  if (!ri) {
+    return store_my_error_message(TS_ERROR, errbuf, errbuf_size, "[TSRemapNewInstance] - Can't create remap_entry class");
+  }
+
+  remap_entry::add_to_list(ri);
+
+  *ih = (void*) ri;
+
+  return TS_SUCCESS;
+}
+
+/* ---------------------- TSRemapDeleteInstance -------------------------- */
+void
+TSRemapDeleteInstance(void* ih)
+{
+  remap_entry *ri = (remap_entry *) ih;
+
+  fprintf(stderr, "Remap Plugin: TSRemapDeleteInstance()\n");
+
+  remap_entry::remove_from_list(ri);
+
+  delete ri;
+}
+
+static volatile unsigned long processing_counter = 0;   // sequential counter
+static int arg_index = 0;
+
+/* -------------------------- TSRemapDoRemap -------------------------------- */
+TSRemapStatus
+TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
+{
+  const char* temp;
+  const char* temp2;
+  int len, len2, port;
+  TSMLoc cfield;
+  unsigned long _processing_counter = ++processing_counter;     // one more function call (in real life use mutex to protect this counter)
+
+  remap_entry *ri = (remap_entry *) ih;
+  fprintf(stderr, "Remap Plugin: TSRemapDoRemap()\n");
+
+  if (!ri || !rri)
+    return TSREMAP_NO_REMAP;                   /* TS must remap this request */
+
+  fprintf(stderr, "[TSRemapDoRemap] From: \"%s\"  To: \"%s\"\n", ri->argv[0], ri->argv[1]);
+
+  temp = TSUrlHostGet(rri->requestBufp, rri->requestUrl, &len);
+  fprintf(stderr, "[TSRemapDoRemap] Request Host(%d): \"%.*s\"\n", len, len, temp);
+
+  temp = TSUrlHostGet(rri->requestBufp, rri->mapToUrl, &len);
+  fprintf(stderr, "[TSRemapDoRemap] Remap To Host: \"%.*s\"\n", len, temp);
+
+  temp = TSUrlHostGet(rri->requestBufp, rri->mapFromUrl, &len);
+  fprintf(stderr, "[TSRemapDoRemap] Remap From Host: \"%.*s\"\n", len, temp);
+
+  fprintf(stderr, "[TSRemapDoRemap] Request Port: %d\n", TSUrlPortGet(rri->requestBufp, rri->requestUrl));
+  fprintf(stderr, "[TSRemapDoRemap] Remap From Port: %d\n", TSUrlPortGet(rri->requestBufp, rri->mapFromUrl));
+  fprintf(stderr, "[TSRemapDoRemap] Remap To Port: %d\n", TSUrlPortGet(rri->requestBufp, rri->mapToUrl));
+
+  temp = TSUrlPathGet(rri->requestBufp, rri->requestUrl, &len);
+  fprintf(stderr, "[TSRemapDoRemap] Request Path: \"%.*s\"\n", len, temp);
+
+  temp = TSUrlPathGet(rri->requestBufp, rri->mapFromUrl, &len);
+  fprintf(stderr, "[TSRemapDoRemap] Remap From Path: \"%.*s\"\n", len, temp);
+
+  temp = TSUrlPathGet(rri->requestBufp, rri->mapToUrl, &len);
+  fprintf(stderr, "[TSRemapDoRemap] Remap To Path: \"%.*s\"\n", len, temp);
+
+  // InkAPI usage case
+  const char *value;
+
+  if ((cfield = TSMimeHdrFieldFind(rri->requestBufp, rri->requestHdrp, TS_MIME_FIELD_DATE, -1)) != TS_NULL_MLOC) {
+    fprintf(stderr, "We have \"Date\" header in request\n");
+    value = TSMimeHdrFieldValueStringGet(rri->requestBufp, rri->requestHdrp, cfield, 0, NULL);
+    fprintf(stderr, "Header value: %s\n", value);
+  }
+  if ((cfield = TSMimeHdrFieldFind(rri->requestBufp, rri->requestHdrp, "MyHeader", sizeof("MyHeader") - 1)) != TS_NULL_MLOC) {
+    fprintf(stderr, "We have \"MyHeader\" header in request\n");
+    value = TSMimeHdrFieldValueStringGet(rri->requestBufp, rri->requestHdrp, cfield, 0, NULL);
+    fprintf(stderr, "Header value: %s\n", value);
+  }
+
+  // How to store plugin private arguments inside Traffic Server request processing block.
+  if (TSHttpArgIndexReserve("remap_example", "Example remap plugin", &arg_index) == TS_SUCCESS) {
+    fprintf(stderr, "[TSRemapDoRemap] Save processing counter %lu inside request processing block\n", _processing_counter);
+    TSHttpTxnArgSet((TSHttpTxn) rh, arg_index, (void *) _processing_counter); // save counter
+  }
+  // How to cancel request processing and return error message to the client
+  // We wiil do it each other request
+  if (_processing_counter & 1) {
+    char tmp[256];
+    static int my_local_counter = 0;
+    snprintf(tmp, sizeof(tmp) - 1,
+             "This is very small example of TS API usage!\nIteration %d!\nHTTP return code %d\n",
+             my_local_counter, TS_HTTP_STATUS_CONTINUE + my_local_counter);
+    TSHttpTxnSetHttpRetStatus((TSHttpTxn) rh, (TSHttpStatus) ((int) TS_HTTP_STATUS_CONTINUE + my_local_counter));   //TS_HTTP_STATUS_SERVICE_UNAVAILABLE); //TS_HTTP_STATUS_NOT_ACCEPTABLE);
+    TSHttpTxnSetHttpRetBody((TSHttpTxn) rh, (const char *) tmp, true);
+    my_local_counter++;
+  }
+  // hardcoded case for remapping
+  // You need to check host and port if you are using the same plugin for multiple remapping rules
+  temp = TSUrlHostGet(rri->requestBufp, rri->requestUrl, &len);
+  temp2 = TSUrlPathGet(rri->requestBufp, rri->requestUrl, &len2);
+  port = TSUrlPortGet(rri->requestBufp, rri->requestUrl);
+
+  if (len == 10 && !memcmp("flickr.com", temp, 10) && port == 80 && len2 >= 3 && !memcmp("47/", temp2, 3)) {
+    char new_path[8192];
+
+    // Ugly, but so is the rest of this "example"
+    if (len2 + 7 >= 8192)
+      return TSREMAP_NO_REMAP;
+
+    if (TSUrlPortSet(rri->requestBufp, rri->mapToUrl, TSUrlPortGet(rri->requestBufp, rri->mapToUrl)) != TS_SUCCESS)
+      return TSREMAP_NO_REMAP;
+
+    if (TSUrlHostSet(rri->requestBufp, rri->requestUrl, "foo.bar.com", 11) != TS_SUCCESS)
+      return TSREMAP_NO_REMAP;
+
+    memcpy(new_path, "47_copy", 7);
+    memcpy(&new_path[7], &temp2[2], len2 - 2);
+
+    if (TSUrlPathSet(rri->requestBufp, rri->requestUrl, new_path, len2 + 5) == TS_SUCCESS)
+      return TSREMAP_DID_REMAP;
+  }
+
+  // Failure ...
+  return TSREMAP_NO_REMAP;
+}
+
+/* ----------------------- TSRemapOSResponse ----------------------------- */
+void
+TSRemapOSResponse(void* ih, TSHttpTxn rh, int os_response_type)
+{
+  int request_id = -1;
+  void *data = TSHttpTxnArgGet((TSHttpTxn) rh, arg_index);  // read counter (we store it in TSRemapDoRemap function call)
+
+  if (data)
+    request_id = *((int*)data);
+  fprintf(stderr, "[TSRemapOSResponse] Read processing counter %d from request processing block\n", request_id);
+  fprintf(stderr, "[TSRemapOSResponse] OS response status: %d\n", os_response_type);
+}
diff --git a/example/replace-header/Makefile.am b/example/replace-header/Makefile.am
new file mode 100644
index 00000000..5927009c
--- /dev/null
+++ b/example/replace-header/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = replace-header.la
+replace_header_la_SOURCES = replace-header.c
+replace_header_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/replace-header.so
diff --git a/example/replace-header/Makefile.in b/example/replace-header/Makefile.in
new file mode 100644
index 00000000..5dec22a8
--- /dev/null
+++ b/example/replace-header/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/replace-header
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+replace_header_la_LIBADD =
+am_replace_header_la_OBJECTS = replace-header.lo
+replace_header_la_OBJECTS = $(am_replace_header_la_OBJECTS)
+replace_header_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(replace_header_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(replace_header_la_SOURCES)
+DIST_SOURCES = $(replace_header_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = replace-header.la
+replace_header_la_SOURCES = replace-header.c
+replace_header_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/replace-header/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/replace-header/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+replace-header.la: $(replace_header_la_OBJECTS) $(replace_header_la_DEPENDENCIES) 
+	$(replace_header_la_LINK) -rpath $(pkglibdir) $(replace_header_la_OBJECTS) $(replace_header_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/replace-header.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/replace-header.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/replace-header/replace-header.c b/example/replace-header/replace-header.c
new file mode 100644
index 00000000..8745f713
--- /dev/null
+++ b/example/replace-header/replace-header.c
@@ -0,0 +1,137 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+ *   replace-header.c:
+ *	an example program...
+ *
+ *
+ *	Usage:
+ *
+ *
+ */
+#include 
+#include 
+#include 
+#include 
+
+static void
+replace_header(TSHttpTxn txnp, TSCont contp)
+{
+  TSMBuffer resp_bufp;
+  TSMLoc resp_loc;
+  TSMLoc field_loc;
+
+  if (!TSHttpTxnServerRespGet(txnp, &resp_bufp, &resp_loc)) {
+    TSError("couldn't retrieve server response header.\n");
+    goto done;
+  }
+
+  field_loc = TSMimeHdrFieldFind(resp_bufp, resp_loc, TS_MIME_FIELD_ACCEPT_RANGES, TS_MIME_LEN_ACCEPT_RANGES);
+  if (field_loc == TS_NULL_MLOC) {
+    /* field was not found */
+
+    /* create a new field in the header */
+    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &field_loc); /* Probably should check for errors. */
+    /* set its name */
+    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, field_loc, TS_MIME_FIELD_ACCEPT_RANGES, TS_MIME_LEN_ACCEPT_RANGES);
+    /* set its value */
+    TSMimeHdrFieldValueAppend(resp_bufp, resp_loc, field_loc, -1, "none", 4);
+    /* insert it into the header */
+    TSMimeHdrFieldAppend(resp_bufp, resp_loc, field_loc);
+    TSHandleMLocRelease(resp_bufp, resp_loc, field_loc);
+    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+  } else {
+    /* clear the field */
+    TSMimeHdrFieldValuesClear(resp_bufp, resp_loc, field_loc);
+    /* set the value to "none" */
+    TSMimeHdrFieldValueStringInsert(resp_bufp, resp_loc, field_loc, -1, "none", 4);
+    TSHandleMLocRelease(resp_bufp, resp_loc, field_loc);
+    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+  }
+
+done:
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+}
+
+static int
+replace_header_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    replace_header(txnp, contp);
+    return 0;
+  default:
+    break;
+  }
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "replace-header";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed. \n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(replace_header_plugin, NULL));
+}
diff --git a/example/response-header-1/Makefile.am b/example/response-header-1/Makefile.am
new file mode 100644
index 00000000..ed650222
--- /dev/null
+++ b/example/response-header-1/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = response-header-1.la
+response_header_1_la_SOURCES = response-header-1.c
+response_header_1_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/response-header-1.so
diff --git a/example/response-header-1/Makefile.in b/example/response-header-1/Makefile.in
new file mode 100644
index 00000000..e8bccc8d
--- /dev/null
+++ b/example/response-header-1/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/response-header-1
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+response_header_1_la_LIBADD =
+am_response_header_1_la_OBJECTS = response-header-1.lo
+response_header_1_la_OBJECTS = $(am_response_header_1_la_OBJECTS)
+response_header_1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(response_header_1_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(response_header_1_la_SOURCES)
+DIST_SOURCES = $(response_header_1_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = response-header-1.la
+response_header_1_la_SOURCES = response-header-1.c
+response_header_1_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/response-header-1/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/response-header-1/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+response-header-1.la: $(response_header_1_la_OBJECTS) $(response_header_1_la_DEPENDENCIES) 
+	$(response_header_1_la_LINK) -rpath $(pkglibdir) $(response_header_1_la_OBJECTS) $(response_header_1_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/response-header-1.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/response-header-1.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/response-header-1/response-header-1.c b/example/response-header-1/response-header-1.c
new file mode 100644
index 00000000..fb85eaea
--- /dev/null
+++ b/example/response-header-1/response-header-1.c
@@ -0,0 +1,333 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+ * response-header-1.c:
+ *		an example program which illustrates adding and manipulating
+ *		an HTTP response MIME header:
+ *
+ *   Authorized possession and use of this software pursuant only
+ *   to the terms of a written license agreement.
+ *
+ *	Usage:	response-header-1.so
+ *
+ *	add read_resp_header hook
+ *	get http response header
+ *	if 200, then
+ *		add mime extension header with count of zero
+ *		add mime extension header with date response was received
+ *		add "Cache-Control: public" header
+ *	else if 304, then
+ *		retrieve cached header
+ *		get old value of mime header count
+ *		increment mime header count
+ *		store mime header with new count
+ *
+ *
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int init_buffer_status;
+
+static char *mimehdr1_name;
+static char *mimehdr2_name;
+static char *mimehdr1_value;
+
+static TSMBuffer hdr_bufp;
+static TSMLoc hdr_loc;
+
+static TSMLoc field_loc;
+static TSMLoc value_loc;
+
+static void
+modify_header(TSHttpTxn txnp, TSCont contp)
+{
+  TSMBuffer resp_bufp;
+  TSMBuffer cached_bufp;
+  TSMLoc resp_loc;
+  TSMLoc cached_loc;
+  TSHttpStatus resp_status;
+  TSMLoc new_field_loc;
+  TSMLoc cached_field_loc;
+  time_t recvd_time;
+
+  const char *chkptr;
+  int chklength;
+
+  int num_refreshes = 0;
+
+  if (!init_buffer_status)
+    return;                     /* caller reenables */
+
+  if (TSHttpTxnServerRespGet(txnp, &resp_bufp, &resp_loc) != TS_SUCCESS) {
+    TSError("couldn't retrieve server response header\n");
+    return;                     /* caller reenables */
+  }
+
+  /* TSqa06246/TSqa06144 */
+  resp_status = TSHttpHdrStatusGet(resp_bufp, resp_loc);
+
+  if (TS_HTTP_STATUS_OK == resp_status) {
+
+    TSDebug("resphdr", "Processing 200 OK");
+    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */
+    TSDebug("resphdr", "Created new resp field with loc %d", new_field_loc);
+
+    /* copy name/values created at init
+     * ( "x-num-served-from-cache" ) : ( "0"  )
+     */
+    TSMimeHdrFieldCopy(resp_bufp, resp_loc, new_field_loc, hdr_bufp, hdr_loc, field_loc);
+
+        /*********** Unclear why this is needed **************/
+    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
+
+
+    /* Cache-Control: Public */
+    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */
+    TSDebug("resphdr", "Created new resp field with loc %d", new_field_loc);
+    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
+    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc,
+                           TS_MIME_FIELD_CACHE_CONTROL, TS_MIME_LEN_CACHE_CONTROL);
+    TSMimeHdrFieldValueStringInsert(resp_bufp, resp_loc, new_field_loc,
+                                     -1, TS_HTTP_VALUE_PUBLIC, TS_HTTP_LEN_PUBLIC);
+
+    /*
+     * mimehdr2_name  = TSstrdup( "x-date-200-recvd" ) : CurrentDateTime
+     */
+    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probably should check for errors */
+    TSDebug("resphdr", "Created new resp field with loc %d", new_field_loc);
+    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
+    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr2_name, strlen(mimehdr2_name));
+    recvd_time = time(NULL);
+    TSMimeHdrFieldValueDateInsert(resp_bufp, resp_loc, new_field_loc, recvd_time);
+
+    TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
+    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+
+  } else if (TS_HTTP_STATUS_NOT_MODIFIED == resp_status) {
+
+    TSDebug("resphdr", "Processing 304 Not Modified");
+
+    /* N.B.: Protect writes to data (hash on URL + mutex: (ies)) */
+
+    /* Get the cached HTTP header */
+    if (TSHttpTxnCachedRespGet(txnp, &cached_bufp, &cached_loc) != TS_SUCCESS) {
+      TSError("STATUS 304, TSHttpTxnCachedRespGet():");
+      TSError("couldn't retrieve cached response header\n");
+      TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+      return;                   /* Caller reenables */
+    }
+
+    /* Get the cached MIME field name for this HTTP header */
+    cached_field_loc = TSMimeHdrFieldFind(cached_bufp, cached_loc,
+                                           (const char *) mimehdr1_name, strlen(mimehdr1_name));
+    if (TS_NULL_MLOC == cached_field_loc) {
+      TSError("Can't find header %s in cached document", mimehdr1_name);
+      TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+      TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
+      return;                   /* Caller reenables */
+    }
+
+    /* Get the cached MIME value for this name in this HTTP header */
+    chkptr = TSMimeHdrFieldValueStringGet(cached_bufp, cached_loc, cached_field_loc, 0, &chklength);
+    if (NULL == chkptr || !chklength) {
+      TSError("Could not find value for cached MIME field name %s", mimehdr1_name);
+      TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+      TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
+      TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc);
+      return;                   /* Caller reenables */
+    }
+    TSDebug("resphdr", "Header field value is %s, with length %d", chkptr, chklength);
+
+
+    /* Get the cached MIME value for this name in this HTTP header */
+    /*
+       TSMimeHdrFieldValueUintGet(cached_bufp, cached_loc, cached_field_loc, 0, &num_refreshes);
+       TSDebug("resphdr",
+       "Cached header shows %d refreshes so far", num_refreshes );
+
+       num_refreshes++ ;
+     */
+
+       /* txn origin server response for this transaction stored
+       * in resp_bufp, resp_loc
+       *
+       * Create a new MIME field/value. Cached value has been incremented.
+       * Insert new MIME field/value into the server response buffer,
+       * allow HTTP processing to continue. This will update
+       * (indirectly invalidates) the cached HTTP headers MIME field.
+       * It is apparently not necessary to update all of the MIME fields
+       * in the in-process response in order to have the cached response
+       * become invalid.
+     */
+    TSMimeHdrFieldCreate(resp_bufp, resp_loc, &new_field_loc); /* Probaby should check for errrors */
+
+    /* mimehdr1_name : TSstrdup( "x-num-served-from-cache" ) ; */
+
+    TSMimeHdrFieldAppend(resp_bufp, resp_loc, new_field_loc);
+    TSMimeHdrFieldNameSet(resp_bufp, resp_loc, new_field_loc, mimehdr1_name, strlen(mimehdr1_name));
+
+    TSMimeHdrFieldValueUintInsert(resp_bufp, resp_loc, new_field_loc, -1, num_refreshes);
+
+    TSHandleMLocRelease(resp_bufp, resp_loc, new_field_loc);
+    TSHandleMLocRelease(cached_bufp, cached_loc, cached_field_loc);
+    TSHandleMLocRelease(cached_bufp, TS_NULL_MLOC, cached_loc);
+    TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_loc);
+
+  } else {
+    TSDebug("resphdr", "other response code %d", resp_status);
+  }
+
+  /*
+   *  Additional 200/304 processing can go here, if so desired.
+   */
+
+  /* Caller reneables */
+}
+
+
+static int
+modify_response_header_plugin(TSCont contp, TSEvent event, void *edata)
+{
+
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    TSDebug("resphdr", "Called back with TS_EVENT_HTTP_READ_RESPONSE_HDR");
+    modify_header(txnp, contp);
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    /*  fall through  */
+
+  default:
+    break;
+  }
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSMLoc chk_field_loc;
+
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "response-header-1";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  init_buffer_status = 0;
+  if (argc > 1) {
+    TSError("usage: %s \n", argv[0]);
+    TSError("warning: too many args %d\n", argc);
+    TSError("warning: ignoring unused arguments beginning with %s\n", argv[1]);
+  }
+
+  /*
+   *  The following code sets up an "init buffer" containing an extension header
+   *  and its initial value.  This will be the same for all requests, so we try
+   *  to be efficient and do all of the work here rather than on a per-transaction
+   *  basis.
+   */
+
+
+  hdr_bufp = TSMBufferCreate();
+  TSMimeHdrCreate(hdr_bufp, &hdr_loc);
+
+  mimehdr1_name = TSstrdup("x-num-served-from-cache");
+  mimehdr1_value = TSstrdup("0");
+
+  /* Create name here and set DateTime value when o.s.
+   * response 200 is received
+   */
+  mimehdr2_name = TSstrdup("x-date-200-recvd");
+
+  TSDebug("resphdr", "Inserting header %s with value %s into init buffer", mimehdr1_name, mimehdr1_value);
+
+  TSMimeHdrFieldCreate(hdr_bufp, hdr_loc, &field_loc); /* Probably should check for errors */
+  TSMimeHdrFieldAppend(hdr_bufp, hdr_loc, field_loc);
+  TSMimeHdrFieldNameSet(hdr_bufp, hdr_loc, field_loc, mimehdr1_name, strlen(mimehdr1_name));
+  TSMimeHdrFieldValueStringInsert(hdr_bufp, hdr_loc, field_loc, -1, mimehdr1_value, strlen(mimehdr1_value));
+  TSDebug("resphdr", "init buffer hdr, field and value locs are %d, %d and %d", hdr_loc, field_loc, value_loc);
+  init_buffer_status = 1;
+
+
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(modify_response_header_plugin, NULL));
+
+  /*
+   *  The following code demonstrates how to extract the field_loc from the header.
+   *  In this plugin, the init buffer and thus field_loc never changes.  Code
+   *  similar to this may be used to extract header fields from any buffer.
+   */
+
+  if (TS_NULL_MLOC == (chk_field_loc = TSMimeHdrFieldGet(hdr_bufp, hdr_loc, 0))) {
+    TSError("couldn't retrieve header field from init buffer");
+    TSError("marking init buffer as corrupt; no more plugin processing");
+    init_buffer_status = 0;
+    /* bail out here and reenable transaction */
+  } else {
+    if (field_loc != chk_field_loc)
+      TSError("retrieved buffer field loc is %d when it should be %d", chk_field_loc, field_loc);
+  }
+}
diff --git a/example/server-transform/Makefile.am b/example/server-transform/Makefile.am
new file mode 100644
index 00000000..06961074
--- /dev/null
+++ b/example/server-transform/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = server-transform.la
+server_transform_la_SOURCES = server-transform.c
+server_transform_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/server-transform.so
diff --git a/example/server-transform/Makefile.in b/example/server-transform/Makefile.in
new file mode 100644
index 00000000..291edae8
--- /dev/null
+++ b/example/server-transform/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/server-transform
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+server_transform_la_LIBADD =
+am_server_transform_la_OBJECTS = server-transform.lo
+server_transform_la_OBJECTS = $(am_server_transform_la_OBJECTS)
+server_transform_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(server_transform_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(server_transform_la_SOURCES)
+DIST_SOURCES = $(server_transform_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = server-transform.la
+server_transform_la_SOURCES = server-transform.c
+server_transform_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/server-transform/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/server-transform/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+server-transform.la: $(server_transform_la_OBJECTS) $(server_transform_la_DEPENDENCIES) 
+	$(server_transform_la_LINK) -rpath $(pkglibdir) $(server_transform_la_OBJECTS) $(server_transform_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server-transform.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/server-transform.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/server-transform/server-transform.c b/example/server-transform/server-transform.c
new file mode 100644
index 00000000..12ddac16
--- /dev/null
+++ b/example/server-transform/server-transform.c
@@ -0,0 +1,691 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* server-transform.c:  an example program that sends response content
+ *                      to a server to be transformed, and sends the
+ *                      transformed content to the client
+ *
+ *
+ *	Usage:
+ *	(NT): ServerTransform.dll
+ *	(Solaris): server-transform.so
+ *
+ *
+ */
+
+/* The protocol spoken with the server is simple. The plugin sends the
+   content-length of the document being transformed as a 4-byte
+   integer and then it sends the document itself. The first 4-bytes of
+   the server response are a status code/content length. If the code
+   is greater than 0 then the plugin assumes transformation was
+   successful and uses the code as the content length of the
+   transformed document. If the status code is less than or equal to 0
+   then the plugin bypasses transformation and sends the original
+   document on through.
+
+   The plugin does a fair amount of error checking and tries to bypass
+   transformation in many cases such as when it can't connect to the
+   server. This example plugin simply connects to port 7 on localhost,
+   which on our solaris machines (and most unix machines) is the echo
+   port. One nicety about the protocol is that simply having the
+   server echo back what it is sent results in a "null"
+   transformation. (i.e. A transformation which does not modify the
+   content). */
+
+#include 
+#include 
+
+#if !defined (_WIN32)
+#  include 
+#else
+#  include 
+#endif
+
+#include 
+
+#define STATE_BUFFER       1
+#define STATE_CONNECT      2
+#define STATE_WRITE        3
+#define STATE_READ_STATUS  4
+#define STATE_READ         5
+#define STATE_BYPASS       6
+
+typedef struct
+{
+  int state;
+  TSHttpTxn txn;
+
+  TSIOBuffer input_buf;
+  TSIOBufferReader input_reader;
+
+  TSIOBuffer output_buf;
+  TSIOBufferReader output_reader;
+  TSVConn output_vc;
+  TSVIO output_vio;
+
+  TSAction pending_action;
+  TSVConn server_vc;
+  TSVIO server_vio;
+
+  int content_length;
+} TransformData;
+
+static TSCont transform_create(TSHttpTxn txnp);
+static void transform_destroy(TSCont contp);
+static int transform_connect(TSCont contp, TransformData * data);
+static int transform_write(TSCont contp, TransformData * data);
+static int transform_read_status(TSCont contp, TransformData * data);
+static int transform_read(TSCont contp, TransformData * data);
+static int transform_bypass(TSCont contp, TransformData * data);
+static int transform_buffer_event(TSCont contp, TransformData * data, TSEvent event, void *edata);
+static int transform_connect_event(TSCont contp, TransformData * data, TSEvent event, void *edata);
+static int transform_write_event(TSCont contp, TransformData * data, TSEvent event, void *edata);
+static int transform_read_status_event(TSCont contp, TransformData * data, TSEvent event, void *edata);
+static int transform_read_event(TSCont contp, TransformData * data, TSEvent event, void *edata);
+static int transform_bypass_event(TSCont contp, TransformData * data, TSEvent event, void *edata);
+static int transform_handler(TSCont contp, TSEvent event, void *edata);
+
+#if !defined (_WIN32)
+static in_addr_t server_ip;
+#else
+static unsigned int server_ip;
+#endif
+
+static int server_port;
+
+static TSCont
+transform_create(TSHttpTxn txnp)
+{
+  TSCont contp;
+  TransformData *data;
+
+  contp = TSTransformCreate(transform_handler, txnp);
+
+  data = (TransformData *) TSmalloc(sizeof(TransformData));
+  data->state = STATE_BUFFER;
+  data->txn = txnp;
+  data->input_buf = NULL;
+  data->input_reader = NULL;
+  data->output_buf = NULL;
+  data->output_reader = NULL;
+  data->output_vio = NULL;
+  data->output_vc = NULL;
+  data->pending_action = NULL;
+  data->server_vc = NULL;
+  data->server_vio = NULL;
+  data->content_length = 0;
+
+  TSContDataSet(contp, data);
+  return contp;
+}
+
+static void
+transform_destroy(TSCont contp)
+{
+  TransformData *data;
+
+  data = TSContDataGet(contp);
+  if (data != NULL) {
+    if (data->input_buf)
+      TSIOBufferDestroy(data->input_buf);
+
+    if (data->output_buf)
+      TSIOBufferDestroy(data->output_buf);
+
+    if (data->pending_action)
+      TSActionCancel(data->pending_action);
+
+    if (data->server_vc)
+      TSVConnAbort(data->server_vc, 1);
+
+    TSfree(data);
+  } else {
+    TSError("Unable to get Continuation's Data. TSContDataGet returns NULL");
+  }
+
+  TSContDestroy(contp);
+}
+
+static int
+transform_connect(TSCont contp, TransformData * data)
+{
+  TSAction action;
+  int content_length;
+
+  data->state = STATE_CONNECT;
+
+  content_length = TSIOBufferReaderAvail(data->input_reader);
+  if (content_length >= 0) {
+    data->content_length = content_length;
+    data->content_length = htonl(data->content_length);
+
+    /* Prepend the content length to the buffer.
+     * If we decide to not send the content to the transforming
+     * server then we need to make sure and skip input_reader
+     * over the content length.
+     */
+
+    {
+      TSIOBuffer temp;
+      TSIOBufferReader tempReader;
+
+      temp = TSIOBufferCreate();
+      tempReader = TSIOBufferReaderAlloc(temp);
+
+      TSIOBufferWrite(temp, (const char *) &data->content_length, sizeof(int));
+      TSIOBufferCopy(temp, data->input_reader, data->content_length, 0);
+
+      TSIOBufferReaderFree(data->input_reader);
+      TSIOBufferDestroy(data->input_buf);
+      data->input_buf = temp;
+      data->input_reader = tempReader;
+    }
+  } else {
+    TSError("TSIOBufferReaderAvail returns TS_ERROR");
+    return 0;
+  }
+
+  action = TSNetConnect(contp, server_ip, server_port);
+  if (!TSActionDone(action)) {
+    data->pending_action = action;
+  }
+
+  return 0;
+}
+
+static int
+transform_write(TSCont contp, TransformData * data)
+{
+  int content_length;
+
+  data->state = STATE_WRITE;
+
+  content_length = TSIOBufferReaderAvail(data->input_reader);
+  if (content_length >= 0) {
+    data->server_vio = TSVConnWrite(data->server_vc, contp, TSIOBufferReaderClone(data->input_reader), content_length);
+  } else {
+    TSError("TSIOBufferReaderAvail returns TS_ERROR");
+  }
+  return 0;
+}
+
+static int
+transform_read_status(TSCont contp, TransformData * data)
+{
+  data->state = STATE_READ_STATUS;
+
+  data->output_buf = TSIOBufferCreate();
+  data->output_reader = TSIOBufferReaderAlloc(data->output_buf);
+  if (data->output_reader != NULL) {
+    data->server_vio = TSVConnRead(data->server_vc, contp, data->output_buf, sizeof(int));
+  } else {
+    TSError("Error in Allocating a Reader to output buffer. TSIOBufferReaderAlloc returns NULL");
+  }
+
+  return 0;
+}
+
+static int
+transform_read(TSCont contp, TransformData * data)
+{
+  data->state = STATE_READ;
+
+  TSIOBufferDestroy(data->input_buf);
+  data->input_buf = NULL;
+  data->input_reader = NULL;
+
+  data->server_vio = TSVConnRead(data->server_vc, contp, data->output_buf, data->content_length);
+  data->output_vc = TSTransformOutputVConnGet((TSVConn) contp);
+  if (data->output_vc == NULL) {
+    TSError("TSTransformOutputVConnGet returns NULL");
+  } else {
+    data->output_vio = TSVConnWrite(data->output_vc, contp, data->output_reader, data->content_length);
+    if (data->output_vio == NULL) {
+      TSError("TSVConnWrite returns NULL");
+    }
+  }
+
+  return 0;
+}
+
+static int
+transform_bypass(TSCont contp, TransformData * data)
+{
+  data->state = STATE_BYPASS;
+
+  if (data->server_vc) {
+    TSVConnAbort(data->server_vc, 1);
+    data->server_vc = NULL;
+    data->server_vio = NULL;
+  }
+
+  if (data->output_buf) {
+    TSIOBufferDestroy(data->output_buf);
+    data->output_buf = NULL;
+    data->output_reader = NULL;
+  }
+
+  TSIOBufferReaderConsume(data->input_reader, sizeof(int));
+  data->output_vc = TSTransformOutputVConnGet((TSVConn) contp);
+  if (data->output_vc == NULL) {
+    TSError("TSTransformOutputVConnGet returns NULL");
+  } else {
+    data->output_vio =
+      TSVConnWrite(data->output_vc, contp, data->input_reader, TSIOBufferReaderAvail(data->input_reader));
+    if (data->output_vio == NULL) {
+      TSError("TSVConnWrite returns NULL");
+    }
+  }
+  return 1;
+}
+
+static int
+transform_buffer_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
+{
+  TSVIO write_vio;
+  int towrite;
+  int avail;
+
+  if (!data->input_buf) {
+    data->input_buf = TSIOBufferCreate();
+    data->input_reader = TSIOBufferReaderAlloc(data->input_buf);
+  }
+
+  /* Get the write VIO for the write operation that was performed on
+     ourself. This VIO contains the buffer that we are to read from
+     as well as the continuation we are to call when the buffer is
+     empty. */
+  write_vio = TSVConnWriteVIOGet(contp);
+
+  /* We also check to see if the write VIO's buffer is non-NULL. A
+     NULL buffer indicates that the write operation has been
+     shutdown and that the continuation does not want us to send any
+     more WRITE_READY or WRITE_COMPLETE events. For this buffered
+     transformation that means we're done buffering data. */
+  if (!TSVIOBufferGet(write_vio)) {
+    return transform_connect(contp, data);
+  }
+
+  /* Determine how much data we have left to read. For this server
+     transform plugin this is also the amount of data we have left
+     to write to the output connection. */
+  towrite = TSVIONTodoGet(write_vio);
+  if (towrite > 0) {
+    /* The amount of data left to read needs to be truncated by
+       the amount of data actually in the read buffer. */
+    avail = TSIOBufferReaderAvail(TSVIOReaderGet(write_vio));
+    if (towrite > avail) {
+      towrite = avail;
+    }
+
+    if (towrite > 0) {
+      /* Copy the data from the read buffer to the input buffer. */
+      TSIOBufferCopy(data->input_buf, TSVIOReaderGet(write_vio), towrite, 0);
+
+      /* Tell the read buffer that we have read the data and are no
+         longer interested in it. */
+      TSIOBufferReaderConsume(TSVIOReaderGet(write_vio), towrite);
+
+      /* Modify the write VIO to reflect how much data we've
+         completed. */
+      TSVIONDoneSet(write_vio, TSVIONDoneGet(write_vio) + towrite);
+    }
+  }
+
+  /* Now we check the write VIO to see if there is data left to
+     read. */
+  if (TSVIONTodoGet(write_vio) > 0) {
+    /* Call back the write VIO continuation to let it know that we
+       are ready for more data. */
+    TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_READY, write_vio);
+  } else {
+    /* Call back the write VIO continuation to let it know that we
+       have completed the write operation. */
+    TSContCall(TSVIOContGet(write_vio), TS_EVENT_VCONN_WRITE_COMPLETE, write_vio);
+
+    /* start compression... */
+    return transform_connect(contp, data);
+  }
+
+  return 0;
+}
+
+static int
+transform_connect_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_NET_CONNECT:
+    data->pending_action = NULL;
+    data->server_vc = (TSVConn) edata;
+    return transform_write(contp, data);
+  case TS_EVENT_NET_CONNECT_FAILED:
+    data->pending_action = NULL;
+    return transform_bypass(contp, data);
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+static int
+transform_write_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_VCONN_WRITE_READY:
+    TSVIOReenable(data->server_vio);
+    break;
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    return transform_read_status(contp, data);
+  default:
+    /* An error occurred while writing to the server. Close down
+       the connection to the server and bypass. */
+    return transform_bypass(contp, data);
+  }
+
+  return 0;
+}
+
+static int
+transform_read_status_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_ERROR:
+  case TS_EVENT_VCONN_EOS:
+    return transform_bypass(contp, data);
+  case TS_EVENT_VCONN_READ_COMPLETE:
+    if (TSIOBufferReaderAvail(data->output_reader) == sizeof(int)) {
+      TSIOBufferBlock blk;
+      char *buf;
+      void *buf_ptr;
+      int64_t avail;
+      int64_t read_nbytes = sizeof(int);
+      int64_t read_ndone = 0;
+
+      buf_ptr = &data->content_length;
+      while (read_nbytes > 0) {
+        blk = TSIOBufferReaderStart(data->output_reader);
+        buf = (char *) TSIOBufferBlockReadStart(blk, data->output_reader, &avail);
+        read_ndone = (avail >= read_nbytes) ? read_nbytes : avail;
+        memcpy(buf_ptr, buf, read_ndone);
+        if (read_ndone > 0) {
+          TSIOBufferReaderConsume(data->output_reader, read_ndone);
+          read_nbytes -= read_ndone;
+          /* move ptr frwd by read_ndone bytes */
+          buf_ptr = (char *) buf_ptr + read_ndone;
+        }
+      }
+      data->content_length = ntohl(data->content_length);
+      return transform_read(contp, data);
+    }
+    return transform_bypass(contp, data);
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+static int
+transform_read_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_ERROR:
+    TSVConnAbort(data->server_vc, 1);
+    data->server_vc = NULL;
+    data->server_vio = NULL;
+
+    TSVConnAbort(data->output_vc, 1);
+    data->output_vc = NULL;
+    data->output_vio = NULL;
+    break;
+  case TS_EVENT_VCONN_EOS:
+    TSVConnAbort(data->server_vc, 1);
+    data->server_vc = NULL;
+    data->server_vio = NULL;
+
+    TSVConnAbort(data->output_vc, 1);
+    data->output_vc = NULL;
+    data->output_vio = NULL;
+    break;
+  case TS_EVENT_VCONN_READ_COMPLETE:
+    TSVConnClose(data->server_vc);
+    data->server_vc = NULL;
+    data->server_vio = NULL;
+
+    TSVIOReenable(data->output_vio);
+    break;
+  case TS_EVENT_VCONN_READ_READY:
+    TSVIOReenable(data->output_vio);
+    break;
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    TSVConnShutdown(data->output_vc, 0, 1);
+    break;
+  case TS_EVENT_VCONN_WRITE_READY:
+    TSVIOReenable(data->server_vio);
+    break;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+static int
+transform_bypass_event(TSCont contp, TransformData * data, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_VCONN_WRITE_COMPLETE:
+    TSVConnShutdown(data->output_vc, 0, 1);
+    break;
+  case TS_EVENT_VCONN_WRITE_READY:
+  default:
+    TSVIOReenable(data->output_vio);
+    break;
+  }
+
+  return 0;
+}
+
+static int
+transform_handler(TSCont contp, TSEvent event, void *edata)
+{
+  /* Check to see if the transformation has been closed by a call to
+     TSVConnClose. */
+  if (TSVConnClosedGet(contp)) {
+    transform_destroy(contp);
+    return 0;
+  } else {
+    TransformData *data;
+    int val = 0;
+
+    data = (TransformData *)TSContDataGet(contp);
+    if (data == NULL) {
+      TSError("Didn't get Continuation's Data. Ignoring Event..");
+      return 0;
+    }
+    do {
+      switch (data->state) {
+      case STATE_BUFFER:
+        val = transform_buffer_event(contp, data, event, edata);
+        break;
+      case STATE_CONNECT:
+        val = transform_connect_event(contp, data, event, edata);
+        break;
+      case STATE_WRITE:
+        val = transform_write_event(contp, data, event, edata);
+        break;
+      case STATE_READ_STATUS:
+        val = transform_read_status_event(contp, data, event, edata);
+        break;
+      case STATE_READ:
+        val = transform_read_event(contp, data, event, edata);
+        break;
+      case STATE_BYPASS:
+        val = transform_bypass_event(contp, data, event, edata);
+        break;
+      }
+    } while (val);
+  }
+
+  return 0;
+}
+
+static int
+request_ok(TSHttpTxn txnp)
+{
+  /* Is the initial client request OK for transformation. This is a
+     good place to check accept headers to see if the client can
+     accept a transformed document. */
+  return 1;
+}
+
+static int
+cache_response_ok(TSHttpTxn txnp)
+{
+  /* Is the response we're reading from cache OK for
+   * transformation. This is a good place to check the cached
+   * response to see if it is transformable. The default
+   * behavior is to cache transformed content; therefore
+   * to avoid transforming twice we will not transform
+   * content served from the cache.
+   */
+  return 0;
+}
+
+static int
+server_response_ok(TSHttpTxn txnp)
+{
+  /* Is the response the server sent OK for transformation. This is
+   * a good place to check the server's response to see if it is
+   * transformable. In this example, we will transform only "200 OK"
+   * responses.
+   */
+
+  TSMBuffer bufp;
+  TSMLoc hdr_loc;
+  TSHttpStatus resp_status;
+
+  if (TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
+    TSError("Unable to get handle to Server Response");
+    return 0;
+  }
+
+  resp_status = TSHttpHdrStatusGet(bufp, hdr_loc);
+  if (TS_HTTP_STATUS_OK == resp_status) {
+    if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) != TS_SUCCESS) {
+      TSError("Unable to release handle to server request");
+    }
+    return 1;
+  } else {
+    if (TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc) != TS_SUCCESS) {
+      TSError("Unable to release handle to server request");
+    }
+    return 0;
+  }
+}
+
+static int
+transform_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_REQUEST_HDR:
+    if (request_ok(txnp)) {
+      TSHttpTxnHookAdd(txnp, TS_HTTP_READ_CACHE_HDR_HOOK, contp);
+      TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, contp);
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+  case TS_EVENT_HTTP_READ_CACHE_HDR:
+    if (cache_response_ok(txnp)) {
+      TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, transform_create(txnp));
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    if (server_response_ok(txnp)) {
+      TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, transform_create(txnp));
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    break;
+  default:
+    break;
+  }
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Since this is an TS-SDK 2.0 plugin, we need at
+       least Traffic Server 2.0 to run */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+  TSCont cont;
+
+  info.plugin_name = "server-transform";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  /* connect to the echo port on localhost */
+  server_ip = (127 << 24) | (0 << 16) | (0 << 8) | (1);
+  server_ip = htonl(server_ip);
+  server_port = 7;
+
+  cont = TSContCreate(transform_plugin, NULL);
+  TSHttpHookAdd(TS_HTTP_READ_REQUEST_HDR_HOOK, cont);
+}
diff --git a/example/session-1/Makefile.am b/example/session-1/Makefile.am
new file mode 100644
index 00000000..8c91d7fc
--- /dev/null
+++ b/example/session-1/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = session-1.la
+session_1_la_SOURCES = session-1.c
+session_1_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/session-1.so
diff --git a/example/session-1/Makefile.in b/example/session-1/Makefile.in
new file mode 100644
index 00000000..3426ba48
--- /dev/null
+++ b/example/session-1/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/session-1
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+session_1_la_LIBADD =
+am_session_1_la_OBJECTS = session-1.lo
+session_1_la_OBJECTS = $(am_session_1_la_OBJECTS)
+session_1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(session_1_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(session_1_la_SOURCES)
+DIST_SOURCES = $(session_1_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = session-1.la
+session_1_la_SOURCES = session-1.c
+session_1_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/session-1/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/session-1/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+session-1.la: $(session_1_la_OBJECTS) $(session_1_la_DEPENDENCIES) 
+	$(session_1_la_LINK) -rpath $(pkglibdir) $(session_1_la_OBJECTS) $(session_1_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session-1.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/session-1.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/session-1/session-1.c b/example/session-1/session-1.c
new file mode 100644
index 00000000..63269b31
--- /dev/null
+++ b/example/session-1/session-1.c
@@ -0,0 +1,144 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* session-1.c: a plugin that illustrates how to use
+ *                session hooks
+ *
+ *
+ *  Usage: session-1.so
+ *
+ */
+
+#include 
+#include 
+
+static INKStat transaction_count;
+static INKStat session_count;
+static INKStat av_transaction;
+
+
+static void
+txn_handler(TSHttpTxn txnp, TSCont contp)
+{
+  int64_t num_txns = 0;
+
+  INKStatIncrement(transaction_count);
+  num_txns = INKStatIntGet(transaction_count);
+  TSDebug("tag_session", "The number of transactions is %d\n", num_txns);
+}
+
+
+static void
+handle_session(TSHttpSsn ssnp, TSCont contp)
+{
+  int64_t num_ssn = 0;
+
+  INKStatIncrement(session_count);
+  num_ssn = INKStatIntGet(session_count);
+  TSDebug("tag_session", "The number of sessions is %d\n", num_ssn);
+  TSHttpSsnHookAdd(ssnp, TS_HTTP_TXN_START_HOOK, contp);
+}
+
+static int
+ssn_handler(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpSsn ssnp;
+  TSHttpTxn txnp;
+
+  switch (event) {
+  case TS_EVENT_HTTP_SSN_START:
+
+    ssnp = (TSHttpSsn) edata;
+    handle_session(ssnp, contp);
+    TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE);
+    return 0;
+
+  case TS_EVENT_HTTP_TXN_START:
+    txnp = (TSHttpTxn) edata;
+    txn_handler(txnp, contp);
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    return 0;
+
+  default:
+    TSDebug("tag_session", "In the default case: event = %d\n", event);
+    break;
+  }
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSCont contp;
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "session-1";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("[PluginInit] Plugin registration failed.\n");
+    goto error;
+  }
+
+  if (!check_ts_version()) {
+    TSError("[PluginInit] Plugin requires Traffic Server 3.0 or later\n");
+    goto error;
+  }
+
+  transaction_count = INKStatCreate("transaction.count", INKSTAT_TYPE_INT64);
+  session_count = INKStatCreate("session.count", INKSTAT_TYPE_INT64);
+  av_transaction = INKStatCreate("avg.transactions", INKSTAT_TYPE_FLOAT);
+
+  contp = TSContCreate(ssn_handler, NULL);
+  TSHttpHookAdd(TS_HTTP_SSN_START_HOOK, contp);
+
+error:
+  TSError("[PluginInit] Plugin not initialized");
+}
diff --git a/example/thread-1/Makefile.am b/example/thread-1/Makefile.am
new file mode 100644
index 00000000..ac5fd5e4
--- /dev/null
+++ b/example/thread-1/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = thread-1.la
+thread_1_la_SOURCES = thread-1.c
+thread_1_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/thread-1.so
diff --git a/example/thread-1/Makefile.in b/example/thread-1/Makefile.in
new file mode 100644
index 00000000..7c79bbc8
--- /dev/null
+++ b/example/thread-1/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/thread-1
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+thread_1_la_LIBADD =
+am_thread_1_la_OBJECTS = thread-1.lo
+thread_1_la_OBJECTS = $(am_thread_1_la_OBJECTS)
+thread_1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(thread_1_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(thread_1_la_SOURCES)
+DIST_SOURCES = $(thread_1_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = thread-1.la
+thread_1_la_SOURCES = thread-1.c
+thread_1_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/thread-1/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/thread-1/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+thread-1.la: $(thread_1_la_OBJECTS) $(thread_1_la_DEPENDENCIES) 
+	$(thread_1_la_LINK) -rpath $(pkglibdir) $(thread_1_la_OBJECTS) $(thread_1_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread-1.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/thread-1.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/thread-1/readme.txt b/example/thread-1/readme.txt
new file mode 100644
index 00000000..1829b8d0
--- /dev/null
+++ b/example/thread-1/readme.txt
@@ -0,0 +1,20 @@
+About thread-plugin.c
+
+This plugin sets up a callback to a continuation whose
+handler function creates a thread.
+
+TSPluginInit uses TSHttpHookAdd to create a 
+continuation that is called back after the HTTP
+origin server DNS lookup (the hook is 
+TS_HTTP_OS_DNS_HOOK). The handler function
+for the continuation is thread_plugin.
+
+The thread_plugin function creates a thread using 
+TSThreadCreate(), passing it the reenable_txn function
+as follows:
+TSThreadCreate(reenable_txn, edta);
+
+The thread runs the reenable_txn function, which simply
+reenables the HTTP transaction using TSHttpTxnReenable(). 
+The thread is automatically destroyed when the function 
+returns.
diff --git a/example/thread-1/thread-1.c b/example/thread-1/thread-1.c
new file mode 100644
index 00000000..1d6c5d50
--- /dev/null
+++ b/example/thread-1/thread-1.c
@@ -0,0 +1,111 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* thread-1.c:  an example program that creates a thread
+ *
+ *
+ *
+ *	Usage:
+ *	(NT): Thread.dll
+ *	(Solaris): thread-1.so
+ *
+ *
+ */
+
+#include 
+#include 
+#include 
+
+static void *
+reenable_txn(void *data)
+{
+  TSHttpTxn txnp = (TSHttpTxn) data;
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return NULL;
+}
+
+static int
+thread_plugin(TSCont contp, TSEvent event, void *edata)
+{
+  switch (event) {
+  case TS_EVENT_HTTP_OS_DNS:
+      /**
+       * Check if the thread has been created successfully or not.
+       * If the thread has not been created successfully, assert.
+       */
+    if (!TSThreadCreate(reenable_txn, edata)) {
+      TSReleaseAssert(!"Failure in thread creation");
+    }
+    return 0;
+  default:
+    break;
+  }
+  return 0;
+}
+
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+
+  }
+
+  return result;
+}
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name = "thread-1";
+  info.vendor_name = "MyCompany";
+  info.support_email = "ts-api-support@MyCompany.com";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, TSContCreate(thread_plugin, NULL));
+}
diff --git a/example/thread-pool/Makefile.am b/example/thread-pool/Makefile.am
new file mode 100644
index 00000000..fcc30e2e
--- /dev/null
+++ b/example/thread-pool/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CFLAGS+=-I$(top_srcdir)/proxy/api
+
+pkglibdir = ${pkglibexecdir}
+pkglib_LTLIBRARIES = psi.la
+psi_la_SOURCES = psi.c thread.c
+psi_la_LDFLAGS = -module -avoid-version -shared
+
+all:
+	ln -sf .libs/psi.so
diff --git a/example/thread-pool/Makefile.in b/example/thread-pool/Makefile.in
new file mode 100644
index 00000000..802ab43a
--- /dev/null
+++ b/example/thread-pool/Makefile.in
@@ -0,0 +1,738 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = example/thread-pool
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+psi_la_LIBADD =
+am_psi_la_OBJECTS = psi.lo thread.lo
+psi_la_OBJECTS = $(am_psi_la_OBJECTS)
+psi_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(psi_la_LDFLAGS) \
+	$(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(psi_la_SOURCES)
+DIST_SOURCES = $(psi_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = ${pkglibexecdir}
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@ -I$(top_srcdir)/proxy/api
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+pkglib_LTLIBRARIES = psi.la
+psi_la_SOURCES = psi.c thread.c
+psi_la_LDFLAGS = -module -avoid-version -shared
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign example/thread-pool/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign example/thread-pool/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkglibdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibdir)"
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+	}
+
+uninstall-pkglibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+	done
+
+clean-pkglibLTLIBRARIES:
+	-test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+	@list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+psi.la: $(psi_la_OBJECTS) $(psi_la_DEPENDENCIES) 
+	$(psi_la_LINK) -rpath $(pkglibdir) $(psi_la_OBJECTS) $(psi_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(pkglibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-pkglibLTLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-pkglibLTLIBRARIES
+
+
+all:
+	ln -sf .libs/psi.so
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/example/thread-pool/README.txt b/example/thread-pool/README.txt
new file mode 100644
index 00000000..54328722
--- /dev/null
+++ b/example/thread-pool/README.txt
@@ -0,0 +1,133 @@
+
+	Thread pool sample plugin for SDK 3.0
+	-------------------------------------
+
+List of files:
+==============
+ Plugin
+ ------
+ - psi.c : proxy side include plugin
+ - thread.h : thread pool header
+ - thread.c : thread pool implementation
+
+ Tools for testing
+ -----------------
+ - include/gen.c : utility to generate text files of various size
+ - include/gen_inc.sh : script to generate include files for testing
+
+ - test/SDKTest/psi_server.c : SDKTest server plugins to test psi
+ - test/SDKTest/SDKtest_server.config : SDKTest config file
+
+
+Description
+===========
+ The plugin looks for the specific header "X-Psi" in the OS HTTP response.
+ If this header is found, and if the document is of type text/html,
+ the plugin parses the response body to find include tags: "<--include=filename-->".
+
+ When an include tag is found, the plugin substitutes it by the content
+ of the file `filename`.
+
+ Filename must be a simple filename. It can not contain a path (relative or absolute).
+
+ Example:
+ --------
+ The OS sends the following HTTP response:
+	HTTP/1.0 200 OK\r\n
+	Content-Type: text/html\r\n
+	X-Psi: true\r\n
+	\r\n\r\n
+	
+	My html source code
+	
+	Some more html code
+	
+
+ The text file 'include.txt' on the proxy filesystem contains:
+	include content line 1
+	include content line 2
+	include content line 3
+
+ The response processed by the proxy and finally sent to the client is:
+	HTTP/1.0 200 OK\r\n
+	Content-Type: text/html\r\n
+	X-Psi: true\r\n
+	\r\n\r\n
+	
+	My html source code
+	include content line 1
+	include content line 2
+	include content line 3
+	Some more html code
+	
+ Note that the content of the 'include.txt' file is now inserted into
+ the body of the HTML response.
+ 
+
+Architecture
+============
+
+ Pool of threads
+ ---------------
+ The psi plugin uses a pool of threads to make system blocking calls (access to disk).
+ This is to avoid blocking a TS thread and slowing down the whole TS.
+
+ High level algorithm:
+ --------------------
+ 0. At init time, the plugin spawns threads.
+ 1. The plugin scans any HTTP response message header for the specific header X-Psi.
+ 2. If found, it sets up a transformation.
+ 3. The transformation parses the HTML content.
+ 4. When an include tag is found, the plugin creates a job and put it into
+    the thread's queue of jobs.
+ 5. Then it goes into an inactive mode, waiting for the job to get done by a thread.
+ 6. A thread picks up the job. Reads the file from the disk (blocking system call).
+    Then reenables the transformation.
+ 7. The transformation insert the content of the file into the HTML body.
+ 8. Go to step 8.
+
+
+
+Plugin Installation
+===================
+ Add a line to Traffic Server plugin.config with the name of the plugin: psi.so
+ No arguments required.
+
+ The files to include must be located under the directory /include
+  is the path where the psi.so library is located
+ (by default $TS_HOME/etc/trafficserver/plugins)
+
+ Start TS as usual. Now any HTTP response with the X-Psi headers will be processed
+ by the PSI plugin.
+
+ 
+
+Plugin Testing
+==============
+
+ Sample include file generation
+ ------------------------------
+ A basic utility ('gen')to generate files to be inserted is provided
+ in the directory thread-pool/include.
+ This create text files of various sizes.
+ Compile gen the execute gen_inc.sh to generate files:
+ > cd include
+ > make
+ > gen_inc.sh
+
+ Load
+ ----
+ SDKTest can be used to test this plugin. SDKTest allows to simulate:
+  - synthetic clients sending requests
+  - a synthetic origin server
+
+ The synthetic origin server has to be customized in order to send back
+ responses that contains the specific 'X-Psi' header.
+ This is done through a SDKTest server plugin. 
+ 
+ The rate of responses with X-Psi header is configurable thru a SDKTest config file.
+
+ A SDKTest server plugin as well as a SDKTest configuration file
+ are provided in the directory thread-pool/test/SDKTest.
+ Refer to the SDKTest manual for detailed setup instructions.
+
diff --git a/example/thread-pool/TESTPLAN.txt b/example/thread-pool/TESTPLAN.txt
new file mode 100644
index 00000000..c2141154
--- /dev/null
+++ b/example/thread-pool/TESTPLAN.txt
@@ -0,0 +1,74 @@
+	Thread-Pool Sample Plugin Testing
+	=================================
+
+
+Functional testing
+==================
+
+SynTest test cases are provided for functional testing as well as
+boundary testing.
+
+List of tests:
+--------------
+Test case are under thread-pool/test/SynTest/Tests/Psi
+1.cfg:Description: PSI Plugin - Include tag at the beginning of doc 
+2.cfg:Description: PSI Plugin - include tag middle of body doc 
+3.cfg:Description: PSI Plugin - include tag end of body doc 
+4.cfg:Description: PSI Plugin - 2 include tags in the same body 
+5.cfg:Description: PSI Plugin - Boundary case: no filename in include 
+6.cfg:Description: PSI Plugin - Boundary case: include tag doesn't end 
+7.cfg:Description: PSI Plugin - Boundary case: include file doesn't exist 
+8.cfg:Description: PSI Plugin - Boundary case: tag similar to include but slightly different 
+9.cfg:Description: PSI Plugin - Boundary case: include file is empty 
+10.cfg:Description: PSI Plugin - Boundary case: huge file to include 
+11.cfg:Description: PSI Plugin - Boundary case: no X-Psi header 
+12.cfg:Description: PSI Plugin - Boundary case: Server Aborts in middle of header
+13.cfg:Description: PSI Plugin - Boundary case: Server Aborts in middle of body 
+
+SynTest config file:
+--------------------
+SynTest config files are under thread-pool/test/SynTest
+ - system.cfg: master SynTest config file
+ - tests_psi.cfg: test plan for SynTest
+
+Tests setup:
+------------
+ - Update plugin.config to add the psi plugin
+ - Generate the include files using the gen_inc.sh tool in thread-pool/include
+ - Copy the include files into $TS_HOME/etc/trafficserver/plugins/include
+ - Start TS
+ - Start SynTest
+
+Expected tests result:
+----------------------
+All tests should pass.
+
+
+Load Testing
+============
+
+SDKTest is used for load testing.
+
+A SDKTest server plugin is required to exercise the plugin (the server
+must send back responses with 'X-Psi' header).
+
+The SDKTest server plugin is located under thread-pool/test/SDKTest
+A SDKTest configuration file is also provided (allows to change the ratio
+of X-Psi responses).
+
+Tests setup:
+------------
+TS setup:
+ - Update plugin.config to add the psi plugin
+ - Generate the include files using the gen_inc.sh tool in thread-pool/include
+ - Copy the include files into $TS_HOME/etc/trafficserver/plugins/include
+ - Start TS
+
+SDKTest setup (Refer to SDKTest manual for detailed instructions):
+ - Compile and install the SDKTest server plugin
+ - Configure SDKTest using the provided config file
+ - Start SDKTest
+
+Expected tests result:
+----------------------
+Load testing should run for 24hours with no crash and no mem leak.
diff --git a/example/thread-pool/include/Makefile.am b/example/thread-pool/include/Makefile.am
new file mode 100644
index 00000000..9badaf26
--- /dev/null
+++ b/example/thread-pool/include/Makefile.am
@@ -0,0 +1,25 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+CC=cc
+
+all:  gen 
+
+gen: gen.c
+	$(CC) -o gen gen.c
+
+clean-local:
+	rm -f gen gen.o 
diff --git a/example/thread-pool/include/gen.c b/example/thread-pool/include/gen.c
new file mode 100644
index 00000000..a4ec4e53
--- /dev/null
+++ b/example/thread-pool/include/gen.c
@@ -0,0 +1,40 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include 
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+
+  if (argc != 2) {
+    fprintf(stderr, "Syntax: gen N (with N number of bytes to generate).\n");
+    exit(-1);
+  }
+
+  for (i = 0; i < atoi(argv[1]); i++) {
+    printf("%d", i % 10);
+  }
+
+}
diff --git a/example/thread-pool/include/gen_inc.sh b/example/thread-pool/include/gen_inc.sh
new file mode 100644
index 00000000..de9d871f
--- /dev/null
+++ b/example/thread-pool/include/gen_inc.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+GEN=./gen
+
+# Generate docs for SynTest test cases
+
+$GEN 0 > incfile0.txt
+$GEN 100 > incfile1.txt
+$GEN 50000 > incfile2.txt
+
+# Generate docs for SDKTest test cases
+
+# docs of size 0, 10k, 20k, 30k, ... 90k
+for i in 0 1 2 3 4 5 6 7 8 9
+do
+  $GEN ${i}0000 > file${i}.txt
+done
+
+# docs of size 1.1k, 1.2k, ...,2.0k, ..., 9.9k
+for i in 1 2 3 4 5 6 7 8 9
+do
+    for j in 0 1 2 3 4 5 6 7 8 9 
+    do
+        $GEN ${i}${j}00 > file${i}${j}.txt
+    done
+done
diff --git a/example/thread-pool/psi.c b/example/thread-pool/psi.c
new file mode 100644
index 00000000..ab7ee367
--- /dev/null
+++ b/example/thread-pool/psi.c
@@ -0,0 +1,1077 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+ *
+ *
+ *
+ *	Usage:
+ * 	(NT): psi.dll
+ *	(Solaris): psi.so
+ *
+ *  Proxy Side Include plugin (PSI)
+ *
+ *   Synopsis:
+ *
+ *  This plugin allows to insert the content of a file stored on the proxy disk
+ *  into the body of an html response.
+ *
+ *  The plugin illustrates how to use a pool of threads in order to do blocking
+ *  calls (here, some disk i/o) in a Traffic Server plugin.
+ *
+ *
+ *   Details:
+ *
+ *  Refer to README file.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "thread.h"
+
+#define MIN(x,y) ((x < y) ? x :y)
+
+#define DBG_TAG "xpsi"
+
+/* This is the number of threads spawned by the plugin.
+   Should be tuned based on performance requirements,
+   blocking calls duration, etc... */
+#define NB_THREADS 3
+
+
+#define PSI_FILENAME_MAX_SIZE 512
+#define PSI_PATH_MAX_SIZE     256
+#define PSI_PATH "include"
+
+#define PSI_START_TAG      ""
+#define PSI_END_TAG_LEN    3
+
+#define MIME_FIELD_XPSI "X-Psi"
+
+typedef enum
+{
+  STATE_READ_DATA = 1,
+  STATE_READ_PSI = 2,
+  STATE_DUMP_PSI = 3
+} PluginState;
+
+typedef enum
+{
+  PARSE_SEARCH,
+  PARSE_EXTRACT,
+} ParseState;
+
+
+typedef struct
+{
+  unsigned int magic;
+  TSVIO output_vio;
+  TSIOBuffer output_buffer;
+  TSIOBufferReader output_reader;
+
+  TSIOBuffer psi_buffer;
+  TSIOBufferReader psi_reader;
+  char psi_filename[PSI_FILENAME_MAX_SIZE + 128];
+  int psi_filename_len;
+  int psi_success;
+
+  ParseState parse_state;
+
+  PluginState state;
+  int transform_bytes;
+} ContData;
+
+
+typedef struct
+{
+  TSCont contp;
+  TSEvent event;
+} TryLockData;
+
+
+typedef enum
+{
+  STR_SUCCESS,
+  STR_PARTIAL,
+  STR_FAIL
+} StrOperationResult;
+
+
+extern Queue job_queue;
+
+static TSTextLogObject log;
+static char psi_directory[PSI_PATH_MAX_SIZE];
+
+
+static int trylock_handler(TSCont contp, TSEvent event, void *edata);
+
+/*-------------------------------------------------------------------------
+  cont_data_alloc
+  Allocate and initialize a ContData structure associated to a transaction
+
+  Input:
+  Output:
+  Return Value:
+    Pointer on a new allocated ContData structure
+  -------------------------------------------------------------------------*/
+static ContData *
+cont_data_alloc()
+{
+  ContData *data;
+
+  data = (ContData *) TSmalloc(sizeof(ContData));
+  data->magic = MAGIC_ALIVE;
+  data->output_vio = NULL;
+  data->output_buffer = NULL;
+  data->output_reader = NULL;
+
+  data->psi_buffer = NULL;
+  data->psi_reader = NULL;
+  data->psi_filename[0] = '\0';
+  data->psi_filename_len = 0;
+  data->psi_success = 0;
+
+  data->parse_state = PARSE_SEARCH;
+
+  data->state = STATE_READ_DATA;
+  data->transform_bytes = 0;
+
+  return data;
+}
+
+
+/*-------------------------------------------------------------------------
+  cont_data_destroy
+  Deallocate ContData structure associated to a transaction
+
+  Input:
+    data   structure to deallocate
+  Output:
+  Return Value:
+    none
+  -------------------------------------------------------------------------*/
+static void
+cont_data_destroy(ContData * data)
+{
+  TSDebug(DBG_TAG, "Destroying continuation data");
+  if (data) {
+    TSAssert(data->magic == MAGIC_ALIVE);
+    if (data->output_reader) {
+      TSIOBufferReaderFree(data->output_reader);
+      data->output_reader = NULL;
+    }
+    if (data->output_buffer) {
+      TSIOBufferDestroy(data->output_buffer);
+      data->output_buffer = NULL;
+    }
+    if (data->psi_reader) {
+      TSIOBufferReaderFree(data->psi_reader);
+      data->psi_reader = NULL;
+    }
+    if (data->psi_buffer) {
+      TSIOBufferDestroy(data->psi_buffer);
+      data->psi_buffer = NULL;
+    }
+    data->magic = MAGIC_DEAD;
+    TSfree(data);
+  }
+}
+
+
+/*-------------------------------------------------------------------------
+  strsearch_ioreader
+  Looks for string pattern in an iobuffer
+
+  Input:
+    reader   reader on a iobuffer
+    pattern  string to look for (nul terminated)
+  Output:
+    nparse   number of chars scanned, excluding the matching pattern
+  Return Value:
+    STR_SUCCESS if pattern found
+    STR_PARTIAL if pattern found partially
+    STR_FAIL    if pattern not found
+  -------------------------------------------------------------------------*/
+static StrOperationResult
+strsearch_ioreader(TSIOBufferReader reader, const char *pattern, int *nparse)
+{
+  int index = 0;
+  TSIOBufferBlock block = TSIOBufferReaderStart(reader);
+  int slen = strlen(pattern);
+
+  if (slen <= 0) {
+    return STR_FAIL;
+  }
+
+  *nparse = 0;
+
+  /* Loop thru each block while we've not yet found the pattern */
+  while ((block != NULL) && (index < slen)) {
+    int64_t blocklen;
+    const char *blockptr = TSIOBufferBlockReadStart(block, reader, &blocklen);
+    const char *ptr;
+
+    for (ptr = blockptr; ptr < blockptr + blocklen; ptr++) {
+      (*nparse)++;
+      if (*ptr == pattern[index]) {
+        index++;
+        if (index == slen) {
+          break;
+        }
+      } else {
+        index = 0;
+      }
+    }
+
+    /* Parse next block */
+    block = TSIOBufferBlockNext(block);
+  }
+
+  *nparse -= index;             /* Adjust nparse so it doesn't include matching chars */
+  if (index == slen) {
+    TSDebug(DBG_TAG, "strfind: match for %s at position %d", pattern, *nparse);
+    return STR_SUCCESS;
+  } else if (index > 0) {
+    TSDebug(DBG_TAG, "strfind: partial match for %s at position %d", pattern, *nparse);
+    return STR_PARTIAL;
+  } else {
+    TSDebug(DBG_TAG, "strfind no match for %s", pattern);
+    return STR_FAIL;
+  }
+}
+
+
+/*-------------------------------------------------------------------------
+  strextract_ioreader
+  Extract a string from an iobuffer.
+  Start reading at position offset in iobuffer and extract until the
+  string end_pattern is found.
+
+  Input:
+    reader      reader on a iobuffer
+    offset      position to start reading
+    end_pattern the termination string (nul terminated)
+  Output:
+    buffer      if success, contains the extracted string, nul terminated
+    buflen      if success, contains the buffer length (excluding null char).
+  Return Value:
+    STR_SUCCESS if extraction successful
+    STR_PARTIAL if extraction not yet completed
+    STR_FAIL    if extraction failed
+  -------------------------------------------------------------------------*/
+static int
+strextract_ioreader(TSIOBufferReader reader, int offset, const char *end_pattern, char *buffer, int *buflen)
+{
+  int buf_idx = 0;
+  int p_idx = 0;
+  int nbytes_so_far = 0;
+  int plen = strlen(end_pattern);
+  const char *ptr;
+  TSIOBufferBlock block = TSIOBufferReaderStart(reader);
+
+  if (plen <= 0) {
+    return STR_FAIL;
+  }
+
+  /* Now start extraction */
+  while ((block != NULL) && (p_idx < plen) && (buf_idx < PSI_FILENAME_MAX_SIZE)) {
+    int64_t blocklen;
+    const char *blockptr = TSIOBufferBlockReadStart(block, reader, &blocklen);
+
+    for (ptr = blockptr; ptr < blockptr + blocklen; ptr++, nbytes_so_far++) {
+      if (nbytes_so_far >= offset) {
+
+        /* Add a new character to the filename */
+        buffer[buf_idx++] = *ptr;
+
+        /* If we have reach the end of the filename, we're done */
+        if (end_pattern[p_idx] == *ptr) {
+          p_idx++;
+          if (p_idx == plen) {
+            break;
+          }
+        } else {
+          p_idx = 0;
+        }
+
+        /* The filename is too long, something is fishy... let's abort extraction */
+        if (buf_idx >= PSI_FILENAME_MAX_SIZE) {
+          break;
+        }
+      }
+    }
+
+    block = TSIOBufferBlockNext(block);
+  }
+
+  /* Error, could not read end of filename */
+  if (buf_idx >= PSI_FILENAME_MAX_SIZE) {
+    TSDebug(DBG_TAG, "strextract: filename too long");
+    *buflen = 0;
+    return STR_FAIL;
+  }
+
+  /* Full Match */
+  if (p_idx == plen) {
+    /* Nul terminate the filename, remove the end_pattern copied into the buffer */
+    *buflen = buf_idx - plen;
+    buffer[*buflen] = '\0';
+    TSDebug(DBG_TAG, "strextract: filename = |%s|", buffer);
+    return STR_SUCCESS;
+  }
+  /* End of filename not yet reached we need to read some more data */
+  else {
+    TSDebug(DBG_TAG, "strextract: partially extracted filename");
+    *buflen = buf_idx - p_idx;
+    return STR_PARTIAL;
+  }
+}
+
+
+/*-------------------------------------------------------------------------
+  parse_data
+  Search for psi filename in the data.
+
+  Input:
+    contp   continuation for the current transaction
+    reader  reader on the iobuffer that contains data
+    avail   amount of data available in the iobuffer
+  Output:
+    towrite    amount of data in the iobuffer that can be written
+               to the downstream vconnection
+    toconsume  amount of data in the iobuffer to consume
+  Return Value:
+    0   if no psi filename found
+    1  if a psi filename was found
+  -------------------------------------------------------------------------*/
+static int
+parse_data(TSCont contp, TSIOBufferReader input_reader, int avail, int *toconsume, int *towrite)
+{
+  ContData *data;
+  int nparse = 0;
+  int status;
+
+  data = TSContDataGet(contp);
+  TSAssert(data->magic == MAGIC_ALIVE);
+
+  if (data->parse_state == PARSE_SEARCH) {
+
+    /* Search for the start pattern */
+    status = strsearch_ioreader(input_reader, PSI_START_TAG, &nparse);
+    switch (status) {
+    case STR_FAIL:
+      /* We didn't found the pattern */
+      *toconsume = avail;
+      *towrite = avail;
+      data->parse_state = PARSE_SEARCH;
+      return 0;
+    case STR_PARTIAL:
+      /* We need to read some more data */
+      *toconsume = nparse;
+      *towrite = nparse;
+      data->parse_state = PARSE_SEARCH;
+      return 0;
+    case STR_SUCCESS:
+      /* We found the start_pattern, let's go ahead */
+      data->psi_filename_len = 0;
+      data->psi_filename[0] = '\0';
+      data->parse_state = PARSE_EXTRACT;
+      break;
+    default:
+      TSAssert(!"strsearch_ioreader returned unexpected status");
+    }
+  }
+
+
+  /* And now let's extract the filename */
+  status = strextract_ioreader(input_reader, nparse + PSI_START_TAG_LEN,
+                               PSI_END_TAG, data->psi_filename, &data->psi_filename_len);
+  switch (status) {
+  case STR_FAIL:
+    /* We couldn't extract a valid filename */
+    *toconsume = nparse;
+    *towrite = nparse;
+    data->parse_state = PARSE_SEARCH;
+    return 0;
+  case STR_PARTIAL:
+    /* We need to read some more data */
+    *toconsume = nparse;
+    *towrite = nparse;
+    data->parse_state = PARSE_EXTRACT;
+    return 0;
+  case STR_SUCCESS:
+    /* We got a valid filename */
+    *toconsume = nparse + PSI_START_TAG_LEN + data->psi_filename_len + PSI_END_TAG_LEN;
+    *towrite = nparse;
+    data->parse_state = PARSE_SEARCH;
+    return 1;
+  default:
+    TSAssert(!"strextract_ioreader returned bad status");
+  }
+
+  return 0;
+}
+
+//TODO: Use libc basename function
+//
+/*-------------------------------------------------------------------------
+  strip_path
+  Utility func to strip path from a filename (= _basename cmd on unix)
+  Input:
+    filename
+  Output :
+    None
+  Return Value:
+    Filename with path stripped
+  -------------------------------------------------------------------------*/
+static const char *
+_basename(const char *filename)
+{
+  char *cptr;
+  const char *ptr = filename;
+
+  while ((cptr = strchr(ptr, (int) '/')) != NULL) {
+    ptr = cptr + 1;
+  }
+  return ptr;
+}
+
+/*-------------------------------------------------------------------------
+  psi_include
+  Read file to include. Copy its content into an iobuffer.
+
+  This is the function doing blocking calls and called by the plugin's threads
+
+  Input:
+    data      continuation for the current transaction
+  Output :
+    data->psi_buffer  contains the file content
+    data->psi_sucess  0 if include failed, 1 if success
+  Return Value:
+    0  if failure
+    1  if success
+  -------------------------------------------------------------------------*/
+static int
+psi_include(TSCont contp, void *edata)
+{
+#define BUFFER_SIZE 1024
+  ContData *data;
+  TSFile filep;
+  char buf[BUFFER_SIZE];
+  char inc_file[PSI_PATH_MAX_SIZE + PSI_FILENAME_MAX_SIZE];
+
+  /* We manipulate plugin continuation data from a separate thread.
+     Grab mutex to avoid concurrent access */
+  TSMutexLock(TSContMutexGet(contp));
+  data = TSContDataGet(contp);
+  TSAssert(data->magic == MAGIC_ALIVE);
+
+  if (!data->psi_buffer) {
+    data->psi_buffer = TSIOBufferCreate();
+    data->psi_reader = TSIOBufferReaderAlloc(data->psi_buffer);
+  }
+
+  /* For security reason, we do not allow to include files that are
+     not in the directory /include.
+     Also include file cannot contain any path. */
+  sprintf(inc_file, "%s/%s", psi_directory, _basename(data->psi_filename));
+
+  /* Read the include file and copy content into iobuffer */
+  if ((filep = TSfopen(inc_file, "r")) != NULL) {
+    TSDebug(DBG_TAG, "Reading include file %s", inc_file);
+
+    while (TSfgets(filep, buf, BUFFER_SIZE) != NULL) {
+      TSIOBufferBlock block;
+      int64_t len, avail, ndone, ntodo, towrite;
+      char *ptr_block;
+
+      len = strlen(buf);
+      ndone = 0;
+      ntodo = len;
+      while (ntodo > 0) {
+        /* TSIOBufferStart allocates more blocks if required */
+        block = TSIOBufferStart(data->psi_buffer);
+        ptr_block = TSIOBufferBlockWriteStart(block, &avail);
+        towrite = MIN(ntodo, avail);
+
+        memcpy(ptr_block, buf + ndone, towrite);
+        TSIOBufferProduce(data->psi_buffer, towrite);
+        ntodo -= towrite;
+        ndone += towrite;
+      }
+    }
+    TSfclose(filep);
+    data->psi_success = 1;
+    if (log) {
+      TSTextLogObjectWrite(log, "Successfully included file: %s", inc_file);
+    }
+  } else {
+    data->psi_success = 0;
+    if (log) {
+      TSTextLogObjectWrite(log, "Failed to include file: %s", inc_file);
+    }
+  }
+
+  /* Change state and schedule an event EVENT_IMMEDIATE on the plugin continuation
+     to let it know we're done. */
+
+  /* Note: if the blocking call was not in the transformation state (i.e. in
+     TS_HTTP_READ_REQUEST_HDR, TS_HTTP_OS_DNS and so on...) we could
+     use TSHttpTxnReenable to wake up the transaction instead of sending an event. */
+
+  TSContSchedule(contp, 0, TS_THREAD_POOL_DEFAULT);
+  data->psi_success = 0;
+  data->state = STATE_READ_DATA;
+  TSMutexUnlock(TSContMutexGet(contp));
+
+  return 0;
+}
+
+/*-------------------------------------------------------------------------
+  wake_up_streams
+  Send an event to the upstream vconnection to either
+    - ask for more data
+    - let it know we're done
+  Reenable the downstream vconnection
+  Input:
+    contp      continuation for the current transaction
+  Output :
+  Return Value:
+   0 if failure
+   1 if success
+  -------------------------------------------------------------------------*/
+static int
+wake_up_streams(TSCont contp)
+{
+  TSVIO input_vio;
+  ContData *data;
+  int ntodo;
+
+  data = TSContDataGet(contp);
+  TSAssert(data->magic == MAGIC_ALIVE);
+
+  input_vio = TSVConnWriteVIOGet(contp);
+  ntodo = TSVIONTodoGet(input_vio);
+
+  if (ntodo > 0) {
+    TSVIOReenable(data->output_vio);
+    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
+  } else {
+    TSDebug(DBG_TAG, "Total bytes produced by transform = %d", data->transform_bytes);
+    TSVIONBytesSet(data->output_vio, data->transform_bytes);
+    TSVIOReenable(data->output_vio);
+    TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
+  }
+
+  return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+  handle_transform
+   Get data from upstream vconn.
+   Parse it.
+   Include file if include tags found.
+   Copy data to downstream vconn.
+   Wake up upstream to get more data.
+
+  Input:
+    contp      continuation for the current transaction
+  Output :
+  Return Value:
+   0 if failure
+   1 if success
+  -------------------------------------------------------------------------*/
+static int
+handle_transform(TSCont contp)
+{
+  TSVConn output_conn;
+  TSVIO input_vio;
+  ContData *data;
+  TSIOBufferReader input_reader;
+  int toread, avail, psi, toconsume, towrite;
+  TSReturnCode retval;
+
+  /* Get the output (downstream) vconnection where we'll write data to. */
+  output_conn = TSTransformOutputVConnGet(contp);
+
+  /* Get upstream vio */
+  input_vio = TSVConnWriteVIOGet(contp);
+  data = TSContDataGet(contp);
+  TSAssert(data->magic == MAGIC_ALIVE);
+
+  if (!data->output_buffer) {
+    data->output_buffer = TSIOBufferCreate();
+    data->output_reader = TSIOBufferReaderAlloc(data->output_buffer);
+
+    /* INT64_MAX because we don't know yet how much bytes we'll produce */
+    data->output_vio = TSVConnWrite(output_conn, contp, data->output_reader, INT64_MAX);
+  }
+
+  /* If the input VIO's buffer is NULL, the transformation is over */
+  if (!TSVIOBufferGet(input_vio)) {
+    TSDebug(DBG_TAG, "input_vio NULL, terminating transformation");
+    TSVIONBytesSet(data->output_vio, data->transform_bytes);
+    TSVIOReenable(data->output_vio);
+    return 1;
+  }
+
+  /* Determine how much data we have left to read. */
+  toread = TSVIONTodoGet(input_vio);
+
+  if (toread > 0) {
+    input_reader = TSVIOReaderGet(input_vio);
+    avail = TSIOBufferReaderAvail(input_reader);
+
+    /* There are some data available for reading. Let's parse it */
+    if (avail > 0) {
+
+      /* No need to parse data if there are too few bytes left to contain
+         an include command... */
+      if (toread > (PSI_START_TAG_LEN + PSI_END_TAG_LEN)) {
+        psi = parse_data(contp, input_reader, avail, &toconsume, &towrite);
+      } else {
+        towrite = avail;
+        toconsume = avail;
+        psi = 0;
+      }
+
+      if (towrite > 0) {
+        /* Update the total size of the doc so far */
+        data->transform_bytes += towrite;
+
+        /* Copy the data from the read buffer to the output buffer. */
+        retval = TSIOBufferCopy(TSVIOBufferGet(data->output_vio), TSVIOReaderGet(input_vio), towrite, 0);
+        /* Reenable the output connection so it can read the data we've produced. */
+        TSVIOReenable(data->output_vio);
+      }
+
+      if (toconsume > 0) {
+        /* Consume data we've processed an we are no longer interested in */
+        TSIOBufferReaderConsume(input_reader, toconsume);
+
+        /* Modify the input VIO to reflect how much data we've completed. */
+        TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + toconsume);
+      }
+
+      /* Did we find a psi filename to execute in the data ? */
+      if (psi) {
+        Job *new_job;
+        /* Add a request to include a file into the jobs queue.. */
+        /* We'll be called back once it's done with an EVENT_IMMEDIATE */
+        TSDebug(DBG_TAG, "Psi filename extracted. Adding an include job to thread queue.");
+        data->state = STATE_READ_PSI;
+
+        /* Create a new job request and add it to the queue */
+        new_job = job_create(contp, &psi_include, NULL);
+        add_to_queue(&job_queue, new_job);
+
+        /* Signal to the threads there is a new job */
+        thread_signal_job();
+
+        return 1;
+      }
+    }
+  }
+
+  /* Wake up upstream and downstream vconnections */
+  wake_up_streams(contp);
+
+  return 1;
+}
+
+
+/*-------------------------------------------------------------------------
+  dump_psi
+  Dump the psi_output to the downstream vconnection.
+
+  Input:
+    contp      continuation for the current transaction
+  Output :
+  Return Value:
+   0 if failure
+   1 if success
+  -------------------------------------------------------------------------*/
+static int
+dump_psi(TSCont contp)
+{
+  ContData *data;
+  int psi_output_len;
+  TSVIO input_vio;
+  TSReturnCode retval;
+
+  input_vio = TSVConnWriteVIOGet(contp);
+  data = TSContDataGet(contp);
+  TSAssert(data->magic == MAGIC_ALIVE);
+
+  /* If script exec succeded, copy its output to the downstream vconn */
+  if (data->psi_success == 1) {
+    psi_output_len = TSIOBufferReaderAvail(data->psi_reader);
+
+    if (psi_output_len > 0) {
+      data->transform_bytes += psi_output_len;
+
+      TSDebug(DBG_TAG, "Inserting %d bytes from include file", psi_output_len);
+      retval = TSIOBufferCopy(TSVIOBufferGet(data->output_vio), data->psi_reader, psi_output_len, 0);
+      /* Consume all the output data */
+      TSIOBufferReaderConsume(data->psi_reader, psi_output_len);
+
+      /* Reenable the output connection so it can read the data we've produced. */
+      TSVIOReenable(data->output_vio);
+    }
+  }
+
+  /* Change state to finish up reading upstream data */
+  data->state = STATE_READ_DATA;
+  return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+  transform_handler
+  Handler for all events received during the transformation process
+
+  Input:
+    contp      continuation for the current transaction
+    event      event received
+    data       pointer on optional data
+  Output :
+  Return Value:
+  -------------------------------------------------------------------------*/
+static int
+transform_handler(TSCont contp, TSEvent event, void *edata)
+{
+  TSVIO input_vio;
+  ContData *data;
+  int state, retval;
+
+  /* This section will be called by both TS internal
+     and the thread. Protect it with a mutex to avoid
+     concurrent calls. */
+
+  /* Handle TryLock result */
+  if (TSMutexLockTry(TSContMutexGet(contp)) != TS_SUCCESS) {
+    TSCont c = TSContCreate(trylock_handler, NULL);
+    TryLockData *d = TSmalloc(sizeof(TryLockData));
+
+    d->contp = contp;
+    d->event = event;
+    TSContDataSet(c, d);
+    TSContSchedule(c, 10, TS_THREAD_POOL_DEFAULT);
+    return 1;
+  }
+
+  data = TSContDataGet(contp);
+  TSAssert(data->magic == MAGIC_ALIVE);
+
+  state = data->state;
+
+  /* Check to see if the transformation has been closed */
+  retval = TSVConnClosedGet(contp);
+  if (retval) {
+    /* If the thread is still executing its job, we don't want to destroy
+       the continuation right away as the thread will call us back
+       on this continuation. */
+    if (state == STATE_READ_PSI) {
+      TSContSchedule(contp, 10, TS_THREAD_POOL_DEFAULT);
+    } else {
+      TSMutexUnlock(TSContMutexGet(contp));
+      cont_data_destroy(TSContDataGet(contp));
+      TSContDestroy(contp);
+      return 1;
+    }
+  } else {
+    switch (event) {
+    case TS_EVENT_ERROR:
+      input_vio = TSVConnWriteVIOGet(contp);
+      TSContCall(TSVIOContGet(input_vio), TS_EVENT_ERROR, input_vio);
+      break;
+
+    case TS_EVENT_VCONN_WRITE_COMPLETE:
+      TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
+      break;
+
+    case TS_EVENT_VCONN_WRITE_READY:
+      /* downstream vconnection is done reading data we've write into it.
+         let's read some more data from upstream if we're in read state. */
+      if (state == STATE_READ_DATA) {
+        handle_transform(contp);
+      }
+      break;
+
+    case TS_EVENT_IMMEDIATE:
+      if (state == STATE_READ_DATA) {
+        /* upstream vconnection signals some more data ready to be read
+           let's try to transform some more data */
+        handle_transform(contp);
+      } else if (state == STATE_DUMP_PSI) {
+        /* The thread scheduled an event on our continuation to let us
+           know it has completed its job
+           Let's dump the include content to the output vconnection */
+        dump_psi(contp);
+        wake_up_streams(contp);
+      }
+      break;
+
+    default:
+      TSAssert(!"Unexpected event");
+      break;
+    }
+  }
+
+  TSMutexUnlock(TSContMutexGet(contp));
+  return 1;
+}
+
+/*-------------------------------------------------------------------------
+  trylock_handler
+  Small handler to handle TSMutexLockTry failures
+
+  Input:
+    contp      continuation for the current transaction
+    event      event received
+    data       pointer on optional data
+  Output :
+  Return Value:
+  -------------------------------------------------------------------------*/
+static int
+trylock_handler(TSCont contp, TSEvent event, void *edata)
+{
+  TryLockData *data = TSContDataGet(contp);
+  transform_handler(data->contp, data->event, NULL);
+  TSfree(data);
+  TSContDestroy(contp);
+  return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+  transformable
+  Determine if the current transaction should be transformed or not
+
+  Input:
+    txnp      current transaction
+  Output :
+  Return Value:
+    1  if transformable
+    0  if not
+  -------------------------------------------------------------------------*/
+static int
+transformable(TSHttpTxn txnp)
+{
+  /*  We are only interested in transforming "200 OK" responses
+     with a Content-Type: text/ header and with X-Psi header */
+  TSMBuffer bufp;
+  TSMLoc hdr_loc, field_loc;
+  TSHttpStatus resp_status;
+  const char *value;
+
+  TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc);
+
+  resp_status = TSHttpHdrStatusGet(bufp, hdr_loc);
+  if (resp_status != TS_HTTP_STATUS_OK) {
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return 0;
+  }
+
+  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CONTENT_TYPE, -1);
+  if (field_loc == TS_NULL_MLOC) {
+    TSError("[transformable] Error while searching Content-Type field");
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return 0;
+  }
+
+  value = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, 0, NULL);
+  if ((value == NULL) || (strncasecmp(value, "text/", sizeof("text/") - 1) != 0)) {
+    TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+    return 0;
+  }
+
+  TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+
+  field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, MIME_FIELD_XPSI, -1);
+
+  TSHandleMLocRelease(bufp, hdr_loc, field_loc);
+  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
+
+  return 1;
+}
+
+/*-------------------------------------------------------------------------
+  transform_add
+  Create a transformation and alloc data structure
+
+  Input:
+    txnp      current transaction
+  Output :
+  Return Value:
+    1  if transformation created
+    0  if not
+  -------------------------------------------------------------------------*/
+static int
+transform_add(TSHttpTxn txnp)
+{
+  TSCont contp;
+  ContData *data;
+
+  contp = TSTransformCreate(transform_handler, txnp);
+  data = cont_data_alloc();
+  TSContDataSet(contp, data);
+
+  TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, contp);
+  return 1;
+}
+
+/*-------------------------------------------------------------------------
+  read_response_handler
+  Handler for events related to hook READ_RESPONSE
+
+  Input:
+    contp      continuation for the current transaction
+    event      event received
+    data       pointer on eventual data
+  Output :
+  Return Value:
+  -------------------------------------------------------------------------*/
+static int
+read_response_handler(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txnp = (TSHttpTxn) edata;
+
+  switch (event) {
+  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
+    if (transformable(txnp)) {
+      TSDebug(DBG_TAG, "Add a transformation");
+      transform_add(txnp);
+    }
+    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+    return 0;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+  check_ts_version
+  Make sure TS version is at least 2.0
+
+  Input:
+  Output :
+  Return Value:
+    0  if error
+    1  if success
+  -------------------------------------------------------------------------*/
+int
+check_ts_version()
+{
+
+  const char *ts_version = TSTrafficServerVersionGet();
+  int result = 0;
+
+  if (ts_version) {
+    int major_ts_version = 0;
+    int minor_ts_version = 0;
+    int patch_ts_version = 0;
+
+    if (sscanf(ts_version, "%d.%d.%d", &major_ts_version, &minor_ts_version, &patch_ts_version) != 3) {
+      return 0;
+    }
+
+    /* Need at least TS 2.0 */
+    if (major_ts_version >= 2) {
+      result = 1;
+    }
+  }
+
+  return result;
+}
+
+
+/*-------------------------------------------------------------------------
+  TSPluginInit
+  Function called at plugin init time
+
+  Input:
+    argc  number of args
+    argv  list vof args
+  Output :
+  Return Value:
+  -------------------------------------------------------------------------*/
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+  int i;
+  TSReturnCode retval;
+
+  info.plugin_name = "psi";
+  info.vendor_name = "Apache";
+  info.support_email = "";
+
+  if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) {
+    TSError("Plugin registration failed.\n");
+  }
+
+  if (!check_ts_version()) {
+    TSError("Plugin requires Traffic Server 3.0 or later\n");
+    return;
+  }
+
+  /* Initialize the psi directory = /include */
+  sprintf(psi_directory, "%s/%s", TSPluginDirGet(), PSI_PATH);
+
+  /* create an TSTextLogObject to log any psi include */
+  retval = TSTextLogObjectCreate("psi", TS_LOG_MODE_ADD_TIMESTAMP, &log);
+  if (retval == TS_ERROR) {
+    TSError("Failed creating log for psi plugin");
+    log = NULL;
+  }
+
+  /* Create working threads */
+  thread_init();
+  init_queue(&job_queue);
+
+  for (i = 0; i < NB_THREADS; i++) {
+    char *thread_name = (char *) TSmalloc(64);
+    sprintf(thread_name, "Thread[%d]", i);
+    if (!TSThreadCreate((TSThreadFunc) thread_loop, thread_name)) {
+      TSError("[TSPluginInit] Error while creating threads");
+      return;
+    }
+  }
+
+  TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, TSContCreate(read_response_handler, TSMutexCreate()));
+  TSDebug(DBG_TAG, "Plugin started");
+}
diff --git a/example/thread-pool/test/SDKTest/SDKtest_server.config b/example/thread-pool/test/SDKTest/SDKtest_server.config
new file mode 100644
index 00000000..50c02269
--- /dev/null
+++ b/example/thread-pool/test/SDKTest/SDKtest_server.config
@@ -0,0 +1,15 @@
+        # SDKtest_client configuration file
+        #
+		#
+	# If you provide plugin for SDKtest_server, specify the name of
+	# the plugin file in 'plugin' option. And put the .so file for
+        # the plugin under the same directory as SDKtest_server.config
+        #	(plugin = hello_world.so)
+
+# load the psi plugin
+plugin = psi_server.so
+
+# ratio of responses with a X-Psi header and an include tag in the body
+psi_ratio = 10 
+
+
diff --git a/example/thread-pool/test/SDKTest/psi_server.c b/example/thread-pool/test/SDKTest/psi_server.c
new file mode 100644
index 00000000..e2b06d6c
--- /dev/null
+++ b/example/thread-pool/test/SDKTest/psi_server.c
@@ -0,0 +1,195 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/* SimSynthServerCache.c
+ *
+ *
+ * Description:
+ *   Simulate server response that contains:
+ *      - PSI header
+ *      - PSI include in body
+ *
+ *   Ratio for generating PSI response is specifid in config file.
+ *
+ * Added Options in Synth_server.config -
+ *     psi_ratio : percentage of response with psi embedded we want to generate
+ */
+
+#include 
+#include 
+#include 
+#include "ServerAPI.h"
+
+#define PSI_TAG_FORMAT  ""
+#define PSI_TAG_MAX_SIZE 128
+#define PSI_MIME_HEADER "X-Psi: true"
+
+#define MAX_HEADER_RESPONSE 256
+#define TRUE 1
+#define FALSE 0
+
+typedef struct
+{
+  int status_code;
+  long request_length;
+  long bytes_not_sent;
+  char header_response[MAX_HEADER_RESPONSE];
+  int done_sent_header;         /* flag to see if header has been sent or not */
+  int psi;
+} RequestInfo;
+
+typedef struct
+{
+  double psi_ratio;             /* for psi_ratio */
+} SCPlugin;
+
+SCPlugin my_plugin;
+
+/* generate a random number to see if the document should include psi or not */
+int
+generate_psibility()
+{
+  double rand;
+  rand = drand48();
+  if (rand < my_plugin.psi_ratio) {
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+
+void
+TSOptionsProcess(char *option, char *value)
+{
+  if (strcmp(option, "psi_ratio") == 0) {
+    fprintf(stderr, "psi ratio set to %d %%\n", atoi(value));
+    my_plugin.psi_ratio = (double) (atoi(value)) / 100.0;
+  }
+}
+
+
+void
+TSPluginInit()
+{
+  fprintf(stderr, "*** PSI Server ***\n");
+  TSFuncRegister(TS_FID_OPTIONS_PROCESS);
+  TSFuncRegister(TS_FID_RESPONSE_PREPARE);
+  TSFuncRegister(TS_FID_RESPONSE_PUT);
+}
+
+/* prepare response header for a request */
+int
+TSResponsePrepare(char *req_hdr, int req_len, void **response_id)
+{
+  char *len_string;
+  RequestInfo *resp_id = (RequestInfo *) malloc(sizeof(RequestInfo));
+
+  resp_id->psi = generate_psibility();
+
+  resp_id->done_sent_header = FALSE;
+  if ((len_string = strstr(req_hdr, "length"))) {
+    len_string += strlen("length");
+    resp_id->request_length = atoi(len_string);
+    resp_id->bytes_not_sent = resp_id->request_length;
+    resp_id->status_code = 200;
+
+    if (resp_id->psi) {
+      sprintf(resp_id->header_response, "%s\r\n%s\r\n%s%ld\r\n%s\r\n\r\n",
+              "HTTP/1.0 200 OK",
+              "Content-type: text/plain", "Content-length: ", resp_id->request_length, PSI_MIME_HEADER);
+    } else {
+      sprintf(resp_id->header_response, "%s\r\n%s\r\n%s%ld\r\n\r\n",
+              "HTTP/1.0 200 OK", "Content-type: text/plain", "Content-length: ", resp_id->request_length);
+    }
+  } else {
+    resp_id->request_length = -1;
+    resp_id->status_code = 404;
+    resp_id->bytes_not_sent = 0;
+    sprintf(resp_id->header_response, "%s\r\n%s\r\n\r\n", "HTTP/1.0 404 Not Found", "Content-type: text/plain");
+  }
+  *response_id = resp_id;
+  return TRUE;
+}
+
+/* put response (response header + response document) into buffer */
+void
+TSResponsePut(void **resp_id /* return */ ,
+               void *resp_buffer /* return */ ,
+               int *resp_bytes /* return */ ,
+               int resp_buffer_size, int bytes_last_response)
+{
+  int i = 0;
+  RequestInfo *rid = *((RequestInfo **) resp_id);
+  int psi = 0;
+  int len;
+  char psi_tag[PSI_TAG_MAX_SIZE];
+
+  /* copy the header into the response buffer */
+  if (!rid->done_sent_header) {
+    i = sprintf((char *) resp_buffer, "%s", rid->header_response);
+    rid->done_sent_header = TRUE;
+  }
+
+  /* copy the content into the response buffer      */
+  /* for a psi response, it will look like:         */
+  /*    XXX...XXXXXX...XXXE   */
+  /* with 0<= N <= 99                               */
+  /*                                                */
+  /* for non psi response, it will looke like:      */
+  /*   XXX...XXXE                                    */
+
+  if (rid->status_code == 200) {
+    /* buffer is not large enough to handle all content */
+    if (rid->bytes_not_sent + i > resp_buffer_size) {
+      memset((void *) ((char *) resp_buffer + i), 'X', resp_buffer_size - i);
+      *resp_bytes = resp_buffer_size;
+      rid->bytes_not_sent -= (resp_buffer_size - i);
+    }
+    /* buffer is large enough to handle it in one shot */
+    else {
+      if (rid->psi) {
+        /* generate our psi tag:  */
+        len = sprintf(psi_tag, PSI_TAG_FORMAT, rand() % 100);
+
+        /* hopefully enough space for our include command */
+        if (rid->bytes_not_sent >= len) {
+          memcpy((void *) ((char *) resp_buffer + i), psi_tag, len);
+          rid->bytes_not_sent -= len;
+          i += len;
+        }
+      }
+      memset((void *) ((char *) resp_buffer + i), 'X', rid->bytes_not_sent);
+      memset((void *) ((char *) resp_buffer + i + rid->bytes_not_sent - 1), 'E', 1);
+      *resp_bytes = rid->bytes_not_sent + i;
+      rid->bytes_not_sent = 0;
+
+    }
+  }
+  /* return NULL as the resp_id to indicate
+   * if it is the last TSResponsePut call */
+  if (rid->bytes_not_sent <= 0 || rid->status_code != 200) {
+    free(rid);
+    *((RequestInfo **) resp_id) = NULL;
+  }
+}
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/1.cfg b/example/thread-pool/test/SynTest/Tests/Psi/1.cfg
new file mode 100644
index 00000000..c7fbe3bb
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/1.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - Include tag at the beginning of doc 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc1_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/10.cfg b/example/thread-pool/test/SynTest/Tests/Psi/10.cfg
new file mode 100644
index 00000000..15475969
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/10.cfg
@@ -0,0 +1,51 @@
+[test]
+Description: PSI Plugin - Boundary case: huge file to include 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc10_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+# huge file. do not print body
+print-body: false 
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/11.cfg b/example/thread-pool/test/SynTest/Tests/Psi/11.cfg
new file mode 100644
index 00000000..b839b1f3
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/11.cfg
@@ -0,0 +1,49 @@
+[test]
+Description: PSI Plugin - Boundary case: no X-Psi header 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+content-file: ./Tests/Psi/psi_files/tc11_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/12.cfg b/example/thread-pool/test/SynTest/Tests/Psi/12.cfg
new file mode 100644
index 00000000..2f2dc6c0
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/12.cfg
@@ -0,0 +1,45 @@
+[test]
+Description: PSI Plugin - Boundary case: Server Aborts in middle of header
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+socket-response: SendPartialHeaderAndCloseConnection
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc12_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+
+[proxy-response]
+# proxy returns 502 Server Hangup
+Must-have: {
+	Status ==502 
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/13.cfg b/example/thread-pool/test/SynTest/Tests/Psi/13.cfg
new file mode 100644
index 00000000..d5368023
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/13.cfg
@@ -0,0 +1,51 @@
+[test]
+Description: PSI Plugin - Boundary case: Server Aborts in middle of body 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+socket-response: SendPartialBodyAndCloseConnection
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc13_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/2.cfg b/example/thread-pool/test/SynTest/Tests/Psi/2.cfg
new file mode 100644
index 00000000..5e58fbe5
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/2.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - include tag middle of body doc 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc2_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/3.cfg b/example/thread-pool/test/SynTest/Tests/Psi/3.cfg
new file mode 100644
index 00000000..46d49f6d
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/3.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - include tag end of body doc 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc3_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/4.cfg b/example/thread-pool/test/SynTest/Tests/Psi/4.cfg
new file mode 100644
index 00000000..5db8ab00
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/4.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - 2 include tags in the same body 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc4_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/5.cfg b/example/thread-pool/test/SynTest/Tests/Psi/5.cfg
new file mode 100644
index 00000000..9092b7dc
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/5.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - Boundary case: no filename in include 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc5_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/6.cfg b/example/thread-pool/test/SynTest/Tests/Psi/6.cfg
new file mode 100644
index 00000000..68108562
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/6.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - Boundary case: include tag doesn't end 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc6_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/7.cfg b/example/thread-pool/test/SynTest/Tests/Psi/7.cfg
new file mode 100644
index 00000000..fc2bf253
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/7.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - Boundary case: include file doesn't exist 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc7_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/8.cfg b/example/thread-pool/test/SynTest/Tests/Psi/8.cfg
new file mode 100644
index 00000000..8c18a34f
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/8.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - Boundary case: tag similar to include but slightly different 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc8_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/9.cfg b/example/thread-pool/test/SynTest/Tests/Psi/9.cfg
new file mode 100644
index 00000000..af67d2a5
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/9.cfg
@@ -0,0 +1,50 @@
+[test]
+Description: PSI Plugin - Boundary case: include file is empty 
+
+### request
+
+[client-request]
+request: {
+	GET http://$(SVR_HOST):$(SVR_PORT)/ http/1.0
+	Host: http://$(SVR_HOST):$(SVR_PORT)/
+	User-Agent: HTTP Protocol Tester Client 1.0
+	Content-Length: 0
+}
+
+### response
+
+[server-response]
+http-response: {
+	HTTP/1.1 200 OK
+	Date: +0
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+	X-Psi: true
+}
+content-file: ./Tests/Psi/psi_files/tc9_file.txt
+
+### verification
+[output]
+# As syntest can't do this, we need to visually inspect bodies... :-(
+print-headers: false
+print-body: true
+
+[proxy-request]
+verify-header-valid: true
+
+[server-response]
+Must-have: {
+	Status == 200
+	Version == HTTP/1.1
+}
+verify-header-valid: true
+
+[proxy-response]
+Must-have: {
+	Status == 200
+	Server: HTTP Protocol Tester 1.0
+	Content-Type: text/html
+}
+verify-header-valid: true
+
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc10_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc10_file.txt
new file mode 100644
index 00000000..32e161ae
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc10_file.txt
@@ -0,0 +1,3 @@
+include a big file.
+
+include should be up there.
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc11_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc11_file.txt
new file mode 100644
index 00000000..1522b5b0
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc11_file.txt
@@ -0,0 +1,2 @@
+This body should not be transformed.
+include should still be between bars || is it ok ?
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc12_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc12_file.txt
new file mode 100644
index 00000000..8afd2a75
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc12_file.txt
@@ -0,0 +1,3 @@
+Server should abort before body is sent
+
+include should be up there.
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc13_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc13_file.txt
new file mode 100644
index 00000000..b5b4f2d9
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc13_file.txt
@@ -0,0 +1,3 @@
+Server should abort in middle of body 
+
+include should be up there.
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc1_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc1_file.txt
new file mode 100644
index 00000000..e0ed8883
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc1_file.txt
@@ -0,0 +1,2 @@
+
+include should be up there.
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc2_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc2_file.txt
new file mode 100644
index 00000000..f5cbe003
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc2_file.txt
@@ -0,0 +1 @@
+include should be between bars || is it ok ?
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc3_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc3_file.txt
new file mode 100644
index 00000000..02443f76
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc3_file.txt
@@ -0,0 +1,2 @@
+include should be down there:
+
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc4_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc4_file.txt
new file mode 100644
index 00000000..8541e059
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc4_file.txt
@@ -0,0 +1,5 @@
+2 includes in the body. One starting down there:
+
+One other down there:
+
+that's all folks !
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc5_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc5_file.txt
new file mode 100644
index 00000000..54a5e5fe
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc5_file.txt
@@ -0,0 +1,3 @@
+this is a doc with an include that has no filename
+
+should remove the tag and include nothing
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc6_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc6_file.txt
new file mode 100644
index 00000000..da41686d
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc6_file.txt
@@ -0,0 +1 @@
+should keep the uncomplete tag and include nothing
+should remove the tag and include nothing
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc8_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc8_file.txt
new file mode 100644
index 00000000..d4002230
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc8_file.txt
@@ -0,0 +1,3 @@
+tag similar to include but slightly different.
+
+should not remove the tag and include nothing
diff --git a/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc9_file.txt b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc9_file.txt
new file mode 100644
index 00000000..d7a9a33a
--- /dev/null
+++ b/example/thread-pool/test/SynTest/Tests/Psi/psi_files/tc9_file.txt
@@ -0,0 +1,2 @@
+include an empty file: should be no chars betwwen bars: ||
+OK ?
diff --git a/example/thread-pool/test/SynTest/system.cfg b/example/thread-pool/test/SynTest/system.cfg
new file mode 100644
index 00000000..4488828e
--- /dev/null
+++ b/example/thread-pool/test/SynTest/system.cfg
@@ -0,0 +1,44 @@
+# system.cfg
+#
+# This file consists of key-value pairs in MIME format. Keys must be unique
+# otherwise the last value seen is what's stored.
+# 
+# Comments start with '#'s and whitespace is ignored.
+#
+# "on" and "off" are reserved words. The corresponding keys are treated
+# as test group names.
+
+$SVR_HOST = cachedev.example.com
+$SVR_PORT = 1973 
+
+$PROXY_HOST = cachedev.example.com
+$PROXY_PORT = 8280
+
+$LOG_HOST = cachedev.example.com
+
+
+[config]
+proxy-host: $(PROXY_HOST)
+proxy-port: $(PROXY_PORT)
+server-host: $(SVR_HOST)
+server-port: $(SVR_PORT)
+log-host: $(LOG_HOST)
+log-dir: /export/workareas/franckc/traffic_tomcat/sun_opt/logs 
+# log-format: cqts ttms chi crc/pssc pscl ...
+# log-flush-delay: 15
+
+# System-level output control.
+# These settings can be overridden at the test-group and at the test levels.
+[output]
+print-headers: true 
+print-body: false
+print-verifications: false 
+print-echo: false
+verbose-mode: false
+
+# Reference to the test-group config file.
+[tests]
+#file: ims_tests.cfg
+#file: test_f.cfg
+file: tests_psi.cfg
+
diff --git a/example/thread-pool/test/SynTest/tests_psi.cfg b/example/thread-pool/test/SynTest/tests_psi.cfg
new file mode 100644
index 00000000..31a887ef
--- /dev/null
+++ b/example/thread-pool/test/SynTest/tests_psi.cfg
@@ -0,0 +1,61 @@
+# The "test-groups" section is required. It lists the test groups under the
+# "list" header. The test groups listed will each have their own sections.
+#
+
+
+[test-groups]
+list: {
+        Psi
+}
+
+
+
+#define default values for commonly used variables
+#these should be redefined where appropriate in individual tests
+$EXPIRES = 200
+$LM = 0
+$STAMP = $(now)
+
+verbose-mode:false 
+print-headers: false		
+print-body: false 
+print-verifications: true 
+
+
+# Each test group has "run" and "list" fields.
+# The valid values for "run" are "true" and "false".
+# The list blob lists the filenames of the test configuration files.
+#
+
+[Psi]
+run: true			
+list: {
+	generate-resource
+	Tests/Psi/1.cfg
+	generate-resource
+	Tests/Psi/2.cfg
+	generate-resource
+	Tests/Psi/3.cfg
+	generate-resource
+	Tests/Psi/4.cfg
+	generate-resource
+	Tests/Psi/5.cfg
+	generate-resource
+	Tests/Psi/6.cfg
+	generate-resource
+	Tests/Psi/7.cfg
+	generate-resource
+	Tests/Psi/8.cfg
+	generate-resource
+	Tests/Psi/9.cfg
+	generate-resource
+	Tests/Psi/10.cfg
+	generate-resource
+	Tests/Psi/11.cfg
+	generate-resource
+	Tests/Psi/12.cfg
+	generate-resource
+	Tests/Psi/13.cfg
+}
+
+
diff --git a/example/thread-pool/thread.c b/example/thread-pool/thread.c
new file mode 100644
index 00000000..4b55438e
--- /dev/null
+++ b/example/thread-pool/thread.c
@@ -0,0 +1,189 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+
+
+#include 
+#include 
+#include 
+
+#include "thread.h"
+
+#define DBGTAG  "xthread"
+
+struct timespec tp1;
+struct timespec tp2;
+
+Queue job_queue;
+
+static pthread_cond_t cond;
+static pthread_mutex_t cond_mutex;
+
+
+void
+init_queue(Queue * q)
+{
+  q->head = NULL;               /* Pointer on head cell */
+  q->tail = NULL;               /* Pointer on tail cell */
+  q->nb_elem = 0;               /* Nb elem in the queue */
+  q->mutex = TSMutexCreate();
+}
+
+void
+add_to_queue(Queue * q, void *data)
+{
+  Cell *new_cell;
+  int n;
+
+  if (data != NULL) {
+    TSMutexLock(q->mutex);
+    /* Init the new cell */
+    new_cell = TSmalloc(sizeof(Cell));
+    new_cell->magic = MAGIC_ALIVE;
+    new_cell->ptr_data = data;
+    new_cell->ptr_next = q->tail;
+    new_cell->ptr_prev = NULL;
+
+    /* Add this new cell to the queue */
+    if (q->tail == NULL) {
+      TSAssert(q->head == NULL);
+      TSAssert(q->nb_elem == 0);
+      q->tail = new_cell;
+      q->head = new_cell;
+    } else {
+      TSAssert(q->tail->magic == MAGIC_ALIVE);
+      q->tail->ptr_prev = new_cell;
+      q->tail = new_cell;
+    }
+    n = q->nb_elem++;
+    TSMutexUnlock(q->mutex);
+
+    if (n > MAX_JOBS_ALARM) {
+      TSError("Warning:Too many jobs in plugin thread pool queue (%d). Maximum allowed is %d", n, MAX_JOBS_ALARM);
+    }
+  }
+}
+
+void *
+remove_from_queue(Queue * q)
+{
+  void *data = NULL;
+  Cell *remove_cell;
+
+  TSMutexLock(q->mutex);
+  if (q->nb_elem > 0) {
+
+    remove_cell = q->head;
+    TSAssert(remove_cell->magic == MAGIC_ALIVE);
+
+    data = remove_cell->ptr_data;
+    q->head = remove_cell->ptr_prev;
+    if (q->head == NULL) {
+      TSAssert(q->nb_elem == 1);
+      q->tail = NULL;
+    } else {
+      TSAssert(q->head->magic == MAGIC_ALIVE);
+      q->head->ptr_next = NULL;
+    }
+
+    remove_cell->magic = MAGIC_DEAD;
+    TSfree(remove_cell);
+    q->nb_elem--;
+
+  }
+  TSMutexUnlock(q->mutex);
+  return data;
+}
+
+int
+get_nbelem_queue(Queue * q)
+{
+  int nb;
+  TSMutexLock(q->mutex);
+  nb = q->nb_elem;
+  TSMutexUnlock(q->mutex);
+
+  return nb;
+}
+
+Job *
+job_create(TSCont contp, ExecFunc func, void *data)
+{
+  Job *new_job;
+
+  new_job = TSmalloc(sizeof(Job));
+  new_job->magic = MAGIC_ALIVE;
+  new_job->cont = contp;
+  new_job->func = func;
+  new_job->data = data;
+  return new_job;
+}
+
+void
+job_delete(Job * job)
+{
+  job->magic = MAGIC_DEAD;
+  TSfree(job);
+}
+
+void
+thread_signal_job()
+{
+  pthread_mutex_lock(&cond_mutex);
+  pthread_cond_broadcast(&cond);
+  pthread_mutex_unlock(&cond_mutex);
+}
+
+void
+thread_init()
+{
+  pthread_cond_init(&cond, NULL);
+}
+
+void
+thread_loop(void *arg)
+{
+  Job *job_todo;
+
+  /* Infinite loop */
+  for (;;) {
+    /* returns a job or NULL if no jobs to do */
+    job_todo = remove_from_queue(&job_queue);
+
+    if (job_todo != NULL) {
+      TSAssert(job_todo->magic == MAGIC_ALIVE);
+
+      /* Simply execute the job function */
+      job_todo->func(job_todo->cont, job_todo->data);
+
+      /* Destroy this job */
+      job_delete(job_todo);
+    } else {
+      /* Sleep until we get awake (probably some work to do) */
+      pthread_mutex_lock(&cond_mutex);
+      pthread_cond_wait(&cond, &cond_mutex);
+      pthread_mutex_unlock(&cond_mutex);
+    }
+  }
+}
+
diff --git a/example/thread-pool/thread.h b/example/thread-pool/thread.h
new file mode 100644
index 00000000..b6f59005
--- /dev/null
+++ b/example/thread-pool/thread.h
@@ -0,0 +1,89 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+
+
+#ifndef _THREAD_H_
+#define _THREAD_H_
+
+#define MAGIC_ALIVE 0xfeedbabe
+#define MAGIC_DEAD  0xdeadbeef
+
+/* If more than MAX_JOBS_ALARM are present in queue, the plugin
+   will log error messages. This should be tuned based on your application */
+#define MAX_JOBS_ALARM 1000
+
+typedef int (*ExecFunc) (TSCont, void *);
+
+/* Structure that contains all information for a job execution */
+typedef struct
+{
+  unsigned int magic;
+  TSCont cont;                 /* Continuation to call once job is done */
+  ExecFunc func;                /* Job function */
+  void *data;                   /* Any data to pass to the job function */
+} Job;
+
+/* Implementation of the queue for jobs */
+struct cell_rec
+{
+  unsigned int magic;
+  void *ptr_data;
+  struct cell_rec *ptr_next;
+  struct cell_rec *ptr_prev;
+};
+typedef struct cell_rec Cell;
+
+typedef struct
+{
+  Cell *head;
+  Cell *tail;
+  int nb_elem;
+  TSMutex mutex;
+} Queue;
+
+
+/* queue manipulation functions */
+void init_queue(Queue * q);
+
+void add_to_queue(Queue * q, void *data);
+
+void *remove_from_queue(Queue * q);
+
+int get_nbelem_queue(Queue * q);
+
+
+/* Job functions */
+Job *job_create(TSCont contp, ExecFunc func, void *data);
+
+void job_delete(Job * job);
+
+
+/* thread functions */
+void thread_signal_job();
+
+void thread_init();
+
+void thread_loop(void *arg);
+
+#endif
diff --git a/iocore/Makefile.am b/iocore/Makefile.am
new file mode 100644
index 00000000..5178b56a
--- /dev/null
+++ b/iocore/Makefile.am
@@ -0,0 +1,24 @@
+# Makefile.am for traffic/iocore
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+if STANDALONE_IOCORE
+SUBDIRS = eventsystem net aio dns hostdb utils cache
+else
+SUBDIRS = eventsystem net aio dns hostdb utils cache cluster 
+endif
+
diff --git a/iocore/Makefile.in b/iocore/Makefile.in
new file mode 100644
index 00000000..563423cd
--- /dev/null
+++ b/iocore/Makefile.in
@@ -0,0 +1,772 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for traffic/iocore
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = iocore
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+	html-recursive info-recursive install-data-recursive \
+	install-dvi-recursive install-exec-recursive \
+	install-html-recursive install-info-recursive \
+	install-pdf-recursive install-ps-recursive install-recursive \
+	installcheck-recursive installdirs-recursive pdf-recursive \
+	ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+	$(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+	distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = eventsystem net aio dns hostdb utils cache cluster
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+pkgdatadir = @pkgdatadir@
+pkglibdir = @pkglibdir@
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+@STANDALONE_IOCORE_FALSE@SUBDIRS = eventsystem net aio dns hostdb utils cache cluster 
+@STANDALONE_IOCORE_TRUE@SUBDIRS = eventsystem net aio dns hostdb utils cache
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign iocore/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+	@fail= failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+	@fail= failcom='exit 1'; \
+	for f in x $$MAKEFLAGS; do \
+	  case $$f in \
+	    *=* | --[!k]*);; \
+	    *k*) failcom='fail=yes';; \
+	  esac; \
+	done; \
+	dot_seen=no; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	rev=''; for subdir in $$list; do \
+	  if test "$$subdir" = "."; then :; else \
+	    rev="$$subdir $$rev"; \
+	  fi; \
+	done; \
+	rev="$$rev ."; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+ctags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+	done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d "$(distdir)/$$subdir" \
+	    || $(MKDIR_P) "$(distdir)/$$subdir" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+	install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+	all all-am check check-am clean clean-generic clean-libtool \
+	ctags ctags-recursive distclean distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-generic \
+	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+	uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/iocore/aio/AIO.cc b/iocore/aio/AIO.cc
new file mode 100644
index 00000000..ba96549b
--- /dev/null
+++ b/iocore/aio/AIO.cc
@@ -0,0 +1,534 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+ * Async Disk IO operations.
+ */
+
+#include "P_AIO.h"
+
+#define MAX_DISKS_POSSIBLE 100
+
+// globals
+
+int ts_config_with_inkdiskio = 0;
+/* structure to hold information about each file descriptor */
+AIO_Reqs *aio_reqs[MAX_DISKS_POSSIBLE];
+/* number of unique file descriptors in the aio_reqs array */
+volatile int num_filedes = 1;
+RecRawStatBlock *aio_rsb = NULL;
+// acquire this mutex before inserting a new entry in the aio_reqs array.
+// Don't need to acquire this for searching the array
+static ink_mutex insert_mutex;
+Continuation *aio_err_callbck = 0;
+RecInt cache_config_threads_per_disk = 12;
+RecInt api_config_threads_per_disk = 12;
+int thread_is_created = 0;
+
+
+// AIO Stats
+uint64_t aio_num_read = 0;
+uint64_t aio_bytes_read = 0;
+uint64_t aio_num_write = 0;
+uint64_t aio_bytes_written = 0;
+
+static void aio_move(AIO_Reqs *req);
+
+/*
+ * Stats
+ */
+
+static int
+aio_stats_cb(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id)
+{
+  NOWARN_UNUSED(name);
+  (void) data_type;
+  (void) rsb;
+  int64_t new_val = 0;
+  int64_t diff = 0;
+  int64_t count, sum;
+  ink_hrtime now = ink_get_hrtime();
+  // The RecGetGlobalXXX stat functions are cheaper than the
+  // RecGetXXX functions. The Global ones are expensive
+  // for increments and decrements. But for AIO stats we
+  // only do Sets and Gets, so they are cheaper in our case.
+  RecGetGlobalRawStatSum(aio_rsb, id, &sum);
+  RecGetGlobalRawStatCount(aio_rsb, id, &count);
+
+  int64_t time_diff = ink_hrtime_to_msec(now - count);
+  if (time_diff == 0) {
+    data->rec_float = 0.0;
+    return 0;
+  }
+  switch (id) {
+  case AIO_STAT_READ_PER_SEC:
+    new_val = aio_num_read;
+    break;
+  case AIO_STAT_WRITE_PER_SEC:
+    new_val = aio_num_write;
+    break;
+  case AIO_STAT_KB_READ_PER_SEC:
+    new_val = aio_bytes_read >> 10;
+    break;
+  case AIO_STAT_KB_WRITE_PER_SEC:
+    new_val = aio_bytes_written >> 10;
+    break;
+  default:
+    ink_assert(0);
+  }
+  diff = new_val - sum;
+  RecSetGlobalRawStatSum(aio_rsb, id, new_val);
+  RecSetGlobalRawStatCount(aio_rsb, id, now);
+  data->rec_float = (float) diff *1000.00 / (float) time_diff;
+  return 0;
+}
+
+
+#ifdef AIO_STATS
+/* total number of requests received - for debugging */
+static int num_requests = 0;
+/* performance results */
+static AIOTestData *data;
+
+int
+AIOTestData::ink_aio_stats(int event, void *d)
+{
+  ink_hrtime now = ink_get_hrtime();
+  double time_msec = (double) (now - start) / (double) HRTIME_MSECOND;
+  int i = (aio_reqs[0] == NULL)? 1 : 0;
+  for (; i < num_filedes; i++) {
+    printf("%0.2f\t%i\t%i\t%i\n", time_msec, aio_reqs[i]->filedes, aio_reqs[i]->pending, aio_reqs[i]->queued);
+  printf("Num Requests: %i Num Queued: %i num Moved: %i\n\n", data->num_req, data->num_queue, data->num_temp);
+  eventProcessor.schedule_in(this, HRTIME_MSECONDS(50), ET_CALL);
+  return EVENT_DONE;
+}
+
+#endif // AIO_STATS
+
+/*
+ * Common
+ */
+AIOCallback *
+new_AIOCallback(void)
+{
+  return new AIOCallbackInternal;
+}
+
+void
+ink_aio_set_callback(Continuation *callback)
+{
+  aio_err_callbck = callback;
+}
+
+void
+ink_aio_init(ModuleVersion v)
+{
+  ink_release_assert(!checkModuleVersion(v, AIO_MODULE_VERSION));
+
+  aio_rsb = RecAllocateRawStatBlock((int) AIO_STAT_COUNT);
+  RecRegisterRawStat(aio_rsb, RECT_PROCESS, "proxy.process.cache.read_per_sec",
+                     RECD_FLOAT, RECP_NULL, (int) AIO_STAT_READ_PER_SEC, aio_stats_cb);
+  RecRegisterRawStat(aio_rsb, RECT_PROCESS, "proxy.process.cache.write_per_sec",
+                     RECD_FLOAT, RECP_NULL, (int) AIO_STAT_WRITE_PER_SEC, aio_stats_cb);
+  RecRegisterRawStat(aio_rsb, RECT_PROCESS,
+                     "proxy.process.cache.KB_read_per_sec",
+                     RECD_FLOAT, RECP_NULL, (int) AIO_STAT_KB_READ_PER_SEC, aio_stats_cb);
+  RecRegisterRawStat(aio_rsb, RECT_PROCESS,
+                     "proxy.process.cache.KB_write_per_sec",
+                     RECD_FLOAT, RECP_NULL, (int) AIO_STAT_KB_WRITE_PER_SEC, aio_stats_cb);
+  memset(&aio_reqs, 0, MAX_DISKS_POSSIBLE * sizeof(AIO_Reqs *));
+  ink_mutex_init(&insert_mutex, NULL);
+
+  IOCORE_ReadConfigInteger(cache_config_threads_per_disk, "proxy.config.cache.threads_per_disk");
+}
+
+int
+ink_aio_start()
+{
+#ifdef AIO_STATS
+  data = new AIOTestData();
+  eventProcessor.schedule_in(data, HRTIME_MSECONDS(100), ET_CALL);
+#endif
+  return 0;
+}
+
+
+static void *aio_thread_main(void *arg);
+
+struct AIOThreadInfo:public Continuation
+{
+
+  AIO_Reqs *req;
+  int sleep_wait;
+
+  int start(int event, Event *e)
+  {
+    (void) event;
+    (void) e;
+    aio_thread_main(this);
+    return EVENT_DONE;
+  }
+
+  AIOThreadInfo(AIO_Reqs *thr_req, int sleep):Continuation(new_ProxyMutex()), req(thr_req), sleep_wait(sleep)
+  {
+    SET_HANDLER(&AIOThreadInfo::start);
+  }
+
+};
+
+/* priority scheduling */
+/* Have 2 queues per file descriptor - A queue for http requests and another
+   for non-http (streaming) request. Each file descriptor has a lock
+   and condition variable associated with it. A dedicated number of threads
+   (THREADS_PER_DISK) wait on the condition variable associated with the
+   file descriptor. The cache threads try to put the request in the
+   appropriate queue. If they fail to acquire the lock, they put the
+   request in the atomic list. Requests are served in the order of
+   highest priority first. If both the queues are empty, the aio threads
+   check if there is any request on the other disks */
+
+
+/* insert  an entry for file descriptor fildes into aio_reqs */
+static AIO_Reqs *
+aio_init_fildes(int fildes, int fromAPI = 0)
+{
+  char thr_name[MAX_THREAD_NAME_LENGTH];
+  int i;
+  AIO_Reqs *request = (AIO_Reqs *) malloc(sizeof(AIO_Reqs));
+
+  memset(request, 0, sizeof(AIO_Reqs));
+
+  INK_WRITE_MEMORY_BARRIER;
+
+  ink_cond_init(&request->aio_cond);
+  ink_mutex_init(&request->aio_mutex, NULL);
+  ink_atomiclist_init(&request->aio_temp_list, "temp_list", (uintptr_t) &((AIOCallback *) 0)->link);
+
+  RecInt thread_num;
+
+  if (fromAPI) {
+    request->index = 0;
+    request->filedes = -1;
+    aio_reqs[0] = request;
+    thread_is_created = 1;
+    thread_num = api_config_threads_per_disk;
+  } else {
+    request->index = num_filedes;
+    request->filedes = fildes;
+    aio_reqs[num_filedes] = request;
+    thread_num = cache_config_threads_per_disk;
+  }
+
+  /* create the main thread */
+  AIOThreadInfo *thr_info;
+  for (i = 0; i < thread_num; i++) {
+    if (i == (thread_num - 1))
+      thr_info = new AIOThreadInfo(request, 1);
+    else
+      thr_info = new AIOThreadInfo(request, 0);
+    snprintf(thr_name, MAX_THREAD_NAME_LENGTH, "[ET_AIO %d]", i);
+    ink_assert(eventProcessor.spawn_thread(thr_info, thr_name));
+  }
+
+  /* the num_filedes should be incremented after initializing everything.
+     This prevents a thread from looking at uninitialized fields */
+  if (!fromAPI) {
+    num_filedes++;
+  }
+  return request;
+}
+
+/* insert a request into either aio_todo or http_todo queue. aio_todo
+   list is kept sorted */
+static void
+aio_insert(AIOCallback *op, AIO_Reqs *req)
+{
+#ifdef AIO_STATS
+  num_requests++;
+  req->queued++;
+#endif
+  if (op->aiocb.aio_reqprio == AIO_LOWEST_PRIORITY)     // http request
+  {
+    AIOCallback *cb = (AIOCallback *) req->http_aio_todo.tail;
+    if (!cb)
+      req->http_aio_todo.push(op);
+    else
+      req->http_aio_todo.insert(op, cb);
+  } else {
+
+    AIOCallback *cb = (AIOCallback *) req->aio_todo.tail;
+
+    for (; cb; cb = (AIOCallback *) cb->link.prev) {
+      if (cb->aiocb.aio_reqprio >= op->aiocb.aio_reqprio) {
+        req->aio_todo.insert(op, cb);
+        return;
+      }
+    }
+
+    /* Either the queue was empty or this request has the highest priority */
+    req->aio_todo.push(op);
+  }
+}
+
+/* move the request from the atomic list to the queue */
+static void
+aio_move(AIO_Reqs *req)
+{
+  AIOCallback *next = NULL, *prev = NULL, *cb = (AIOCallback *) ink_atomiclist_popall(&req->aio_temp_list);
+  /* flip the list */
+  if (!cb)
+    return;
+  while (cb->link.next) {
+    next = (AIOCallback *) cb->link.next;
+    cb->link.next = prev;
+    prev = cb;
+    cb = next;
+  }
+  /* fix the last pointer */
+  cb->link.next = prev;
+  for (; cb; cb = next) {
+    next = (AIOCallback *) cb->link.next;
+    cb->link.next = NULL;
+    cb->link.prev = NULL;
+    aio_insert(cb, req);
+  }
+}
+
+/* queue the new request */
+static void
+aio_queue_req(AIOCallbackInternal *op, int fromAPI = 0)
+{
+  int thread_ndx = 1;
+  AIO_Reqs *req = op->aio_req;
+  op->link.next = NULL;;
+  op->link.prev = NULL;
+#ifdef AIO_STATS
+  ink_atomic_increment((int *) &data->num_req, 1);
+#endif
+  if (!fromAPI && (!req || req->filedes != op->aiocb.aio_fildes)) {
+    /* search for the matching file descriptor */
+    for (; thread_ndx < num_filedes; thread_ndx++) {
+      if (aio_reqs[thread_ndx]->filedes == op->aiocb.aio_fildes) {
+        /* found the matching file descriptor */
+        req = aio_reqs[thread_ndx];
+        break;
+      }
+    }
+    if (!req) {
+      ink_mutex_acquire(&insert_mutex);
+      if (thread_ndx == num_filedes) {
+        /* insert a new entry */
+        req = aio_init_fildes(op->aiocb.aio_fildes);
+      } else {
+        /* a new entry was inserted between the time we checked the
+           aio_reqs and acquired the mutex. check the aio_reqs array to
+           make sure the entry inserted does not correspond  to the current
+           file descriptor */
+        for (thread_ndx = 1; thread_ndx < num_filedes; thread_ndx++) {
+          if (aio_reqs[thread_ndx]->filedes == op->aiocb.aio_fildes) {
+            req = aio_reqs[thread_ndx];
+            break;
+          }
+        }
+        if (!req)
+          req = aio_init_fildes(op->aiocb.aio_fildes);
+      }
+      ink_mutex_release(&insert_mutex);
+    }
+    op->aio_req = req;
+  }
+  if (fromAPI && (!req || req->filedes != -1)) {
+    ink_mutex_acquire(&insert_mutex);
+    if (aio_reqs[0] == NULL) {
+      req = aio_init_fildes(-1, 1);
+    } else {
+      req = aio_reqs[0];
+    }
+    ink_mutex_release(&insert_mutex);
+    op->aio_req = req;
+  }
+  ink_atomic_increment(&req->requests_queued, 1);
+  if (!ink_mutex_try_acquire(&req->aio_mutex)) {
+#ifdef AIO_STATS
+    ink_atomic_increment(&data->num_temp, 1);
+#endif
+    ink_atomiclist_push(&req->aio_temp_list, op);
+  } else {
+    /* check if any pending requests on the atomic list */
+#ifdef AIO_STATS
+    ink_atomic_increment(&data->num_queue, 1);
+#endif
+    if (!INK_ATOMICLIST_EMPTY(req->aio_temp_list))
+      aio_move(req);
+    /* now put the new request */
+    aio_insert(op, req);
+    ink_cond_signal(&req->aio_cond);
+    ink_mutex_release(&req->aio_mutex);
+  }
+}
+
+static inline int
+cache_op(AIOCallbackInternal *op)
+{
+  bool read = (op->aiocb.aio_lio_opcode == LIO_READ) ? 1 : 0;
+  for (; op; op = (AIOCallbackInternal *) op->then) {
+    ink_aiocb_t *a = &op->aiocb;
+    ssize_t err, res = 0;
+
+    while (a->aio_nbytes - res > 0) {
+      do {
+        if (read)
+          err = pread(a->aio_fildes, ((char *) a->aio_buf) + res, a->aio_nbytes - res, a->aio_offset + res);
+        else
+          err = pwrite(a->aio_fildes, ((char *) a->aio_buf) + res, a->aio_nbytes - res, a->aio_offset + res);
+      } while ((err < 0) && (errno == EINTR || errno == ENOBUFS || errno == ENOMEM));
+      if (err <= 0) {
+        Warning("cache disk operation failed %s %d %d\n",
+                (a->aio_lio_opcode == LIO_READ) ? "READ" : "WRITE", err, errno);
+        op->aio_result = -errno;
+        return (err);
+      }
+      res += err;
+    }
+    op->aio_result = res;
+    ink_assert(op->aio_result == (int64_t) a->aio_nbytes);
+  }
+  return 1;
+}
+
+int
+ink_aio_read(AIOCallback *op, int fromAPI)
+{
+  op->aiocb.aio_lio_opcode = LIO_READ;
+
+#if (AIO_MODE == AIO_MODE_AIO)
+  ink_debug_assert(this_ethread() == op->thread);
+  op->thread->aio_ops.enqueue(op);
+  if (aio_read(&op->aiocb) < 0) {
+    Warning("failed aio_read: %s\n", strerror(errno));
+    op->thread->aio_ops.remove(op);
+    return -1;
+  }
+#elif (AIO_MODE == AIO_MODE_SYNC)
+  cache_op((AIOCallbackInternal *) op);
+  op->action.continuation->handleEvent(AIO_EVENT_DONE, op);
+#elif (AIO_MODE == AIO_MODE_THREAD)
+  aio_queue_req((AIOCallbackInternal *) op, fromAPI);
+#endif
+
+  return 1;
+}
+
+int
+ink_aio_write(AIOCallback *op, int fromAPI)
+{
+  op->aiocb.aio_lio_opcode = LIO_WRITE;
+
+#if (AIO_MODE == AIO_MODE_AIO)
+  ink_debug_assert(this_ethread() == op->thread);
+  op->thread->aio_ops.enqueue(op);
+  if (aio_write(&op->aiocb) < 0) {
+    Warning("failed aio_write: %s\n", strerror(errno));
+    op->thread->aio_ops.remove(op);
+    return -1;
+  }
+#elif (AIO_MODE == AIO_MODE_SYNC)
+  cache_op((AIOCallbackInternal *) op);
+  op->action.continuation->handleEvent(AIO_EVENT_DONE, op);
+#elif (AIO_MODE == AIO_MODE_THREAD)
+  aio_queue_req((AIOCallbackInternal *) op, fromAPI);
+#endif
+
+  return 1;
+}
+
+bool
+ink_aio_thread_num_set(int thread_num)
+{
+  if (thread_num > 0 && !thread_is_created) {
+    api_config_threads_per_disk = thread_num;
+    return true;
+  }
+
+  return false;
+}
+
+void *
+aio_thread_main(void *arg)
+{
+  AIOThreadInfo *thr_info = (AIOThreadInfo *) arg;
+  AIO_Reqs *my_aio_req = (AIO_Reqs *) thr_info->req;
+  AIO_Reqs *current_req = NULL;
+  AIOCallback *op = NULL;
+  ink_mutex_acquire(&my_aio_req->aio_mutex);
+  for (;;) {
+    do {
+      current_req = my_aio_req;
+      /* check if any pending requests on the atomic list */
+      if (!INK_ATOMICLIST_EMPTY(my_aio_req->aio_temp_list))
+        aio_move(my_aio_req);
+      if (!(op = my_aio_req->aio_todo.pop()) && !(op = my_aio_req->http_aio_todo.pop()))
+        break;
+#ifdef AIO_STATS
+      num_requests--;
+      current_req->queued--;
+      ink_atomic_increment((int *) ¤t_req->pending, 1);
+#endif
+      // update the stats;
+      if (op->aiocb.aio_lio_opcode == LIO_WRITE) {
+        aio_num_write++;
+        aio_bytes_written += op->aiocb.aio_nbytes;
+      } else {
+        aio_num_read++;
+        aio_bytes_read += op->aiocb.aio_nbytes;
+      }
+      ink_mutex_release(¤t_req->aio_mutex);
+      if (cache_op((AIOCallbackInternal *) op) <= 0) {
+        if (aio_err_callbck) {
+          AIOCallback *callback_op = new AIOCallbackInternal();
+          callback_op->aiocb.aio_fildes = op->aiocb.aio_fildes;
+          callback_op->action = aio_err_callbck;
+          eventProcessor.schedule_imm(callback_op);
+        }
+      }
+      ink_atomic_increment((int *) ¤t_req->requests_queued, -1);
+#ifdef AIO_STATS
+      ink_atomic_increment((int *) ¤t_req->pending, -1);
+#endif
+      op->link.prev = NULL;
+      op->link.next = NULL;
+      op->mutex = op->action.mutex;
+      if (op->thread == AIO_CALLBACK_THREAD_AIO) {
+        MUTEX_LOCK(lock, op->mutex, thr_info->mutex->thread_holding);
+        if (!op->action.cancelled)
+          op->action.continuation->handleEvent(AIO_EVENT_DONE, op);
+      } else if (op->thread == AIO_CALLBACK_THREAD_ANY)
+        eventProcessor.schedule_imm_signal(op);
+      else
+        op->thread->schedule_imm_signal(op);
+      ink_mutex_acquire(&my_aio_req->aio_mutex);
+    } while (1);
+    ink_cond_wait(&my_aio_req->aio_cond, &my_aio_req->aio_mutex);
+  }
+  return 0;
+}
diff --git a/iocore/aio/I_AIO.h b/iocore/aio/I_AIO.h
new file mode 100644
index 00000000..28e303b6
--- /dev/null
+++ b/iocore/aio/I_AIO.h
@@ -0,0 +1,86 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  Async Disk IO operations.
+
+
+
+ ****************************************************************************/
+#if !defined (_I_AIO_h_)
+#define _I_AIO_h_
+
+#ifndef TS_INLINE
+#define TS_INLINE
+#endif
+
+#include "libts.h"
+#include "I_EventSystem.h"
+#include "I_RecProcess.h"
+
+#define AIO_MODULE_MAJOR_VERSION 1
+#define AIO_MODULE_MINOR_VERSION 0
+#define AIO_MODULE_VERSION       makeModuleVersion(AIO_MODULE_MAJOR_VERSION,\
+						   AIO_MODULE_MINOR_VERSION,\
+						   PUBLIC_MODULE_HEADER)
+
+#define AIO_EVENT_DONE           (AIO_EVENT_EVENTS_START+0)
+
+#define AIO_MODE_AIO             0
+#define AIO_MODE_SYNC            1
+#define AIO_MODE_THREAD          2
+#define AIO_MODE                 AIO_MODE_THREAD
+
+// AIOCallback::thread special values
+#define AIO_CALLBACK_THREAD_ANY ((EThread*)0) // any regular event thread
+#define AIO_CALLBACK_THREAD_AIO ((EThread*)-1)
+
+#define AIO_LOWEST_PRIORITY      0
+#define AIO_DEFAULT_PRIORITY     AIO_LOWEST_PRIORITY
+
+struct AIOCallback: public Continuation
+{
+  // set before calling aio_read/aio_write
+  ink_aiocb_t aiocb;
+  Action action;
+  EThread *thread;
+  AIOCallback *then;
+  // set on return from aio_read/aio_write
+  int64_t aio_result;
+
+  int ok();
+  AIOCallback() : thread(AIO_CALLBACK_THREAD_ANY), then(0) {
+    aiocb.aio_reqprio = AIO_DEFAULT_PRIORITY;
+  }
+};
+
+void ink_aio_init(ModuleVersion version);
+int ink_aio_start();
+void ink_aio_set_callback(Continuation * error_callback);
+
+int ink_aio_read(AIOCallback *op, int fromAPI = 0);   // fromAPI is a boolean to indicate if this is from a API call such as upload proxy feature
+int ink_aio_write(AIOCallback *op, int fromAPI = 0);
+bool ink_aio_thread_num_set(int thread_num);
+AIOCallback *new_AIOCallback(void);
+#endif
diff --git a/iocore/aio/Inline.cc b/iocore/aio/Inline.cc
new file mode 100644
index 00000000..f731ec58
--- /dev/null
+++ b/iocore/aio/Inline.cc
@@ -0,0 +1,31 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/*
+ * Inline Functions as globals for users using the public interface
+ *
+ */
+#define TS_INLINE
+#define INLINE_CC
+
+#include "P_AIO.h"
diff --git a/iocore/aio/Makefile.am b/iocore/aio/Makefile.am
new file mode 100644
index 00000000..b5dcf6ef
--- /dev/null
+++ b/iocore/aio/Makefile.am
@@ -0,0 +1,28 @@
+# Makefile.am for the traffic/iocore/aio hierarchy
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+AM_CPPFLAGS = \
+  -I$(top_srcdir)/iocore/eventsystem \
+  -I$(top_srcdir)/lib/records
+
+DEFS += @IOCORE_MODULARIZED_DEFS@
+
+noinst_LIBRARIES = libinkaio.a
+
+libinkaio_a_SOURCES = AIO.cc I_AIO.h P_AIO.h Inline.cc
+
diff --git a/iocore/aio/Makefile.in b/iocore/aio/Makefile.in
new file mode 100644
index 00000000..7d4d294c
--- /dev/null
+++ b/iocore/aio/Makefile.in
@@ -0,0 +1,696 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for the traffic/iocore/aio hierarchy
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+VPATH = @srcdir@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = iocore/aio
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \
+	$(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \
+	$(top_srcdir)/build/ltoptions.m4 \
+	$(top_srcdir)/build/ltsugar.m4 \
+	$(top_srcdir)/build/ltversion.m4 \
+	$(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \
+	$(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \
+	$(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \
+	$(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libinkaio_a_AR = $(AR) $(ARFLAGS)
+libinkaio_a_LIBADD =
+am_libinkaio_a_OBJECTS = AIO.$(OBJEXT) Inline.$(OBJEXT)
+libinkaio_a_OBJECTS = $(am_libinkaio_a_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts
+depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(libinkaio_a_SOURCES)
+DIST_SOURCES = $(libinkaio_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkglibdir = @pkglibdir@
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+API_DEFS = @API_DEFS@
+AR = @AR@
+ASCPP = @ASCPP@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCACHE = @CCACHE@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXPAT_LDFLAGS = @EXPAT_LDFLAGS@
+EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@
+EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@
+FGREP = @FGREP@
+GREP = @GREP@
+HOST_GUESS = @HOST_GUESS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBCRYPT = @LIBCRYPT@
+LIBDEMANGLE = @LIBDEMANGLE@
+LIBDL = @LIBDL@
+LIBEV = @LIBEV@
+LIBEXC = @LIBEXC@
+LIBEXECINFO = @LIBEXECINFO@
+LIBEXPAT = @LIBEXPAT@
+LIBICONV = @LIBICONV@
+LIBMLD = @LIBMLD@
+LIBNSL = @LIBNSL@
+LIBOBJS = @LIBOBJS@
+LIBPCRE = @LIBPCRE@
+LIBPROFILER = @LIBPROFILER@
+LIBRESOLV = @LIBRESOLV@
+LIBRT = @LIBRT@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBTCL = @LIBTCL@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MGMT_DEFS = @MGMT_DEFS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+RANLIB = @RANLIB@
+RM = @RM@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHARED_CFLAGS = @SHARED_CFLAGS@
+SHARED_CXXFLAGS = @SHARED_CXXFLAGS@
+SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@
+SHARED_LDFLAGS = @SHARED_LDFLAGS@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TCL_BIN_DIR = @TCL_BIN_DIR@
+TCL_LIB_FILE = @TCL_LIB_FILE@
+TCL_LIB_FLAG = @TCL_LIB_FLAG@
+TCL_LIB_SPEC = @TCL_LIB_SPEC@
+TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@
+TCL_SRC_DIR = @TCL_SRC_DIR@
+TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
+TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@
+TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+TCL_VERSION = @TCL_VERSION@
+TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@
+TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@
+TS_VERSION_MAJOR = @TS_VERSION_MAJOR@
+TS_VERSION_MICRO = @TS_VERSION_MICRO@
+TS_VERSION_MINOR = @TS_VERSION_MINOR@
+TS_VERSION_NUMBER = @TS_VERSION_NUMBER@
+TS_VERSION_STRING = @TS_VERSION_STRING@
+VERSION = @VERSION@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@
+allocah = @allocah@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+arpa_ineth = @arpa_ineth@
+arpa_nameser_compath = @arpa_nameser_compath@
+arpa_nameserh = @arpa_nameserh@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_group = @build_group@
+build_machine = @build_machine@
+build_os = @build_os@
+build_person = @build_person@
+build_vendor = @build_vendor@
+builddir = @builddir@
+cachedir = @cachedir@
+cpioh = @cpioh@
+ctypeh = @ctypeh@
+datadir = @datadir@
+datarootdir = @datarootdir@
+default_loopback_iface = @default_loopback_iface@
+defer_accept = @defer_accept@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_remote_cov_commit = @enable_remote_cov_commit@
+endianh = @endianh@
+exec_prefix = @exec_prefix@
+execinfoh = @execinfoh@
+exp_bindir = @exp_bindir@
+exp_cachedir = @exp_cachedir@
+exp_datadir = @exp_datadir@
+exp_exec_prefix = @exp_exec_prefix@
+exp_includedir = @exp_includedir@
+exp_infodir = @exp_infodir@
+exp_installbuilddir = @exp_installbuilddir@
+exp_libdir = @exp_libdir@
+exp_libexecdir = @exp_libexecdir@
+exp_localstatedir = @exp_localstatedir@
+exp_logdir = @exp_logdir@
+exp_mandir = @exp_mandir@
+exp_prefix = @exp_prefix@
+exp_runtimedir = @exp_runtimedir@
+exp_sbindir = @exp_sbindir@
+exp_sysconfdir = @exp_sysconfdir@
+expath = @expath@
+floath = @floath@
+gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@
+gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@
+has_backtrace = @has_backtrace@
+has_clock_gettime = @has_clock_gettime@
+has_demangle = @has_demangle@
+has_eventfd = @has_eventfd@
+has_inkapi = @has_inkapi@
+has_lrand48_r = @has_lrand48_r@
+has_posix_fadvise = @has_posix_fadvise@
+has_posix_memalign = @has_posix_memalign@
+has_profiler = @has_profiler@
+has_purify = @has_purify@
+has_srand48_r = @has_srand48_r@
+has_standalone_iocore = @has_standalone_iocore@
+has_strlcat = @has_strlcat@
+has_strlcpy = @has_strlcpy@
+has_strndup = @has_strndup@
+has_tests = @has_tests@
+has_wccp = @has_wccp@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+ink_with_modules_def = @ink_with_modules_def@
+ink_with_modules_local = @ink_with_modules_local@
+ink_with_modules_process = @ink_with_modules_process@
+install_sh = @install_sh@
+installbuilddir = @installbuilddir@
+iocore_include_dirs = @iocore_include_dirs@
+ip_transparent = @ip_transparent@
+is_micro_build = @is_micro_build@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libgenh = @libgenh@
+localedir = @localedir@
+localstatedir = @localstatedir@
+logdir = @logdir@
+lzmah = @lzmah@
+machine_endianh = @machine_endianh@
+malloch = @malloch@
+mandir = @mandir@
+mathh = @mathh@
+max_api_stats = @max_api_stats@
+mkdir_p = @mkdir_p@
+need_union_semun = @need_union_semun@
+net_ppp_defsh = @net_ppp_defsh@
+netdbh = @netdbh@
+netinet_in_systmh = @netinet_in_systmh@
+netinet_inh = @netinet_inh@
+netinet_ip_icmph = @netinet_ip_icmph@
+netinet_iph = @netinet_iph@
+netinet_tcph = @netinet_tcph@
+oldincludedir = @oldincludedir@
+pcre_pcreh = @pcre_pcreh@
+pcreh = @pcreh@
+pdfdir = @pdfdir@
+pkgbindir = @pkgbindir@
+pkgcachedir = @pkgcachedir@
+pkglocalstatedir = @pkglocalstatedir@
+pkglogdir = @pkglogdir@
+pkgruntimedir = @pkgruntimedir@
+pkgsbindir = @pkgsbindir@
+pkgsysconfdir = @pkgsysconfdir@
+pkgsysgroup = @pkgsysgroup@
+pkgsysuser = @pkgsysuser@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rel_bindir = @rel_bindir@
+rel_cachedir = @rel_cachedir@
+rel_datadir = @rel_datadir@
+rel_exec_prefix = @rel_exec_prefix@
+rel_includedir = @rel_includedir@
+rel_infodir = @rel_infodir@
+rel_installbuilddir = @rel_installbuilddir@
+rel_libdir = @rel_libdir@
+rel_libexecdir = @rel_libexecdir@
+rel_localstatedir = @rel_localstatedir@
+rel_logdir = @rel_logdir@
+rel_mandir = @rel_mandir@
+rel_prefix = @rel_prefix@
+rel_runtimedir = @rel_runtimedir@
+rel_sbindir = @rel_sbindir@
+rel_sysconfdir = @rel_sysconfdir@
+runtimedir = @runtimedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+siginfoh = @siginfoh@
+srcdir = @srcdir@
+stroptsh = @stroptsh@
+sys_byteorderh = @sys_byteorderh@
+sys_epollh = @sys_epollh@
+sys_eventh = @sys_eventh@
+sys_ioctlh = @sys_ioctlh@
+sys_mounth = @sys_mounth@
+sys_paramh = @sys_paramh@
+sys_sockioh = @sys_sockioh@
+sys_sysctlh = @sys_sysctlh@
+sys_sysinfoh = @sys_sysinfoh@
+sys_sysmacrosh = @sys_sysmacrosh@
+sys_systeminfoh = @sys_systeminfoh@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+use_diags = @use_diags@
+use_epoll = @use_epoll@
+use_fast_sdk = @use_fast_sdk@
+use_kqueue = @use_kqueue@
+use_libev = @use_libev@
+use_port = @use_port@
+use_posix_cap = @use_posix_cap@
+use_tproxy = @use_tproxy@
+valuesh = @valuesh@
+waith = @waith@
+zlibh = @zlibh@
+AM_CPPFLAGS = \
+  -I$(top_srcdir)/iocore/eventsystem \
+  -I$(top_srcdir)/lib/records
+
+noinst_LIBRARIES = libinkaio.a
+libinkaio_a_SOURCES = AIO.cc I_AIO.h P_AIO.h Inline.cc
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/aio/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign iocore/aio/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libinkaio.a: $(libinkaio_a_OBJECTS) $(libinkaio_a_DEPENDENCIES) 
+	-rm -f libinkaio.a
+	$(libinkaio_a_AR) libinkaio.a $(libinkaio_a_OBJECTS) $(libinkaio_a_LIBADD)
+	$(RANLIB) libinkaio.a
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AIO.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLIBRARIES ctags distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/iocore/aio/NTAIO.cc b/iocore/aio/NTAIO.cc
new file mode 100644
index 00000000..0140f2f3
--- /dev/null
+++ b/iocore/aio/NTAIO.cc
@@ -0,0 +1,168 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  NTAIO.cc
+
+
+ ****************************************************************************/
+
+#include "P_AIO.h"
+
+extern Continuation *aio_err_callbck;
+
+// AIO Stats
+extern uint64_t aio_num_read;
+extern uint64_t aio_bytes_read;
+extern uint64_t aio_num_write;
+extern uint64_t aio_bytes_written;
+
+NTIOCompletionPort aio_completion_port(1);
+
+
+static inline void
+init_op_sequence(AIOCallback * op, int opcode)
+{
+
+  // zero aio_result's and init opcodes
+  AIOCallback *cur_op;
+  for (cur_op = op; cur_op; cur_op = cur_op->then) {
+    cur_op->aio_result = 0;
+    cur_op->aiocb.aio_lio_opcode = opcode;
+    // set the last op to point to the first op
+    if (cur_op->then == NULL)
+      ((AIOCallbackInternal *) cur_op)->first = op;
+  }
+}
+
+static inline void
+cache_op(AIOCallback * op)
+{
+
+  DWORD bytes_trans;
+
+  // make op continuation share op->action's mutex
+  op->mutex = op->action.mutex;
+
+  // construct a continuation to handle the io completion
+  NTCompletionEvent *ce = NTCompletionEvent_alloc(op);
+  OVERLAPPED *overlapped = ce->get_overlapped();
+  overlapped->Offset = (unsigned long) (op->aiocb.aio_offset & 0xFFFFFFFF);
+  overlapped->OffsetHigh = (unsigned long)
+    (op->aiocb.aio_offset >> 32) & 0xFFFFFFFF;
+  // do the io
+  BOOL ret;
+  switch (op->aiocb.aio_lio_opcode) {
+  case LIO_READ:
+    ret = ReadFile((HANDLE) op->aiocb.aio_fildes,
+                   op->aiocb.aio_buf, (unsigned long) op->aiocb.aio_nbytes, &bytes_trans, overlapped);
+    break;
+  case LIO_WRITE:
+    ret = WriteFile((HANDLE) op->aiocb.aio_fildes,
+                    op->aiocb.aio_buf, (unsigned long) op->aiocb.aio_nbytes, &bytes_trans, overlapped);
+    break;
+  default:
+    ink_debug_assert(!"unknown aio_lio_opcode");
+  }
+  DWORD lerror = GetLastError();
+  if (ret == FALSE && lerror != ERROR_IO_PENDING) {
+
+    op->aio_result = -((int) lerror);
+    eventProcessor.schedule_imm(op);
+  }
+
+}
+
+int
+ink_aio_read(AIOCallback * op)
+{
+  init_op_sequence(op, LIO_READ);
+  cache_op(op);
+  return 1;
+}
+
+int
+ink_aio_write(AIOCallback * op)
+{
+  init_op_sequence(op, LIO_WRITE);
+  cache_op(op);
+  return 1;
+}
+
+
+struct AIOMissEvent:Continuation
+{
+  AIOCallback *cb;
+
+  int mainEvent(int event, Event * e)
+  {
+    if (!cb->action.cancelled)
+      cb->action.continuation->handleEvent(AIO_EVENT_DONE, cb);
+    delete this;
+      return EVENT_DONE;
+  }
+
+  AIOMissEvent(ProxyMutex * amutex, AIOCallback * acb)
+  : Continuation(amutex), cb(acb)
+  {
+    SET_HANDLER(&AIOMissEvent::mainEvent);
+  }
+};
+
+int
+AIOCallbackInternal::io_complete(int event, void *data)
+{
+
+  int lerror;
+  NTCompletionEvent *ce = (NTCompletionEvent *) data;
+
+  // if aio_result is set, the original Read/Write call failed
+  if (!aio_result) {
+    lerror = ce->lerror;
+    aio_result = lerror ? -lerror : ce->_bytes_transferred;
+  }
+  // handle io errors
+  if ((lerror != 0) && aio_err_callbck) {
+    // schedule aio_err_callbck to be called-back
+    // FIXME: optimization, please... ^_^
+    AIOCallback *op = NEW(new AIOCallbackInternal());
+    op->aiocb.aio_fildes = aiocb.aio_fildes;
+    op->action = aio_err_callbck;
+    eventProcessor.schedule_imm(NEW(new AIOMissEvent(op->action.mutex, op)));
+  } else {
+    ink_debug_assert(ce->_bytes_transferred == aiocb.aio_nbytes);
+  }
+
+  if (then) {
+    // more op's in this sequence
+    cache_op(then);
+  } else {
+    // we're done! callback action
+    if (!first->action.cancelled) {
+      first->action.continuation->handleEvent(AIO_EVENT_DONE, first);
+    }
+  }
+
+  return 0;
+}
diff --git a/iocore/aio/P_AIO.h b/iocore/aio/P_AIO.h
new file mode 100644
index 00000000..20d6a65d
--- /dev/null
+++ b/iocore/aio/P_AIO.h
@@ -0,0 +1,133 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+/****************************************************************************
+
+  Async Disk IO operations.
+
+
+
+ ****************************************************************************/
+#ifndef _P_AIO_h_
+#define _P_AIO_h_
+
+#ifndef INLINE_CC
+#undef  TS_INLINE
+#define TS_INLINE inline
+#endif
+
+#include "P_EventSystem.h"
+#include "I_AIO.h"
+
+// for debugging
+// #define AIO_STATS 1
+
+#undef  AIO_MODULE_VERSION
+#define AIO_MODULE_VERSION        makeModuleVersion(AIO_MODULE_MAJOR_VERSION,\
+						    AIO_MODULE_MINOR_VERSION,\
+						    PRIVATE_MODULE_HEADER)
+struct AIO_Reqs;
+
+struct AIOCallbackInternal: public AIOCallback
+{
+  AIOCallback *first;
+  AIO_Reqs *aio_req;
+  ink_hrtime sleep_time;
+  int io_complete(int event, void *data);
+  AIOCallbackInternal()
+  {
+    const size_t to_zero = sizeof(AIOCallbackInternal)
+      - (size_t) & (((AIOCallbackInternal *) 0)->aiocb);
+    memset((char *) &(this->aiocb), 0, to_zero);
+    SET_HANDLER(&AIOCallbackInternal::io_complete);
+    // we do a memset() on AIOCallback and AIOCallbackInternal, so it sets all the members to 0
+    // coverity[uninit_member]
+  }
+};
+
+TS_INLINE int
+AIOCallback::ok()
+{
+  return (off_t) aiocb.aio_nbytes == (off_t) aio_result;
+}
+
+TS_INLINE int
+AIOCallbackInternal::io_complete(int event, void *data)
+{
+  (void) event;
+  (void) data;
+  if (!action.cancelled)
+    action.continuation->handleEvent(AIO_EVENT_DONE, this);
+  return EVENT_DONE;
+}
+
+struct AIO_Reqs
+{
+  Que(AIOCallback, link) aio_todo;       /* queue for holding non-http requests */
+  Que(AIOCallback, link) http_aio_todo;  /* queue for http requests */
+  /* Atomic list to temporarily hold the request if the
+     lock for a particular queue cannot be acquired */
+  InkAtomicList aio_temp_list;
+  ink_mutex aio_mutex;
+  ink_cond aio_cond;
+  int index;                    /* position of this struct in the aio_reqs array */
+  volatile int pending;         /* number of outstanding requests on the disk */
+  volatile int queued;          /* total number of aio_todo and http_todo requests */
+  volatile int filedes;         /* the file descriptor for the requests */
+  volatile int requests_queued;
+};
+
+#ifdef AIO_STATS
+class AIOTestData:public Continuation
+{
+public:
+  int num_req;
+  int num_temp;
+  int num_queue;
+  ink_hrtime start;
+
+  int ink_aio_stats(int event, void *data);
+
+  AIOTestData():Continuation(new_ProxyMutex()), num_req(0), num_temp(0), num_queue(0)
+  {
+    start = ink_get_hrtime();
+    SET_HANDLER(&AIOTestData::ink_aio_stats);
+  }
+};
+#endif
+
+enum aio_stat_enum
+{
+  AIO_STAT_READ_PER_SEC,
+  AIO_STAT_KB_READ_PER_SEC,
+  AIO_STAT_WRITE_PER_SEC,
+  AIO_STAT_KB_WRITE_PER_SEC,
+  AIO_STAT_COUNT
+};
+extern RecRawStatBlock *aio_rsb;
+
+#ifdef _WIN32
+extern NTIOCompletionPort aio_completion_port;
+#endif
+
+#endif
diff --git a/iocore/aio/sample.cfg b/iocore/aio/sample.cfg
new file mode 100644
index 00000000..81deb030
--- /dev/null
+++ b/iocore/aio/sample.cfg
@@ -0,0 +1,17 @@
+disk_size 1
+hotset_size 1
+hotset_frequency 0.5
+run_time 30
+threads_per_disk 1
+touch_data 1
+seq_read_percent 0.5
+seq_write_percent 0.30
+rand_read_percent 0.20
+seq_read_size 131072
+seq_write_size 4093
+rand_read_size 4096
+write_skip 5
+chains 1
+delete_disks 1
+disk_path ./aio.tst
+
diff --git a/iocore/aio/test_AIO.i b/iocore/aio/test_AIO.i
new file mode 100644
index 00000000..d2bf29e3
--- /dev/null
+++ b/iocore/aio/test_AIO.i
@@ -0,0 +1,527 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include 
+#include 
+
+Diags *diags;
+#define DIAGS_LOG_FILE "diags.log"
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//      void reconfigure_diags()
+//
+//      This function extracts the current diags configuration settings from
+//      records.config, and rebuilds the Diags data structures.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+static void
+reconfigure_diags()
+{
+  int i;
+  DiagsConfigState c;
+
+
+  // initial value set to 0 or 1 based on command line tags
+  c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL);
+  c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL);
+
+  c.enabled[DiagsTagType_Debug] = 1;
+  c.enabled[DiagsTagType_Action] = 1;
+  diags->show_location = 1;
+
+
+  // read output routing values
+  for (i = 0; i < DiagsLevel_Count; i++) {
+
+    c.outputs[i].to_stdout = 0;
+    c.outputs[i].to_stderr = 1;
+    c.outputs[i].to_syslog = 1;
+    c.outputs[i].to_diagslog = 1;
+  }
+
+  //////////////////////////////
+  // clear out old tag tables //
+  //////////////////////////////
+
+  diags->deactivate_all(DiagsTagType_Debug);
+  diags->deactivate_all(DiagsTagType_Action);
+
+  //////////////////////////////////////////////////////////////////////
+  //                     add new tag tables 
+  //////////////////////////////////////////////////////////////////////
+
+  if (diags->base_debug_tags)
+    diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug);
+  if (diags->base_action_tags)
+    diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action);
+
+  ////////////////////////////////////
+  // change the diags config values //
+  ////////////////////////////////////
+#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux)
+  diags->config = c;
+#else
+  memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState));
+#endif
+
+}
+
+
+
+static void
+init_diags(char *bdt, char *bat)
+{
+  FILE *diags_log_fp;
+  char diags_logpath[500];
+  strcpy(diags_logpath, DIAGS_LOG_FILE);
+
+  diags_log_fp = fopen(diags_logpath, "w");
+  if (diags_log_fp) {
+    int status;
+    status = setvbuf(diags_log_fp, NULL, _IOLBF, 512);
+    if (status != 0) {
+      fclose(diags_log_fp);
+      diags_log_fp = NULL;
+    }
+  }
+
+  diags = NEW(new Diags(bdt, bat, diags_log_fp));
+
+  if (diags_log_fp == NULL) {
+    SrcLoc loc(__FILE__, __FUNCTION__, __LINE__);
+
+    diags->print(NULL, DL_Warning, NULL, &loc,
+                 "couldn't open diags log file '%s', " "will not log to this file", diags_logpath);
+  }
+
+  diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath);
+  reconfigure_diags();
+
+}
+
+#define MAX_DISK_THREADS 200
+#ifdef DISK_ALIGN
+#define MIN_OFFSET       (32*1024)
+#else
+#define MIN_OFFSET       (8*1024)
+#endif
+enum
+{ READ_MODE, WRITE_MODE, RANDOM_READ_MODE };
+
+struct AIO_Device;
+volatile int n_accessors = 0;
+int orig_n_accessors;
+AIO_Device *dev[MAX_DISK_THREADS];
+
+extern int cache_config_threads_per_disk;
+
+
+int write_after = 0;
+int write_skip = 0;
+int hotset_size = 20;
+double hotset_frequency = 0.9;
+int touch_data = 0;
+int disk_size = 4000;
+int read_size = 1024;
+char *disk_path[MAX_DISK_THREADS];
+int n_disk_path = 0;
+int run_time = 0;
+int threads_per_disk = 1;
+int delete_disks = 0;
+int max_size = 0;
+int use_lseek = 0;
+
+int chains = 1;
+double seq_read_percent = 0.0;
+double seq_write_percent = 0.0;
+double rand_read_percent = 0.0;
+double real_seq_read_percent = 0.0;
+double real_seq_write_percent = 0.0;
+double real_rand_read_percent = 0.0;
+int seq_read_size = 0;
+int seq_write_size = 0;
+int rand_read_size = 0;
+
+struct AIO_Device:public Continuation
+{
+  char *path;
+  int fd;
+  int id;
+  char *buf;
+  ink_hrtime time_start, time_end;
+  int seq_reads;
+  int seq_writes;
+  int rand_reads;
+  int hotset_idx;
+  int mode;
+  AIOCallback *io;
+    AIO_Device(ProxyMutex * m):Continuation(m)
+  {
+    hotset_idx = 0;
+    io = new_AIOCallback();
+    time_start = 0;
+    SET_HANDLER(&AIO_Device::do_hotset);
+  }
+  int select_mode(double p)
+  {
+    if (p < real_seq_read_percent)
+      return READ_MODE;
+    else if (p < real_seq_read_percent + real_seq_write_percent)
+      return WRITE_MODE;
+    else
+      return RANDOM_READ_MODE;
+  };
+  void do_touch_data(ink_off_t orig_len, ink_off_t orig_offset)
+  {
+    if (!touch_data)
+      return;
+    unsigned int len = (unsigned int) orig_len;
+    unsigned int offset = (unsigned int) orig_offset;
+    offset = offset % 1024;
+    char *b = buf;
+    int *x = (int *) b;
+    int j;
+    for (j = 0; j < (int) (len / sizeof(int)); j++) {
+      x[j] = offset;
+      offset = (offset + 1) % 1024;
+    }
+  };
+  int do_check_data(ink_off_t orig_len, ink_off_t orig_offset)
+  {
+    if (!touch_data)
+      return 0;
+    unsigned int len = (unsigned int) orig_len;
+    unsigned int offset = (unsigned int) orig_offset;
+    offset = offset % 1024;
+    int *x = (int *) buf;
+    for (int j = 0; j < (int) (len / sizeof(int)); j++) {
+      if (x[j] != offset)
+        return 1;
+      offset = (offset + 1) % 1024;
+    }
+    return 0;
+  }
+  int do_hotset(int event, Event * e);
+  int do_fd(int event, Event * e);
+
+
+};
+
+
+
+
+void
+dump_summary(void)
+{
+  /* dump timing info */
+  printf("Writing summary info\n");
+
+  printf("----------\n");
+  printf("parameters\n");
+  printf("----------\n");
+  printf("%d disks\n", n_disk_path);
+  printf("%d chains\n", chains);
+  printf("%d threads_per_disk\n", threads_per_disk);
+
+  printf("%0.1f percent %d byte seq_reads by volume\n", seq_read_percent * 100.0, seq_read_size);
+  printf("%0.1f percent %d byte seq_writes by volume\n", seq_write_percent * 100.0, seq_write_size);
+  printf("%0.1f percent %d byte rand_reads by volume\n", rand_read_percent * 100.0, rand_read_size);
+  printf("-------\n");
+  printf("factors\n");
+  printf("-------\n");
+  printf("%0.1f percent %d byte seq_reads by count\n", real_seq_read_percent * 100.0, seq_read_size);
+  printf("%0.1f percent %d byte seq_writes by count\n", real_seq_write_percent * 100.0, seq_write_size);
+  printf("%0.1f percent %d byte rand_reads by count\n", real_rand_read_percent * 100.0, rand_read_size);
+
+  printf("-------------------------\n");
+  printf("individual thread results\n");
+  printf("-------------------------\n");
+  double total_seq_reads = 0;
+  double total_seq_writes = 0;
+  double total_rand_reads = 0;
+  double total_secs = 0.0;
+  for (int i = 0; i < orig_n_accessors; i++) {
+    double secs = (dev[i]->time_end - dev[i]->time_start) / 1000000000.0;
+    double ops_sec = (dev[i]->seq_reads + dev[i]->seq_writes + dev[i]->rand_reads) / secs;
+    printf("%s: #sr:%d #sw:%d #rr:%d %0.1f secs %0.1f ops/sec\n",
+           dev[i]->path, dev[i]->seq_reads, dev[i]->seq_writes, dev[i]->rand_reads, secs, ops_sec);
+    total_secs += secs;
+    total_seq_reads += dev[i]->seq_reads;
+    total_seq_writes += dev[i]->seq_writes;
+    total_rand_reads += dev[i]->rand_reads;
+  }
+  printf("-----------------\n");
+  printf("aggregate results\n");
+  printf("-----------------\n");
+  total_secs /= orig_n_accessors;
+  float sr = (total_seq_reads * seq_read_size) / total_secs;
+  sr /= 1024.0 * 1024.0;
+  float sw = (total_seq_writes * seq_write_size) / total_secs;
+  sw /= 1024.0 * 1024.0;
+  float rr = (total_rand_reads * rand_read_size) / total_secs;
+  rr /= 1024.0 * 1024.0;
+  printf("%f ops %0.2f mbytes/sec %0.1f ops/sec %0.1f ops/sec/disk seq_read\n",
+         total_seq_reads, sr, total_seq_reads / total_secs, total_seq_reads / total_secs / n_disk_path);
+  printf("%f ops %0.2f mbytes/sec %0.1f ops/sec %0.1f ops/sec/disk seq_write\n",
+         total_seq_writes, sw, total_seq_writes / total_secs, total_seq_writes / total_secs / n_disk_path);
+  printf("%f ops %0.2f mbytes/sec %0.1f ops/sec %0.1f ops/sec/disk rand_read\n",
+         total_rand_reads, rr, total_rand_reads / total_secs, total_rand_reads / total_secs / n_disk_path);
+  printf("%0.2f total mbytes/sec\n", sr + sw + rr);
+  printf("----------------------------------------------------------\n");
+
+  if (delete_disks)
+    for (int i = 0; i < n_disk_path; i++)
+      unlink(disk_path[i]);
+  exit(0);
+}
+
+int
+AIO_Device::do_hotset(int event, Event * e)
+{
+  ink_off_t max_offset = ((ink_off_t) disk_size) * 1024 * 1024;
+  io->aiocb.aio_lio_opcode = LIO_WRITE;
+  io->aiocb.aio_fildes = fd;
+  io->aiocb.aio_offset = MIN_OFFSET + hotset_idx * max_size;
+  do_touch_data(seq_read_size, io->aiocb.aio_offset);
+  ink_assert(!do_check_data(seq_read_size, io->aiocb.aio_offset));
+  if (!hotset_idx)
+    fprintf(stderr, "Starting hotset document writing \n");
+  if (io->aiocb.aio_offset > max_offset) {
+    fprintf(stderr,
+            "Finished hotset documents  [%d] offset [%6.0f] size [%6.0f]\n",
+            hotset_idx, (float) MIN_OFFSET, (float) max_size);
+    SET_HANDLER(&AIO_Device::do_fd);
+    eventProcessor.schedule_imm(this);
+    return (0);
+  }
+  io->aiocb.aio_nbytes = seq_read_size;
+  io->aiocb.aio_buf = buf;
+  io->action = this;
+  io->thread = mutex->thread_holding;
+  ink_assert(ink_aio_write(io) >= 0);
+  hotset_idx++;
+  return 0;
+}
+
+int
+AIO_Device::do_fd(int event, Event * e)
+{
+  if (!time_start) {
+    time_start = ink_get_hrtime();
+    fprintf(stderr, "Starting the aio_testing \n");
+  }
+  if ((ink_get_hrtime() - time_start) > (run_time * HRTIME_SECOND)) {
+    time_end = ink_get_hrtime();
+    ink_atomic_increment(&n_accessors, -1);
+    if (n_accessors <= 0)
+      dump_summary();
+    return 0;
+  }
+
+  ink_off_t max_offset = ((ink_off_t) disk_size) * 1024 * 1024; // MB-GB
+  ink_off_t max_hotset_offset = ((ink_off_t) hotset_size) * 1024 * 1024;        // MB-GB
+  ink_off_t seq_read_point = ((ink_off_t) MIN_OFFSET);
+  ink_off_t seq_write_point = ((ink_off_t) MIN_OFFSET) + max_offset / 2 + write_after * 1024 * 1024;
+  seq_write_point += (id % n_disk_path) * (max_offset / (threads_per_disk * 4));
+  if (seq_write_point > max_offset)
+    seq_write_point = MIN_OFFSET;
+
+  if (io->aiocb.aio_lio_opcode == LIO_READ) {
+    ink_assert(!do_check_data(io->aiocb.aio_nbytes, io->aiocb.aio_offset));
+  }
+  memset((void *) buf, 0, max_size);
+  io->aiocb.aio_fildes = fd;
+  io->aiocb.aio_buf = buf;
+  io->action = this;
+  io->thread = mutex->thread_holding;
+
+  switch (select_mode(drand48())) {
+  case READ_MODE:
+    io->aiocb.aio_offset = seq_read_point;
+    io->aiocb.aio_nbytes = seq_read_size;
+    io->aiocb.aio_lio_opcode = LIO_READ;
+    ink_assert(ink_aio_read(io) >= 0);
+    seq_read_point += seq_read_size;
+    if (seq_read_point > max_offset)
+      seq_read_point = MIN_OFFSET;
+    seq_reads++;
+    break;
+  case WRITE_MODE:
+    io->aiocb.aio_offset = seq_write_point;
+    io->aiocb.aio_nbytes = seq_write_size;
+    io->aiocb.aio_lio_opcode = LIO_WRITE;
+    do_touch_data(seq_write_size, ((int) seq_write_point) % 1024);
+    ink_assert(ink_aio_write(io) >= 0);
+    seq_write_point += seq_write_size;
+    seq_write_point += write_skip;
+    if (seq_write_point > max_offset)
+      seq_write_point = MIN_OFFSET;
+
+    seq_writes++;
+    break;
+  case RANDOM_READ_MODE:{
+      // fprintf(stderr, "random read started \n");
+      double p, f;
+      p = drand48();
+      f = drand48();
+      ink_off_t o = 0;
+      if (f < hotset_frequency)
+        o = (ink_off_t) p *max_hotset_offset;
+      else
+        o = (ink_off_t) p *(max_offset - rand_read_size);
+      if (o < MIN_OFFSET)
+        o = MIN_OFFSET;
+      o = (o + (seq_read_size - 1)) & (~(seq_read_size - 1));
+      io->aiocb.aio_offset = o;
+      io->aiocb.aio_nbytes = rand_read_size;
+      io->aiocb.aio_lio_opcode = LIO_READ;
+      ink_assert(ink_aio_read(io) >= 0);
+      rand_reads++;
+      break;
+    }
+  }
+  return 0;
+}
+
+#define PARAM(_s) \
+        else if (strcmp(field_name, #_s) == 0) { \
+            fin >> _s; \
+            cout << "reading " #_s " = "  \
+                 << _s << endl; \
+				  }
+
+int
+read_config(const char *config_filename)
+{
+  ifstream fin(config_filename);
+  char field_name[256];
+  char field_value[256];
+
+  if (!fin.rdbuf()->is_open()) {
+    fin.open("sample.cfg");
+    if (!fin.rdbuf()->is_open()) {
+      cout << "cannot open config files " << config_filename << endl;
+      return (0);
+    }
+  }
+  while (!fin.eof()) {
+    field_name[0] = '\0';
+    fin >> field_name;
+    if (0) {
+    }
+    PARAM(hotset_size)
+      PARAM(hotset_frequency)
+      PARAM(touch_data)
+      PARAM(use_lseek)
+      PARAM(write_after)
+      PARAM(write_skip)
+      PARAM(disk_size)
+      PARAM(seq_read_percent)
+      PARAM(seq_write_percent)
+      PARAM(rand_read_percent)
+      PARAM(seq_read_size)
+      PARAM(seq_write_size)
+      PARAM(rand_read_size)
+      PARAM(run_time)
+      PARAM(chains)
+      PARAM(threads_per_disk)
+      PARAM(delete_disks)
+      else if (strcmp(field_name, "disk_path") == 0) {
+      assert(n_disk_path < MAX_DISK_THREADS);
+      fin >> field_value;
+      disk_path[n_disk_path] = xstrdup(field_value);
+      cout << "reading disk_path = " << disk_path[n_disk_path] << endl;
+      n_disk_path++;
+    }
+  }
+  assert(read_size > 0);
+  int t = seq_read_size + seq_write_size + rand_read_size;
+  real_seq_read_percent = seq_read_percent;
+  real_seq_write_percent = seq_write_percent;
+  real_rand_read_percent = rand_read_percent;
+  if (seq_read_size)
+    real_seq_read_percent *= t / seq_read_size;
+  if (seq_write_size)
+    real_seq_write_percent *= t / seq_write_size;
+  if (rand_read_size)
+    real_rand_read_percent *= t / rand_read_size;
+  float tt = real_seq_read_percent + real_seq_write_percent + real_rand_read_percent;
+  real_seq_read_percent = real_seq_read_percent / tt;
+  real_seq_write_percent = real_seq_write_percent / tt;
+  real_rand_read_percent = real_rand_read_percent / tt;
+  return (1);
+}
+
+
+
+
+int
+main(int argc, char *argv[])
+{
+  int i;
+  int num_net_threads = ink_number_of_processors();
+  init_diags("", NULL);
+  RecProcessInit(RECM_STAND_ALONE);
+  ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION);
+  eventProcessor.start(num_net_threads);
+  RecProcessStart();
+  ink_aio_init(AIO_MODULE_VERSION);
+  srand48(time(NULL));
+
+  if (!read_config(argv[1]))
+    exit(1);
+
+  max_size = seq_read_size;
+  if (seq_write_size > max_size)
+    max_size = seq_write_size;
+  if (rand_read_size > max_size)
+    max_size = rand_read_size;
+
+
+  cache_config_threads_per_disk = threads_per_disk;
+  orig_n_accessors = n_disk_path * threads_per_disk;
+
+  for (i = 0; i < n_disk_path; i++) {
+    for (int j = 0; j < threads_per_disk; j++) {
+      dev[n_accessors] = new AIO_Device(new_ProxyMutex());
+      dev[n_accessors]->id = i * threads_per_disk + j;
+      dev[n_accessors]->path = disk_path[i];
+      dev[n_accessors]->seq_reads = 0;
+      dev[n_accessors]->seq_writes = 0;
+      dev[n_accessors]->rand_reads = 0;
+      dev[n_accessors]->fd = open(dev[n_accessors]->path, O_RDWR | O_CREAT);
+      fchmod(dev[n_accessors]->fd, S_IRWXU | S_IRWXG);
+      if (dev[n_accessors]->fd < 0) {
+        perror(disk_path[i]);
+        exit(1);
+      }
+      dev[n_accessors]->buf = (char *) valloc(max_size);
+      eventProcessor.schedule_imm(dev[n_accessors]);
+      n_accessors++;
+    }
+  }
+
+  this_thread()->execute();
+}
diff --git a/iocore/aio/test_I_AIO.cc b/iocore/aio/test_I_AIO.cc
new file mode 100644
index 00000000..bd6f8260
--- /dev/null
+++ b/iocore/aio/test_I_AIO.cc
@@ -0,0 +1,25 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "I_AIO.h"
+#include "test_AIO.i"
diff --git a/iocore/aio/test_P_AIO.cc b/iocore/aio/test_P_AIO.cc
new file mode 100644
index 00000000..2af02cde
--- /dev/null
+++ b/iocore/aio/test_P_AIO.cc
@@ -0,0 +1,25 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "P_AIO.h"
+#include "test_AIO.i"
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
new file mode 100644
index 00000000..58f5b8cd
--- /dev/null
+++ b/iocore/cache/Cache.cc
@@ -0,0 +1,2825 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+
+#include "P_Cache.h"
+
+// Cache Inspector and State Pages
+#ifdef NON_MODULAR
+#include "P_CacheTest.h"
+#include "StatPages.h"
+#endif
+
+#include "I_Layout.h"
+
+#ifdef HTTP_CACHE
+#include "HttpTransactCache.h"
+#include "HttpSM.h"
+#include "HttpCacheSM.h"
+#include "InkAPIInternal.h"
+#endif
+
+// Compilation Options
+
+#define USELESS_REENABLES       // allow them for now
+// #define VERIFY_JTEST_DATA
+
+#define DOCACHE_CLEAR_DYN_STAT(x) \
+do { \
+	RecSetRawStatSum(rsb, x, 0); \
+	RecSetRawStatCount(rsb, x, 0); \
+} while (0);
+
+// Configuration
+
+int64_t cache_config_ram_cache_size = AUTO_SIZE_RAM_CACHE;
+int cache_config_ram_cache_algorithm = 0;
+int cache_config_ram_cache_compress = 0;
+int cache_config_ram_cache_compress_percent = 90;
+int cache_config_http_max_alts = 3;
+int cache_config_dir_sync_frequency = 60;
+int cache_config_permit_pinning = 0;
+int cache_config_vary_on_user_agent = 0;
+int cache_config_select_alternate = 1;
+int cache_config_max_doc_size = 0;
+int cache_config_min_average_object_size = ESTIMATED_OBJECT_SIZE;
+int64_t cache_config_ram_cache_cutoff = AGG_SIZE;
+int cache_config_max_disk_errors = 5;
+#ifdef HIT_EVACUATE
+int cache_config_hit_evacuate_percent = 10;
+int cache_config_hit_evacuate_size_limit = 0;
+#endif
+int cache_config_force_sector_size = 0;
+int cache_config_target_fragment_size = DEFAULT_TARGET_FRAGMENT_SIZE;
+int cache_config_agg_write_backlog = AGG_SIZE * 2;
+int cache_config_enable_checksum = 0;
+int cache_config_alt_rewrite_max_size = 4096;
+int cache_config_read_while_writer = 0;
+char cache_system_config_directory[PATH_NAME_MAX + 1];
+int cache_config_mutex_retry_delay = 2;
+
+// Globals
+
+RecRawStatBlock *cache_rsb = NULL;
+Cache *theStreamCache = 0;
+Cache *theCache = 0;
+CacheDisk **gdisks = NULL;
+int gndisks = 0;
+static volatile int initialize_disk = 0;
+Cache *caches[NUM_CACHE_FRAG_TYPES] = { 0 };
+CacheSync *cacheDirSync = 0;
+Store theCacheStore;
+volatile int CacheProcessor::initialized = CACHE_INITIALIZING;
+volatile uint32_t CacheProcessor::cache_ready = 0;
+volatile int CacheProcessor::start_done = 0;
+int CacheProcessor::clear = 0;
+int CacheProcessor::fix = 0;
+int CacheProcessor::start_internal_flags = 0;
+int CacheProcessor::auto_clear_flag = 0;
+CacheProcessor cacheProcessor;
+Vol **gvol = NULL;
+volatile int gnvol = 0;
+ClassAllocator cacheVConnectionAllocator("cacheVConnection");
+ClassAllocator evacuationBlockAllocator("evacuationBlock");
+ClassAllocator cacheRemoveContAllocator("cacheRemoveCont");
+ClassAllocator evacuationKeyAllocator("evacuationKey");
+int CacheVC::size_to_init = -1;
+CacheKey zero_key(0, 0);
+
+void verify_cache_api() {
+  ink_assert((int)TS_EVENT_CACHE_OPEN_READ == (int)CACHE_EVENT_OPEN_READ);
+  ink_assert((int)TS_EVENT_CACHE_OPEN_READ_FAILED == (int)CACHE_EVENT_OPEN_READ_FAILED);
+  ink_assert((int)TS_EVENT_CACHE_OPEN_WRITE == (int)CACHE_EVENT_OPEN_WRITE);
+  ink_assert((int)TS_EVENT_CACHE_OPEN_WRITE_FAILED == (int)CACHE_EVENT_OPEN_WRITE_FAILED);
+  ink_assert((int)TS_EVENT_CACHE_REMOVE == (int)CACHE_EVENT_REMOVE);
+  ink_assert((int)TS_EVENT_CACHE_REMOVE_FAILED == (int)CACHE_EVENT_REMOVE_FAILED);
+  ink_assert((int)TS_EVENT_CACHE_SCAN == (int)CACHE_EVENT_SCAN);
+  ink_assert((int)TS_EVENT_CACHE_SCAN_FAILED == (int)CACHE_EVENT_SCAN_FAILED);
+  ink_assert((int)TS_EVENT_CACHE_SCAN_OBJECT == (int)CACHE_EVENT_SCAN_OBJECT);
+  ink_assert((int)TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED == (int)CACHE_EVENT_SCAN_OPERATION_BLOCKED);
+  ink_assert((int)TS_EVENT_CACHE_SCAN_OPERATION_FAILED == (int)CACHE_EVENT_SCAN_OPERATION_FAILED);
+  ink_assert((int)TS_EVENT_CACHE_SCAN_DONE == (int)CACHE_EVENT_SCAN_DONE);
+}
+
+struct VolInitInfo
+{
+  off_t recover_pos;
+  AIOCallbackInternal vol_aio[4];
+  char *vol_h_f;
+
+  VolInitInfo()
+  {
+    recover_pos = 0;
+    if ((vol_h_f = (char *) valloc(4 * STORE_BLOCK_SIZE)) != NULL)
+      memset(vol_h_f, 0, 4 * STORE_BLOCK_SIZE);
+  }
+  ~VolInitInfo()
+  {
+    for (int i = 0; i < 4; i++) {
+      vol_aio[i].action = NULL;
+      vol_aio[i].mutex.clear();
+    }
+    free(vol_h_f);
+  }
+};
+
+void cplist_init();
+static void cplist_update();
+int cplist_reconfigure();
+static int create_volume(int volume_number, off_t size_in_blocks, int scheme, CacheVol *cp);
+static void rebuild_host_table(Cache *cache);
+void register_cache_stats(RecRawStatBlock *rsb, const char *prefix);
+
+Queue cp_list;
+int cp_list_len = 0;
+ConfigVolumes config_volumes;
+
+#if TS_HAS_TESTS
+void force_link_CacheTestCaller() {
+  force_link_CacheTest();
+}
+#endif
+
+int64_t
+cache_bytes_used(int volume)
+{
+  uint64_t used = 0;
+  int start = 0; // These defaults are for volume 0, or volume 1 with volume.config
+  int end = 1;
+
+  if (-1 == volume) {
+    end = gnvol;
+  } else if (volume > 1) { // Special case when volume.config is used
+    start = volume - 1;
+    end = volume;
+  }
+  
+  for (int i = start; i < end; i++) {
+    if (!DISK_BAD(gvol[i]->disk)) {
+      if (!gvol[i]->header->cycle)
+          used += gvol[i]->header->write_pos - gvol[i]->start;
+      else
+          used += gvol[i]->len - vol_dirlen(gvol[i]) - EVACUATION_SIZE;
+    }
+  }
+  return used;
+}
+
+int
+cache_stats_bytes_used_cb(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id)
+{
+  int volume = -1;
+
+  NOWARN_UNUSED(data_type);
+  NOWARN_UNUSED(data);
+
+  // Well, there's no way to pass along the volume ID, so extracting it from the stat name.
+  if (0 == strncmp(name+20, "volume_", 10))
+    volume = strtol(name+30, NULL, 10);
+
+  if (cacheProcessor.initialized == CACHE_INITIALIZED)
+    RecSetGlobalRawStatSum(rsb, id, cache_bytes_used(volume));
+
+  RecRawStatSyncSum(name, data_type, data, rsb, id);
+
+  return 1;
+}
+
+static int
+validate_rww(int new_value)
+{
+  if (new_value) {
+    float http_bg_fill;
+
+    IOCORE_ReadConfigFloat(http_bg_fill, "proxy.config.http.background_fill_completed_threshold");
+    if (http_bg_fill > 0.0) {
+      Note("to enable reading while writing a document, %s should be 0.0: read while writing disabled",
+           "proxy.config.http.background_fill_completed_threshold");
+      return 0;
+    }
+    if (cache_config_max_doc_size > 0) {
+      Note("to enable reading while writing a document, %s should be 0: read while writing disabled",
+           "proxy.config.cache.max_doc_size");
+      return 0;
+    }
+    return new_value;
+  }
+  return 0;
+}
+
+static int
+update_cache_config(const char *name, RecDataT data_type, RecData data, void *cookie)
+{
+  NOWARN_UNUSED(name);
+  NOWARN_UNUSED(data_type);
+  NOWARN_UNUSED(cookie);
+
+  volatile int new_value = validate_rww(data.rec_int);
+  cache_config_read_while_writer = new_value;
+
+  return 0;
+}
+
+CacheVC::CacheVC():alternate_index(CACHE_ALT_INDEX_DEFAULT)
+{
+  size_to_init = sizeof(CacheVC) - (size_t) & ((CacheVC *) 0)->vio;
+  memset((char *) &vio, 0, size_to_init);
+  // the constructor does a memset() on the members that need to be initialized
+  //coverity[uninit_member]
+}
+
+VIO *
+CacheVC::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *abuf)
+{
+  ink_assert(vio.op == VIO::READ);
+  vio.buffer.writer_for(abuf);
+  vio.set_continuation(c);
+  vio.ndone = 0;
+  vio.nbytes = nbytes;
+  vio.vc_server = this;
+  ink_assert(c->mutex->thread_holding);
+  if (!trigger && !recursive)
+    trigger = c->mutex->thread_holding->schedule_imm_local(this);
+  return &vio;
+}
+
+VIO *
+CacheVC::do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *abuf, int64_t offset)
+{
+  NOWARN_UNUSED(nbytes);
+  ink_assert(vio.op == VIO::READ);
+  vio.buffer.writer_for(abuf);
+  vio.set_continuation(c);
+  vio.ndone = 0;
+  vio.nbytes = nbytes;
+  vio.vc_server = this;
+  seek_to = offset;
+  ink_assert(c->mutex->thread_holding);
+  if (!trigger && !recursive)
+    trigger = c->mutex->thread_holding->schedule_imm_local(this);
+  return &vio;
+}
+
+VIO *
+CacheVC::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuf, bool owner)
+{
+  ink_assert(vio.op == VIO::WRITE);
+  ink_assert(!owner);
+  vio.buffer.reader_for(abuf);
+  vio.set_continuation(c);
+  vio.ndone = 0;
+  vio.nbytes = nbytes;
+  vio.vc_server = this;
+  ink_assert(c->mutex->thread_holding);
+  if (!trigger && !recursive)
+    trigger = c->mutex->thread_holding->schedule_imm_local(this);
+  return &vio;
+}
+
+void
+CacheVC::do_io_close(int alerrno)
+{
+  ink_debug_assert(mutex->thread_holding == this_ethread());
+  int previous_closed = closed;
+  closed = (alerrno == -1) ? 1 : -1;    // Stupid default arguments
+  DDebug("cache_close", "do_io_close %p %d %d", this, alerrno, closed);
+  if (!previous_closed && !recursive)
+    die();
+}
+
+void
+CacheVC::reenable(VIO *avio)
+{
+  DDebug("cache_reenable", "reenable %p", this);
+  (void) avio;
+  ink_assert(avio->mutex->thread_holding);
+  if (!trigger) {
+#ifndef USELESS_REENABLES
+    if (vio.op == VIO::READ) {
+      if (vio.buffer.mbuf->max_read_avail() > vio.buffer.writer()->water_mark)
+        ink_assert(!"useless reenable of cache read");
+    } else if (!vio.buffer.reader()->read_avail())
+      ink_assert(!"useless reenable of cache write");
+#endif
+    trigger = avio->mutex->thread_holding->schedule_imm_local(this);
+  }
+}
+
+void
+CacheVC::reenable_re(VIO *avio)
+{
+  DDebug("cache_reenable", "reenable_re %p", this);
+  (void) avio;
+  ink_assert(avio->mutex->thread_holding);
+  if (!trigger) {
+    if (!is_io_in_progress() && !recursive) {
+      handleEvent(EVENT_NONE, (void *) 0);
+    } else
+      trigger = avio->mutex->thread_holding->schedule_imm_local(this);
+  }
+}
+
+bool
+CacheVC::get_data(int i, void *data)
+{
+  switch (i) {
+  case CACHE_DATA_SIZE:
+    *((int *) data) = doc_len;
+    return true;
+#ifdef HTTP_CACHE
+  case CACHE_DATA_HTTP_INFO:
+    *((CacheHTTPInfo **) data) = &alternate;
+    return true;
+#endif
+  case CACHE_DATA_RAM_CACHE_HIT_FLAG:
+    *((int *) data) = !f.not_from_ram_cache;
+    return true;
+  default:
+    break;
+  }
+  return false;
+}
+
+int64_t
+CacheVC::get_object_size()
+{
+  return ((CacheVC *) this)->doc_len;
+}
+
+bool CacheVC::set_data(int i, void *data)
+{
+  (void) i;
+  (void) data;
+  ink_debug_assert(!"CacheVC::set_data should not be called!");
+  return true;
+}
+
+#ifdef HTTP_CACHE
+void
+CacheVC::get_http_info(CacheHTTPInfo ** ainfo)
+{
+  *ainfo = &((CacheVC *) this)->alternate;
+}
+
+// set_http_info must be called before do_io_write
+// cluster vc does an optimization where it calls do_io_write() before
+// calling set_http_info(), but it guarantees that the info will
+// be set before transferring any bytes
+void
+CacheVC::set_http_info(CacheHTTPInfo *ainfo)
+{
+  ink_assert(!total_len);
+  if (f.update) {
+    ainfo->object_key_set(update_key);
+    ainfo->object_size_set(update_len);
+  } else {
+    ainfo->object_key_set(earliest_key);
+    // don't know the total len yet
+  }
+  alternate.copy_shallow(ainfo);
+  ainfo->clear();
+}
+#endif
+
+bool CacheVC::set_pin_in_cache(time_t time_pin)
+{
+  if (total_len) {
+    ink_assert(!"should Pin the document before writing");
+    return false;
+  }
+  if (vio.op != VIO::WRITE) {
+    ink_assert(!"Pinning only allowed while writing objects to the cache");
+    return false;
+  }
+  pin_in_cache = time_pin;
+  return true;
+}
+
+bool CacheVC::set_disk_io_priority(int priority)
+{
+
+  ink_assert(priority >= AIO_LOWEST_PRIORITY);
+  io.aiocb.aio_reqprio = priority;
+  return true;
+}
+
+time_t CacheVC::get_pin_in_cache()
+{
+  return pin_in_cache;
+}
+
+int
+CacheVC::get_disk_io_priority()
+{
+  return io.aiocb.aio_reqprio;
+}
+
+int
+Vol::begin_read(CacheVC *cont)
+{
+  ink_debug_assert(cont->mutex->thread_holding == this_ethread());
+  ink_debug_assert(mutex->thread_holding == this_ethread());
+#ifdef CACHE_STAT_PAGES
+  ink_assert(!cont->stat_link.next && !cont->stat_link.prev);
+  stat_cache_vcs.enqueue(cont, cont->stat_link);
+#endif
+  // no need for evacuation as the entire document is already in memory
+  if (cont->f.single_fragment)
+    return 0;
+  int i = dir_evac_bucket(&cont->earliest_dir);
+  EvacuationBlock *b;
+  for (b = evacuate[i].head; b; b = b->link.next) {
+    if (dir_offset(&b->dir) != dir_offset(&cont->earliest_dir))
+      continue;
+    if (b->readers)
+      b->readers = b->readers + 1;
+    return 0;
+  }
+  // we don't actually need to preserve this block as it is already in
+  // memory, but this is easier, and evacuations are rare
+  EThread *t = cont->mutex->thread_holding;
+  b = new_EvacuationBlock(t);
+  b->readers = 1;
+  b->dir = cont->earliest_dir;
+  b->evac_frags.key = cont->earliest_key;
+  evacuate[i].push(b);
+  return 1;
+}
+
+int
+Vol::close_read(CacheVC *cont)
+{
+  EThread *t = cont->mutex->thread_holding;
+  ink_debug_assert(t == this_ethread());
+  ink_debug_assert(t == mutex->thread_holding);
+  if (dir_is_empty(&cont->earliest_dir))
+    return 1;
+  int i = dir_evac_bucket(&cont->earliest_dir);
+  EvacuationBlock *b;
+  for (b = evacuate[i].head; b;) {
+    EvacuationBlock *next = b->link.next;
+    if (dir_offset(&b->dir) != dir_offset(&cont->earliest_dir)) {
+      b = next;
+      continue;
+    }
+    if (b->readers && !--b->readers) {
+      evacuate[i].remove(b);
+      free_EvacuationBlock(b, t);
+      break;
+    }
+    b = next;
+  }
+#ifdef CACHE_STAT_PAGES
+  stat_cache_vcs.remove(cont, cont->stat_link);
+  ink_assert(!cont->stat_link.next && !cont->stat_link.prev);
+#endif
+  return 1;
+}
+
+// Cache Processor
+
+int
+CacheProcessor::start(int)
+{
+  return start_internal(0);
+}
+
+int
+CacheProcessor::start_internal(int flags)
+{
+#ifdef NON_MODULAR
+  verify_cache_api();
+#endif
+
+  start_internal_flags = flags;
+  clear = !!(flags & PROCESSOR_RECONFIGURE) || auto_clear_flag;
+  fix = !!(flags & PROCESSOR_FIX);
+  int i;
+  start_done = 0;
+  int diskok = 1;
+
+  /* read the config file and create the data structures corresponding
+     to the file */
+  gndisks = theCacheStore.n_disks;
+  gdisks = (CacheDisk **) xmalloc(gndisks * sizeof(CacheDisk *));
+
+  gndisks = 0;
+  ink_aio_set_callback(new AIO_Callback_handler());
+  Span *sd;
+  config_volumes.read_config_file();
+  for (i = 0; i < theCacheStore.n_disks; i++) {
+    sd = theCacheStore.disk[i];
+    char path[PATH_MAX];
+    int opts = O_RDWR;
+    ink_strlcpy(path, sd->pathname, sizeof(path));
+    if (!sd->file_pathname) {
+#if !defined(_WIN32)
+      if (config_volumes.num_http_volumes && config_volumes.num_stream_volumes) {
+        Warning("It is suggested that you use raw disks if streaming and http are in the same cache");
+      }
+#endif
+      ink_strlcat(path, "/cache.db", sizeof(path));
+      opts |= O_CREAT;
+    }
+    opts |= _O_ATTRIB_OVERLAPPED;
+#ifdef O_DIRECT
+    opts |= O_DIRECT;
+#endif
+#ifdef O_DSYNC
+    opts |= O_DSYNC;
+#endif
+
+    int fd = open(path, opts, 0644);
+    int blocks = sd->blocks;
+    if (fd > 0) {
+#if defined (_WIN32)
+      aio_completion_port.register_handle((void *) fd, 0);
+#endif
+      if (!sd->file_pathname) {
+        if (ftruncate(fd, ((uint64_t) blocks) * STORE_BLOCK_SIZE) < 0) {
+          Warning("unable to truncate cache file '%s' to %d blocks", path, blocks);
+          diskok = 0;
+#if defined(_WIN32)
+          /* We can do a specific check for FAT32 systems on NT,
+           * to print a specific warning */
+          if ((((uint64_t) blocks) * STORE_BLOCK_SIZE) > (1 << 32)) {
+            Warning("If you are using a FAT32 file system, please ensure that cachesize"
+                    "specified in storage.config, does not exceed 4GB!. ");
+          }
+#endif
+        }
+      }
+      if (diskok) {
+        gdisks[gndisks] = NEW(new CacheDisk());
+        Debug("cache_hosting", "Disk: %d, blocks: %d", gndisks, blocks);
+        int sector_size = sd->hw_sector_size;
+        if (sector_size < cache_config_force_sector_size)
+          sector_size = cache_config_force_sector_size;
+        if (sd->hw_sector_size <= 0 || sector_size > STORE_BLOCK_SIZE) {
+          Warning("bad hardware sector size %d, resetting to %d", sector_size, STORE_BLOCK_SIZE);
+          sector_size = STORE_BLOCK_SIZE;
+        }
+        off_t skip = ROUND_TO_STORE_BLOCK((sd->offset < START_POS ? START_POS + sd->alignment : sd->offset));
+        blocks = blocks - ROUND_TO_STORE_BLOCK(sd->offset + skip);
+        gdisks[gndisks]->open(path, blocks, skip, sector_size, fd, clear);
+        gndisks++;
+      }
+    } else
+      Warning("cache unable to open '%s': %s", path, strerror(errno));
+  }
+
+  if (gndisks == 0) {
+    Warning("unable to open cache disk(s): Cache Disabled\n");
+    return -1;
+  }
+  start_done = 1;
+
+  return 0;
+}
+
+void
+CacheProcessor::diskInitialized()
+{
+  ink_atomic_increment(&initialize_disk, 1);
+  int bad_disks = 0;
+  int res = 0;
+  if (initialize_disk == gndisks) {
+
+    int i;
+    for (i = 0; i < gndisks; i++) {
+      if (DISK_BAD(gdisks[i]))
+        bad_disks++;
+    }
+
+    if (bad_disks != 0) {
+      // create a new array
+      CacheDisk **p_good_disks;
+      if ((gndisks - bad_disks) > 0)
+        p_good_disks = (CacheDisk **) xmalloc((gndisks - bad_disks) * sizeof(CacheDisk *));
+      else
+        p_good_disks = 0;
+
+      int insert_at = 0;
+      for (i = 0; i < gndisks; i++) {
+        if (DISK_BAD(gdisks[i])) {
+          delete gdisks[i];
+          continue;
+        }
+        if (p_good_disks != NULL) {
+          p_good_disks[insert_at++] = gdisks[i];
+        }
+      }
+      xfree(gdisks);
+      gdisks = p_good_disks;
+      gndisks = gndisks - bad_disks;
+    }
+
+    /* create the cachevol list only if num volumes are greater
+       than 0. */
+    if (config_volumes.num_volumes == 0) {
+      res = cplist_reconfigure();
+      /* if no volumes, default to just an http cache */
+    } else {
+      // else
+      /* create the cachevol list. */
+      cplist_init();
+      /* now change the cachevol list based on the config file */
+      res = cplist_reconfigure();
+    }
+
+    if (res == -1) {
+      /* problems initializing the volume.config. Punt */
+      gnvol = 0;
+      cacheInitialized();
+      return;
+    } else {
+      CacheVol *cp = cp_list.head;
+      for (; cp; cp = cp->link.next) {
+        cp->vol_rsb = RecAllocateRawStatBlock((int) cache_stat_count);
+        char vol_stat_str_prefix[256];
+        snprintf(vol_stat_str_prefix, sizeof(vol_stat_str_prefix), "proxy.process.cache.volume_%d", cp->vol_number);
+        register_cache_stats(cp->vol_rsb, vol_stat_str_prefix);
+      }
+    }
+
+    gvol = (Vol **) xmalloc(gnvol * sizeof(Vol *));
+    memset(gvol, 0, gnvol * sizeof(Vol *));
+    gnvol = 0;
+    for (i = 0; i < gndisks; i++) {
+      CacheDisk *d = gdisks[i];
+      if (is_debug_tag_set("cache_hosting")) {
+        int j;
+        Debug("cache_hosting", "Disk: %d: Vol Blocks: %ld: Free space: %ld",
+              i, d->header->num_diskvol_blks, d->free_space);
+        for (j = 0; j < (int) d->header->num_volumes; j++) {
+          Debug("cache_hosting", "\tVol: %d Size: %d", d->disk_vols[j]->vol_number, d->disk_vols[j]->size);
+        }
+        for (j = 0; j < (int) d->header->num_diskvol_blks; j++) {
+          Debug("cache_hosting", "\tBlock No: %d Size: %d Free: %d",
+                d->header->vol_info[j].number, d->header->vol_info[j].len, d->header->vol_info[j].free);
+        }
+      }
+      d->sync();
+    }
+    if (config_volumes.num_volumes == 0) {
+      theCache = NEW(new Cache());
+      theCache->scheme = CACHE_HTTP_TYPE;
+      theCache->open(clear, fix);
+      return;
+    }
+    if (config_volumes.num_http_volumes != 0) {
+      theCache = NEW(new Cache());
+      theCache->scheme = CACHE_HTTP_TYPE;
+      theCache->open(clear, fix);
+    }
+
+    if (config_volumes.num_stream_volumes != 0) {
+      theStreamCache = NEW(new Cache());
+      theStreamCache->scheme = CACHE_RTSP_TYPE;
+      theStreamCache->open(clear, fix);
+    }
+
+  }
+}
+
+void
+CacheProcessor::cacheInitialized()
+{
+  int i;
+
+  if ((theCache && (theCache->ready == CACHE_INITIALIZING)) ||
+      (theStreamCache && (theStreamCache->ready == CACHE_INITIALIZING)))
+    return;
+  int caches_ready = 0;
+  int cache_init_ok = 0;
+  /* allocate ram size in proportion to the disk space the
+     volume accupies */
+  int64_t total_size = 0;
+  uint64_t total_cache_bytes = 0;
+  uint64_t total_direntries = 0;
+  uint64_t used_direntries = 0;
+  uint64_t vol_total_cache_bytes = 0;
+  uint64_t vol_total_direntries = 0;
+  uint64_t vol_used_direntries = 0;
+  Vol *vol;
+
+  ProxyMutex *mutex = this_ethread()->mutex;
+
+  if (theCache) {
+    total_size += theCache->cache_size;
+    Debug("cache_init", "CacheProcessor::cacheInitialized - theCache, total_size = %" PRId64 " = %" PRId64 " MB",
+          total_size, total_size / ((1024 * 1024) / STORE_BLOCK_SIZE));
+  }
+  if (theStreamCache) {
+    total_size += theStreamCache->cache_size;
+    Debug("cache_init", "CacheProcessor::cacheInitialized - theStreamCache, total_size = %" PRId64 " = %" PRId64 " MB",
+          total_size, total_size / ((1024 * 1024) / STORE_BLOCK_SIZE));
+  }
+
+  if (theCache) {
+    if (theCache->ready == CACHE_INIT_FAILED) {
+      Debug("cache_init", "CacheProcessor::cacheInitialized - failed to initialize the cache for http: cache disabled");
+      Warning("failed to initialize the cache for http: cache disabled\n");
+    } else {
+      caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_HTTP);
+      caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_NONE);
+      caches[CACHE_FRAG_TYPE_HTTP] = theCache;
+      caches[CACHE_FRAG_TYPE_NONE] = theCache;
+    }
+  }
+  if (theStreamCache) {
+    if (theStreamCache->ready == CACHE_INIT_FAILED) {
+      Debug("cache_init",
+            "CacheProcessor::cacheInitialized - failed to initialize the cache for streaming: cache disabled");
+      Warning("failed to initialize the cache for streaming: cache disabled\n");
+    } else {
+      caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_RTSP);
+      caches[CACHE_FRAG_TYPE_RTSP] = theStreamCache;
+    }
+  }
+
+  if (caches_ready) {
+    Debug("cache_init", "CacheProcessor::cacheInitialized - caches_ready=0x%0X, gnvol=%d",
+          (unsigned int) caches_ready, gnvol);
+    int64_t ram_cache_bytes = 0;
+    if (gnvol) {
+      for (i = 0; i < gnvol; i++) {
+        switch (cache_config_ram_cache_algorithm) {
+          default:
+          case RAM_CACHE_ALGORITHM_CLFUS:
+            gvol[i]->ram_cache = new_RamCacheCLFUS();
+            break;
+          case RAM_CACHE_ALGORITHM_LRU:
+            gvol[i]->ram_cache = new_RamCacheLRU();
+            break;
+        }
+      }
+      if (cache_config_ram_cache_size == AUTO_SIZE_RAM_CACHE) {
+        Debug("cache_init", "CacheProcessor::cacheInitialized - cache_config_ram_cache_size == AUTO_SIZE_RAM_CACHE");
+        for (i = 0; i < gnvol; i++) {
+          vol = gvol[i];
+          gvol[i]->ram_cache->init(vol_dirlen(vol), vol);
+          ram_cache_bytes += vol_dirlen(gvol[i]);
+          Debug("cache_init", "CacheProcessor::cacheInitialized - ram_cache_bytes = %" PRId64 " = %" PRId64 "Mb",
+                ram_cache_bytes, ram_cache_bytes / (1024 * 1024));
+          /*
+             CACHE_VOL_SUM_DYN_STAT(cache_ram_cache_bytes_total_stat,
+             (int64_t)vol_dirlen(gvol[i]));
+           */
+          RecSetGlobalRawStatSum(vol->cache_vol->vol_rsb,
+                                 cache_ram_cache_bytes_total_stat, (int64_t) vol_dirlen(gvol[i]));
+          vol_total_cache_bytes = gvol[i]->len - vol_dirlen(gvol[i]);
+          total_cache_bytes += vol_total_cache_bytes;
+          Debug("cache_init", "CacheProcessor::cacheInitialized - total_cache_bytes = %" PRId64 " = %" PRId64 "Mb",
+                total_cache_bytes, total_cache_bytes / (1024 * 1024));
+
+          CACHE_VOL_SUM_DYN_STAT(cache_bytes_total_stat, vol_total_cache_bytes);
+
+
+          vol_total_direntries = gvol[i]->buckets * gvol[i]->segments * DIR_DEPTH;
+          total_direntries += vol_total_direntries;
+          CACHE_VOL_SUM_DYN_STAT(cache_direntries_total_stat, vol_total_direntries);
+
+
+          vol_used_direntries = dir_entries_used(gvol[i]);
+          CACHE_VOL_SUM_DYN_STAT(cache_direntries_used_stat, vol_used_direntries);
+          used_direntries += vol_used_direntries;
+        }
+
+      } else {
+        Debug("cache_init", "CacheProcessor::cacheInitialized - %" PRId64 " != AUTO_SIZE_RAM_CACHE",
+              cache_config_ram_cache_size);
+        int64_t http_ram_cache_size =
+          (theCache) ? (int64_t) (((double) theCache->cache_size / total_size) * cache_config_ram_cache_size) : 0;
+        Debug("cache_init", "CacheProcessor::cacheInitialized - http_ram_cache_size = %" PRId64 " = %" PRId64 "Mb",
+              http_ram_cache_size, http_ram_cache_size / (1024 * 1024));
+        int64_t stream_ram_cache_size = cache_config_ram_cache_size - http_ram_cache_size;
+        Debug("cache_init", "CacheProcessor::cacheInitialized - stream_ram_cache_size = %" PRId64 " = %" PRId64 "Mb",
+              stream_ram_cache_size, stream_ram_cache_size / (1024 * 1024));
+
+        // Dump some ram_cache size information in debug mode.
+        Debug("ram_cache", "config: size = %" PRId64 ", cutoff = %" PRId64 "",
+              cache_config_ram_cache_size, cache_config_ram_cache_cutoff);
+
+        for (i = 0; i < gnvol; i++) {
+          vol = gvol[i];
+          double factor;
+          if (gvol[i]->cache == theCache) {
+            factor = (double) (int64_t) (gvol[i]->len >> STORE_BLOCK_SHIFT) / (int64_t) theCache->cache_size;
+            Debug("cache_init", "CacheProcessor::cacheInitialized - factor = %f", factor);
+            gvol[i]->ram_cache->init((int64_t) (http_ram_cache_size * factor), vol);
+            ram_cache_bytes += (int64_t) (http_ram_cache_size * factor);
+            CACHE_VOL_SUM_DYN_STAT(cache_ram_cache_bytes_total_stat, (int64_t) (http_ram_cache_size * factor));
+          } else {
+            factor = (double) (int64_t) (gvol[i]->len >> STORE_BLOCK_SHIFT) / (int64_t) theStreamCache->cache_size;
+            Debug("cache_init", "CacheProcessor::cacheInitialized - factor = %f", factor);
+            gvol[i]->ram_cache->init((int64_t) (stream_ram_cache_size * factor), vol);
+            ram_cache_bytes += (int64_t) (stream_ram_cache_size * factor);
+            CACHE_VOL_SUM_DYN_STAT(cache_ram_cache_bytes_total_stat, (int64_t) (stream_ram_cache_size * factor));
+          }
+          Debug("cache_init", "CacheProcessor::cacheInitialized[%d] - ram_cache_bytes = %" PRId64 " = %" PRId64 "Mb",
+                i, ram_cache_bytes, ram_cache_bytes / (1024 * 1024));
+
+          vol_total_cache_bytes = gvol[i]->len - vol_dirlen(gvol[i]);
+          total_cache_bytes += vol_total_cache_bytes;
+          CACHE_VOL_SUM_DYN_STAT(cache_bytes_total_stat, vol_total_cache_bytes);
+          Debug("cache_init", "CacheProcessor::cacheInitialized - total_cache_bytes = %" PRId64 " = %" PRId64 "Mb",
+                total_cache_bytes, total_cache_bytes / (1024 * 1024));
+
+          vol_total_direntries = gvol[i]->buckets * gvol[i]->segments * DIR_DEPTH;
+          total_direntries += vol_total_direntries;
+          CACHE_VOL_SUM_DYN_STAT(cache_direntries_total_stat, vol_total_direntries);
+
+
+          vol_used_direntries = dir_entries_used(gvol[i]);
+          CACHE_VOL_SUM_DYN_STAT(cache_direntries_used_stat, vol_used_direntries);
+          used_direntries += vol_used_direntries;
+
+        }
+      }
+      switch (cache_config_ram_cache_compress) {
+        default:
+          Fatal("unknown RAM cache compression type: %d", cache_config_ram_cache_compress);
+        case CACHE_COMPRESSION_NONE: 
+        case CACHE_COMPRESSION_FASTLZ:
+          break;
+        case CACHE_COMPRESSION_LIBZ:
+#if ! TS_HAS_LIBZ
+          Fatal("libz not available for RAM cache compression");
+#endif
+          break;
+        case CACHE_COMPRESSION_LIBLZMA:
+#if ! TS_HAS_LZMA
+          Fatal("lzma not available for RAM cache compression");
+#endif
+          break;
+      }
+
+      GLOBAL_CACHE_SET_DYN_STAT(cache_ram_cache_bytes_total_stat, ram_cache_bytes);
+      GLOBAL_CACHE_SET_DYN_STAT(cache_bytes_total_stat, total_cache_bytes);
+      GLOBAL_CACHE_SET_DYN_STAT(cache_direntries_total_stat, total_direntries);
+      GLOBAL_CACHE_SET_DYN_STAT(cache_direntries_used_stat, used_direntries);
+      dir_sync_init();
+      cache_init_ok = 1;
+    } else
+      Warning("cache unable to open any vols, disabled");
+  }
+  if (cache_init_ok) {
+    // Initialize virtual cache
+    CacheProcessor::initialized = CACHE_INITIALIZED;
+    CacheProcessor::cache_ready = caches_ready;
+    Note("cache enabled");
+#ifdef CLUSTER_CACHE
+    if (!(start_internal_flags & PROCESSOR_RECONFIGURE)) {
+      CacheContinuation::init();
+      clusterProcessor.start();
+    }
+#endif
+  } else {
+    CacheProcessor::initialized = CACHE_INIT_FAILED;
+    Note("cache disabled");
+  }
+}
+
+void
+CacheProcessor::stop()
+{
+}
+
+int
+CacheProcessor::dir_check(bool afix)
+{
+  for (int i = 0; i < gnvol; i++)
+    gvol[i]->dir_check(afix);
+  return 0;
+}
+
+int
+CacheProcessor::db_check(bool afix)
+{
+  for (int i = 0; i < gnvol; i++)
+    gvol[i]->db_check(afix);
+  return 0;
+}
+
+int
+Vol::db_check(bool fix)
+{
+  (void) fix;
+  char tt[256];
+  printf("    Data for [%s]\n", hash_id);
+  printf("        Length:          %" PRIu64 "\n", (uint64_t)len);
+  printf("        Write Position:  %" PRIu64 "\n", (uint64_t) (header->write_pos - skip));
+  printf("        Phase:           %d\n", (int)!!header->phase);
+  ink_ctime_r(&header->create_time, tt);
+  tt[strlen(tt) - 1] = 0;
+  printf("        Create Time:     %s\n", tt);
+  printf("        Sync Serial:     %u\n", (unsigned int)header->sync_serial);
+  printf("        Write Serial:    %u\n", (unsigned int)header->write_serial);
+  printf("\n");
+
+  return 0;
+}
+
+static void
+vol_init_data_internal(Vol *d)
+{
+  d->buckets = ((d->len - (d->start - d->skip)) / cache_config_min_average_object_size) / DIR_DEPTH;
+  d->segments = (d->buckets + (((1<<16)-1)/DIR_DEPTH)) / ((1<<16)/DIR_DEPTH);
+  d->buckets = (d->buckets + d->segments - 1) / d->segments;
+  d->start = d->skip + 2 *vol_dirlen(d);
+}
+
+static void
+vol_init_data(Vol *d) {
+  // iteratively calculate start + buckets
+  vol_init_data_internal(d);
+  vol_init_data_internal(d);
+  vol_init_data_internal(d);
+}
+
+void
+vol_init_dir(Vol *d)
+{
+  int b, s, l;
+
+  for (s = 0; s < d->segments; s++) {
+    d->header->freelist[s] = 0;
+    Dir *seg = dir_segment(s, d);
+    for (l = 1; l < DIR_DEPTH; l++) {
+      for (b = 0; b < d->buckets; b++) {
+        Dir *bucket = dir_bucket(b, seg);
+        dir_free_entry(dir_bucket_row(bucket, l), s, d);
+      }
+    }
+  }
+}
+
+void
+vol_clear_init(Vol *d)
+{
+  size_t dir_len = vol_dirlen(d);
+  memset(d->raw_dir, 0, dir_len);
+  vol_init_dir(d);
+  d->header->magic = VOL_MAGIC;
+  d->header->version.ink_major = CACHE_DB_MAJOR_VERSION;
+  d->header->version.ink_minor = CACHE_DB_MINOR_VERSION;
+  d->scan_pos = d->header->agg_pos = d->header->write_pos = d->start;
+  d->header->last_write_pos = d->header->write_pos;
+  d->header->phase = 0;
+  d->header->cycle = 0;
+  d->header->create_time = time(NULL);
+  d->header->dirty = 0;
+  d->sector_size = d->header->sector_size = d->disk->hw_sector_size;
+  *d->footer = *d->header;
+}
+
+int
+vol_dir_clear(Vol *d)
+{
+  size_t dir_len = vol_dirlen(d);
+  vol_clear_init(d);
+
+  if (pwrite(d->fd, d->raw_dir, dir_len, d->skip) < 0) {
+    Warning("unable to clear cache directory '%s'", d->hash_id);
+    return -1;
+  }
+  return 0;
+}
+
+int
+Vol::clear_dir()
+{
+  size_t dir_len = vol_dirlen(this);
+  vol_clear_init(this);
+
+  SET_HANDLER(&Vol::handle_dir_clear);
+
+  io.aiocb.aio_fildes = fd;
+  io.aiocb.aio_buf = raw_dir;
+  io.aiocb.aio_nbytes = dir_len;
+  io.aiocb.aio_offset = skip;
+  io.action = this;
+  io.thread = AIO_CALLBACK_THREAD_ANY;
+  io.then = 0;
+  ink_assert(ink_aio_write(&io));
+  return 0;
+}
+
+int
+Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
+{
+  dir_skip = ROUND_TO_STORE_BLOCK((dir_skip < START_POS ? START_POS : dir_skip));
+  path = xstrdup(s);
+  const size_t hash_id_size = strlen(s) + 32;
+  hash_id = (char *) malloc(hash_id_size);
+  ink_strncpy(hash_id, s, hash_id_size);
+  const size_t s_size = strlen(s);
+  snprintf(hash_id + s_size, (hash_id_size - s_size), " %" PRIu64 ":%" PRIu64 "",
+           (uint64_t)dir_skip, (uint64_t)blocks);
+  hash_id_md5.encodeBuffer(hash_id, strlen(hash_id));
+  len = blocks * STORE_BLOCK_SIZE;
+  ink_assert(len <= MAX_VOL_SIZE);
+  skip = dir_skip;
+  int i;
+  prev_recover_pos = 0;
+
+  // successive approximation, directory/meta data eats up some storage
+  start = dir_skip;
+  vol_init_data(this);
+  data_blocks = (len - (start - skip)) / STORE_BLOCK_SIZE;
+#ifdef HIT_EVACUATE
+  hit_evacuate_window = (data_blocks * cache_config_hit_evacuate_percent) / 100;
+#endif
+
+  evacuate_size = (int) (len / EVACUATION_BUCKET_SIZE) + 2;
+  int evac_len = (int) evacuate_size * sizeof(DLL);
+  evacuate = (DLL *)malloc(evac_len);
+  memset(evacuate, 0, evac_len);
+
+#if !defined (_WIN32)
+  raw_dir = (char *) valloc(vol_dirlen(this));
+#else
+  /* the directory should be page aligned for raw disk transfers.
+     WIN32 does not support valloc
+     or memalign, so we need to allocate extra space and then align the
+     pointer ourselves.
+     Don't need to keep track of the pointer to the original memory since
+     we never free this */
+  size_t alignment = getpagesize();
+  size_t mem_to_alloc = vol_dirlen(this) + (alignment - 1);
+  raw_dir = (char *) malloc(mem_to_alloc);
+  raw_dir = (char *) align_pointer_forward(raw_dir, alignment);
+#endif
+
+  dir = (Dir *) (raw_dir + vol_headerlen(this));
+  header = (VolHeaderFooter *) raw_dir;
+  footer = (VolHeaderFooter *) (raw_dir + vol_dirlen(this) - ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter)));
+
+  if (clear) {
+    Note("clearing cache directory '%s'", hash_id);
+    return clear_dir();
+  }
+
+  init_info = new VolInitInfo();
+  int footerlen = ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter));
+  off_t footer_offset = vol_dirlen(this) - footerlen;
+  // try A
+  off_t as = skip;
+  if (is_debug_tag_set("cache_init"))
+    Note("reading directory '%s'", hash_id);
+  SET_HANDLER(&Vol::handle_header_read);
+  init_info->vol_aio[0].aiocb.aio_offset = as;
+  init_info->vol_aio[1].aiocb.aio_offset = as + footer_offset;
+  off_t bs = skip + vol_dirlen(this);
+  init_info->vol_aio[2].aiocb.aio_offset = bs;
+  init_info->vol_aio[3].aiocb.aio_offset = bs + footer_offset;
+
+  for (i = 0; i < 4; i++) {
+    AIOCallback *aio = &(init_info->vol_aio[i]);
+    aio->aiocb.aio_fildes = fd;
+    aio->aiocb.aio_buf = &(init_info->vol_h_f[i * STORE_BLOCK_SIZE]);
+    aio->aiocb.aio_nbytes = footerlen;
+    aio->action = this;
+    aio->thread = this_ethread();
+    aio->then = (i < 3) ? &(init_info->vol_aio[i + 1]) : 0;
+  }
+
+  eventProcessor.schedule_imm(this, ET_CALL);
+  return 0;
+}
+
+int
+Vol::handle_dir_clear(int event, void *data)
+{
+  size_t dir_len = vol_dirlen(this);
+  AIOCallback *op;
+
+  if (event == AIO_EVENT_DONE) {
+    op = (AIOCallback *) data;
+    if ((size_t) op->aio_result != (size_t) op->aiocb.aio_nbytes) {
+      Warning("unable to clear cache directory '%s'", hash_id);
+      fd = -1;
+    }
+
+    if (op->aiocb.aio_nbytes == dir_len) {
+      /* clear the header for directory B. We don't need to clear the
+         whole of directory B. The header for directory B starts at
+         skip + len */
+      op->aiocb.aio_nbytes = ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter));
+      op->aiocb.aio_offset = skip + dir_len;
+      ink_assert(ink_aio_write(op));
+      return EVENT_DONE;
+    }
+    set_io_not_in_progress();
+    SET_HANDLER(&Vol::dir_init_done);
+    dir_init_done(EVENT_IMMEDIATE, 0);
+    /* mark the volume as bad */
+  }
+  return EVENT_DONE;
+}
+
+int
+Vol::handle_dir_read(int event, void *data)
+{
+  AIOCallback *op = (AIOCallback *) data;
+
+  if (event == AIO_EVENT_DONE) {
+    if ((size_t) op->aio_result != (size_t) op->aiocb.aio_nbytes) {
+      clear_dir();
+      return EVENT_DONE;
+    }
+  }
+
+  if (header->magic != VOL_MAGIC || header->version.ink_major != CACHE_DB_MAJOR_VERSION || footer->magic != VOL_MAGIC) {
+    Warning("bad footer in cache directory for '%s', clearing", hash_id);
+    Note("clearing cache directory '%s'", hash_id);
+    clear_dir();
+    return EVENT_DONE;
+  }
+  CHECK_DIR(this);
+  sector_size = header->sector_size;
+  SET_HANDLER(&Vol::handle_recover_from_data);
+  return handle_recover_from_data(EVENT_IMMEDIATE, 0);
+}
+
+/*
+   Philosophy:  The idea is to find the region of disk that could be
+   inconsistent and remove all directory entries pointing to that potentially
+   inconsistent region.
+   Start from a consistent position (the write_pos of the last directory
+   synced to disk) and scan forward. Two invariants for docs that were
+   written to the disk after the directory was synced:
+
+   1. doc->magic == DOC_MAGIC
+
+   The following two cases happen only when the previous generation
+   documents are aligned with the current ones.
+
+   2. All the docs written to the disk
+   after the directory was synced will have their sync_serial <=
+   header->sync_serial + 1,  because the write aggregation can take
+   indeterminate amount of time to sync. The doc->sync_serial can be
+   equal to header->sync_serial + 1, because we increment the sync_serial
+   before we sync the directory to disk.
+
+   3. The doc->sync_serial will always increase. If doc->sync_serial
+   decreases, the document was written in the previous phase
+
+   If either of these conditions fail and we are not too close to the end
+   (see the next comment ) then we're done
+
+   We actually start from header->last_write_pos instead of header->write_pos
+   to make sure that we haven't wrapped around the whole disk without
+   syncing the directory.  Since the sync serial is 60 seconds, it is
+   entirely possible to write through the whole cache without
+   once syncing the directory. In this case, we need to clear the
+   cache.The documents written right before we synced the
+   directory to disk should have the write_serial <= header->sync_serial.
+
+      */
+
+int
+Vol::handle_recover_from_data(int event, void *data)
+{
+  (void) data;
+  uint32_t got_len = 0;
+  uint32_t max_sync_serial = header->sync_serial;
+  char *s, *e;
+  if (event == EVENT_IMMEDIATE) {
+    if (header->sync_serial == 0) {
+      io.aiocb.aio_buf = NULL;
+      SET_HANDLER(&Vol::handle_recover_write_dir);
+      return handle_recover_write_dir(EVENT_IMMEDIATE, 0);
+    }
+    // initialize
+    recover_wrapped = 0;
+    last_sync_serial = 0;
+    last_write_serial = 0;
+    recover_pos = header->last_write_pos;
+    if (recover_pos >= skip + len) {
+      recover_wrapped = 1;
+      recover_pos = start;
+    }
+#if defined(_WIN32)
+    io.aiocb.aio_buf = (char *) malloc(RECOVERY_SIZE);
+#else
+    io.aiocb.aio_buf = (char *) valloc(RECOVERY_SIZE);
+#endif
+    io.aiocb.aio_nbytes = RECOVERY_SIZE;
+    if ((off_t)(recover_pos + io.aiocb.aio_nbytes) > (off_t)(skip + len))
+      io.aiocb.aio_nbytes = (skip + len) - recover_pos;
+  } else if (event == AIO_EVENT_DONE) {
+    if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
+      Warning("disk read error on recover '%s', clearing", hash_id);
+      goto Lclear;
+    }
+    if (io.aiocb.aio_offset == header->last_write_pos) {
+
+      /* check that we haven't wrapped around without syncing
+         the directory. Start from last_write_serial (write pos the documents
+         were written to just before syncing the directory) and make sure
+         that all documents have write_serial <= header->write_serial.
+       */
+      uint32_t to_check = header->write_pos - header->last_write_pos;
+      ink_assert(to_check && to_check < (uint32_t)io.aiocb.aio_nbytes);
+      uint32_t done = 0;
+      s = (char *) io.aiocb.aio_buf;
+      while (done < to_check) {
+        Doc *doc = (Doc *) (s + done);
+        if (doc->magic != DOC_MAGIC || doc->write_serial > header->write_serial) {
+          Warning("no valid directory found while recovering '%s', clearing", hash_id);
+          goto Lclear;
+        }
+        done += round_to_approx_size(doc->len);
+        if (doc->sync_serial > last_write_serial)
+          last_sync_serial = doc->sync_serial;
+      }
+      ink_assert(done == to_check);
+
+      got_len = io.aiocb.aio_nbytes - done;
+      recover_pos += io.aiocb.aio_nbytes;
+      s = (char *) io.aiocb.aio_buf + done;
+      e = s + got_len;
+    } else {
+      got_len = io.aiocb.aio_nbytes;
+      recover_pos += io.aiocb.aio_nbytes;
+      s = (char *) io.aiocb.aio_buf;
+      e = s + got_len;
+    }
+  }
+  // examine what we got
+  if (got_len) {
+
+    Doc *doc = NULL;
+
+    if (recover_wrapped && start == io.aiocb.aio_offset) {
+      doc = (Doc *) s;
+      if (doc->magic != DOC_MAGIC || doc->write_serial < last_write_serial) {
+        recover_pos = skip + len - EVACUATION_SIZE;
+        goto Ldone;
+      }
+    }
+
+    while (s < e) {
+      doc = (Doc *) s;
+
+      if (doc->magic != DOC_MAGIC || doc->sync_serial != last_sync_serial) {
+
+        if (doc->magic == DOC_MAGIC) {
+          if (doc->sync_serial > header->sync_serial)
+            max_sync_serial = doc->sync_serial;
+
+          /*
+             doc->magic == DOC_MAGIC, but doc->sync_serial != last_sync_serial
+             This might happen in the following situations
+             1. We are starting off recovery. In this case the
+             last_sync_serial == header->sync_serial, but the doc->sync_serial
+             can be anywhere in the range (0, header->sync_serial + 1]
+             If this is the case, update last_sync_serial and continue;
+
+             2. A dir sync started between writing documents to the
+             aggregation buffer and hence the doc->sync_serial went up.
+             If the doc->sync_serial is greater than the last
+             sync serial and less than (header->sync_serial + 2) then
+             continue;
+
+             3. If the position we are recovering from is within AGG_SIZE
+             from the disk end, then we can't trust this document. The
+             aggregation buffer might have been larger than the remaining space
+             at the end and we decided to wrap around instead of writing
+             anything at that point. In this case, wrap around and start
+             from the beginning.
+
+             If neither of these 3 cases happen, then we are indeed done.
+
+           */
+
+          // case 1
+          // case 2
+          if (doc->sync_serial > last_sync_serial && doc->sync_serial <= header->sync_serial + 1) {
+            last_sync_serial = doc->sync_serial;
+            s += round_to_approx_size(doc->len);
+            continue;
+          }
+          // case 3 - we have already recoverd some data and
+          // (doc->sync_serial < last_sync_serial) ||
+          // (doc->sync_serial > header->sync_serial + 1).
+          // if we are too close to the end, wrap around
+          else if (recover_pos - (e - s) > (skip + len) - AGG_SIZE) {
+            recover_wrapped = 1;
+            recover_pos = start;
+            io.aiocb.aio_nbytes = RECOVERY_SIZE;
+
+            break;
+          }
+          // we are done. This doc was written in the earlier phase
+          recover_pos -= e - s;
+          goto Ldone;
+        } else {
+          // doc->magic != DOC_MAGIC
+          // If we are in the danger zone - recover_pos is within AGG_SIZE
+          // from the end, then wrap around
+          recover_pos -= e - s;
+          if (recover_pos > (skip + len) - AGG_SIZE) {
+            recover_wrapped = 1;
+            recover_pos = start;
+            io.aiocb.aio_nbytes = RECOVERY_SIZE;
+
+            break;
+          }
+          // we ar not in the danger zone
+          goto Ldone;
+        }
+      }
+      // doc->magic == DOC_MAGIC && doc->sync_serial == last_sync_serial
+      last_write_serial = doc->write_serial;
+      s += round_to_approx_size(doc->len);
+    }
+
+    /* if (s > e) then we gone through RECOVERY_SIZE; we need to
+       read more data off disk and continue recovering */
+    if (s >= e) {
+      /* In the last iteration, we increment s by doc->len...need to undo
+         that change */
+      if (s > e)
+        s -= round_to_approx_size(doc->len);
+      recover_pos -= e - s;
+      if (recover_pos >= skip + len)
+        recover_pos = start;
+      io.aiocb.aio_nbytes = RECOVERY_SIZE;
+      if ((off_t)(recover_pos + io.aiocb.aio_nbytes) > (off_t)(skip + len))
+        io.aiocb.aio_nbytes = (skip + len) - recover_pos;
+    }
+  }
+  if (recover_pos == prev_recover_pos) // this should never happen, but if it does break the loop
+    goto Lclear;
+  prev_recover_pos = recover_pos;
+  io.aiocb.aio_offset = recover_pos;
+  ink_assert(ink_aio_read(&io));
+  return EVENT_CONT;
+
+Ldone:{
+    /* if we come back to the starting position, then we don't have to recover anything */
+    if (recover_pos == header->write_pos && recover_wrapped) {
+      SET_HANDLER(&Vol::handle_recover_write_dir);
+      if (is_debug_tag_set("cache_init"))
+        Note("recovery wrapped around. nothing to clear\n");
+      return handle_recover_write_dir(EVENT_IMMEDIATE, 0);
+    }
+
+    recover_pos += EVACUATION_SIZE;   // safely cover the max write size
+    if (recover_pos < header->write_pos && (recover_pos + EVACUATION_SIZE >= header->write_pos)) {
+      Debug("cache_init", "Head Pos: %" PRIu64 ", Rec Pos: %" PRIu64 ", Wrapped:%d", header->write_pos, recover_pos, recover_wrapped);
+      Warning("no valid directory found while recovering '%s', clearing", hash_id);
+      goto Lclear;
+    }
+
+    if (recover_pos > skip + len)
+      recover_pos -= skip + len;
+    // bump sync number so it is different from that in the Doc structs
+    uint32_t next_sync_serial = max_sync_serial + 1;
+    // make that the next sync does not overwrite our good copy!
+    if (!(header->sync_serial & 1) == !(next_sync_serial & 1))
+      next_sync_serial++;
+    // clear effected portion of the cache
+    off_t clear_start = offset_to_vol_offset(this, header->write_pos);
+    off_t clear_end = offset_to_vol_offset(this, recover_pos);
+    if (clear_start <= clear_end)
+      dir_clear_range(clear_start, clear_end, this);
+    else {
+      dir_clear_range(clear_end, DIR_OFFSET_MAX, this);
+      dir_clear_range(1, clear_start, this);
+    }
+    if (is_debug_tag_set("cache_init"))
+      Note("recovery clearing offsets [%" PRIu64 ", %" PRIu64 "] sync_serial %d next %d\n",
+           header->write_pos, recover_pos, header->sync_serial, next_sync_serial);
+    footer->sync_serial = header->sync_serial = next_sync_serial;
+
+    for (int i = 0; i < 3; i++) {
+      AIOCallback *aio = &(init_info->vol_aio[i]);
+      aio->aiocb.aio_fildes = fd;
+      aio->action = this;
+      aio->thread = AIO_CALLBACK_THREAD_ANY;
+      aio->then = (i < 2) ? &(init_info->vol_aio[i + 1]) : 0;
+    }
+    int footerlen = ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter));
+    size_t dirlen = vol_dirlen(this);
+    int B = header->sync_serial & 1;
+    off_t ss = skip + (B ? dirlen : 0);
+
+    init_info->vol_aio[0].aiocb.aio_buf = raw_dir;
+    init_info->vol_aio[0].aiocb.aio_nbytes = footerlen;
+    init_info->vol_aio[0].aiocb.aio_offset = ss;
+    init_info->vol_aio[1].aiocb.aio_buf = raw_dir + footerlen;
+    init_info->vol_aio[1].aiocb.aio_nbytes = dirlen - 2 * footerlen;
+    init_info->vol_aio[1].aiocb.aio_offset = ss + footerlen;
+    init_info->vol_aio[2].aiocb.aio_buf = raw_dir + dirlen - footerlen;
+    init_info->vol_aio[2].aiocb.aio_nbytes = footerlen;
+    init_info->vol_aio[2].aiocb.aio_offset = ss + dirlen - footerlen;
+
+    SET_HANDLER(&Vol::handle_recover_write_dir);
+    ink_assert(ink_aio_write(init_info->vol_aio));
+    return EVENT_CONT;
+  }
+
+Lclear:
+  free((char *) io.aiocb.aio_buf);
+  delete init_info;
+  init_info = 0;
+  clear_dir();
+  return EVENT_CONT;
+}
+
+int
+Vol::handle_recover_write_dir(int event, void *data)
+{
+  (void) event;
+  (void) data;
+  if (io.aiocb.aio_buf)
+    free((char *) io.aiocb.aio_buf);
+  delete init_info;
+  init_info = 0;
+  set_io_not_in_progress();
+  scan_pos = header->write_pos;
+  periodic_scan();
+  SET_HANDLER(&Vol::dir_init_done);
+  return dir_init_done(EVENT_IMMEDIATE, 0);
+}
+
+int
+Vol::handle_header_read(int event, void *data)
+{
+  AIOCallback *op;
+  VolHeaderFooter *hf[4];
+  switch (event) {
+  case EVENT_IMMEDIATE:
+  case EVENT_INTERVAL:
+    ink_assert(ink_aio_read(init_info->vol_aio));
+    return EVENT_CONT;
+
+  case AIO_EVENT_DONE:
+    op = (AIOCallback *) data;
+    for (int i = 0; i < 4; i++) {
+      ink_assert(op != 0);
+      hf[i] = (VolHeaderFooter *) (op->aiocb.aio_buf);
+      if ((size_t) op->aio_result != (size_t) op->aiocb.aio_nbytes) {
+        clear_dir();
+        return EVENT_DONE;
+      }
+      op = op->then;
+    }
+
+    io.aiocb.aio_fildes = fd;
+    io.aiocb.aio_nbytes = vol_dirlen(this);
+    io.aiocb.aio_buf = raw_dir;
+    io.action = this;
+    io.thread = AIO_CALLBACK_THREAD_ANY;
+    io.then = 0;
+
+    if (hf[0]->sync_serial == hf[1]->sync_serial &&
+        (hf[0]->sync_serial >= hf[2]->sync_serial || hf[2]->sync_serial != hf[3]->sync_serial)) {
+      SET_HANDLER(&Vol::handle_dir_read);
+      if (is_debug_tag_set("cache_init"))
+        Note("using directory A for '%s'", hash_id);
+      io.aiocb.aio_offset = skip;
+      ink_assert(ink_aio_read(&io));
+    }
+    // try B
+    else if (hf[2]->sync_serial == hf[3]->sync_serial) {
+
+      SET_HANDLER(&Vol::handle_dir_read);
+      if (is_debug_tag_set("cache_init"))
+        Note("using directory B for '%s'", hash_id);
+      io.aiocb.aio_offset = skip + vol_dirlen(this);
+      ink_assert(ink_aio_read(&io));
+    } else {
+      Note("no good directory, clearing '%s'", hash_id);
+      clear_dir();
+      delete init_info;
+      init_info = 0;
+    }
+
+    return EVENT_DONE;
+  }
+  return EVENT_DONE;
+}
+
+int
+Vol::dir_init_done(int event, void *data)
+{
+  (void) event;
+  (void) data;
+  if (!cache->cache_read_done) {
+    eventProcessor.schedule_in(this, HRTIME_MSECONDS(5), ET_CALL);
+    return EVENT_CONT;
+  } else {
+    int vol_no = ink_atomic_increment(&gnvol, 1);
+    ink_assert(!gvol[vol_no]);
+    gvol[vol_no] = this;
+    SET_HANDLER(&Vol::aggWrite);
+    if (fd == -1)
+      cache->vol_initialized(0);
+    else
+      cache->vol_initialized(1);
+    return EVENT_DONE;
+  }
+}
+
+void
+build_vol_hash_table(CacheHostRecord *cp)
+{
+  int num_vols = cp->num_vols;
+  unsigned int *mapping = (unsigned int *) xmalloc(sizeof(unsigned int) * num_vols);
+  Vol **p = (Vol **) xmalloc(sizeof(Vol *) * num_vols);
+
+  memset(mapping, 0, num_vols * sizeof(unsigned int));
+  memset(p, 0, num_vols * sizeof(Vol *));
+  uint64_t total = 0;
+  int i = 0;
+  int used = 0;
+  int bad_vols = 0;
+  int map = 0;
+  // initialize number of elements per vol
+  for (i = 0; i < num_vols; i++) {
+    if (DISK_BAD(cp->vols[i]->disk)) {
+      bad_vols++;
+      continue;
+    }
+    mapping[map] = i;
+    p[map++] = cp->vols[i];
+    total += (cp->vols[i]->len >> STORE_BLOCK_SHIFT);
+  }
+
+  num_vols -= bad_vols;
+
+  if (!num_vols) {
+    // all the disks are corrupt,
+    if (cp->vol_hash_table) {
+      new_Freer(cp->vol_hash_table, CACHE_MEM_FREE_TIMEOUT);
+    }
+    cp->vol_hash_table = NULL;
+    xfree(mapping);
+    xfree(p);
+    return;
+  }
+
+
+  unsigned int *forvol = (unsigned int *) alloca(sizeof(unsigned int) * num_vols);
+  unsigned int *rnd = (unsigned int *) alloca(sizeof(unsigned int) * num_vols);
+  unsigned short *ttable = (unsigned short *) xmalloc(sizeof(unsigned short) * VOL_HASH_TABLE_SIZE);
+
+  for (i = 0; i < num_vols; i++) {
+    forvol[i] = (VOL_HASH_TABLE_SIZE * (p[i]->len >> STORE_BLOCK_SHIFT)) / total;
+    used += forvol[i];
+  }
+  // spread around the excess
+  int extra = VOL_HASH_TABLE_SIZE - used;
+  for (i = 0; i < extra; i++) {
+    forvol[i % num_vols]++;
+  }
+  // seed random number generator
+  for (i = 0; i < num_vols; i++) {
+    uint64_t x = p[i]->hash_id_md5.fold();
+    rnd[i] = (unsigned int) x;
+  }
+  // initialize table to "empty"
+  for (i = 0; i < VOL_HASH_TABLE_SIZE; i++)
+    ttable[i] = VOL_HASH_EMPTY;
+  // give each machine it's fav
+  int left = VOL_HASH_TABLE_SIZE;
+  int d = 0;
+  for (; left; d = (d + 1) % num_vols) {
+    if (!forvol[d])
+      continue;
+    do {
+      i = next_rand(&rnd[d]) % VOL_HASH_TABLE_SIZE;
+    } while (ttable[i] != VOL_HASH_EMPTY);
+    ttable[i] = mapping[d];
+    forvol[d]--;
+    left--;
+  }
+
+  // install new table
+
+  if (cp->vol_hash_table) {
+    new_Freer(cp->vol_hash_table, CACHE_MEM_FREE_TIMEOUT);
+  }
+  xfree(mapping);
+  xfree(p);
+  cp->vol_hash_table = ttable;
+}
+
+
+void
+Cache::vol_initialized(bool result)
+{
+  ink_atomic_increment(&total_initialized_vol, 1);
+  if (result)
+    ink_atomic_increment(&total_good_nvol, 1);
+  if (total_nvol == total_initialized_vol)
+    open_done();
+}
+
+int
+AIO_Callback_handler::handle_disk_failure(int event, void *data)
+{
+  (void) event;
+  /* search for the matching file descriptor */
+  if (!CacheProcessor::cache_ready)
+    return EVENT_DONE;
+  int disk_no = 0;
+  int good_disks = 0;
+  AIOCallback *cb = (AIOCallback *) data;
+  for (; disk_no < gndisks; disk_no++) {
+    CacheDisk *d = gdisks[disk_no];
+
+    if (d->fd == cb->aiocb.aio_fildes) {
+      d->num_errors++;
+
+      if (!DISK_BAD(d)) {
+
+        char message[128];
+        snprintf(message, sizeof(message), "Error accessing Disk %s", d->path);
+        Warning(message);
+        IOCORE_SignalManager(REC_SIGNAL_CACHE_WARNING, message);
+      } else if (!DISK_BAD_SIGNALLED(d)) {
+
+        char message[128];
+        snprintf(message, sizeof(message), "too many errors accessing disk %s: declaring disk bad", d->path);
+        Warning(message);
+        IOCORE_SignalManager(REC_SIGNAL_CACHE_ERROR, message);
+        /* subtract the disk space that was being used from  the cache size stat */
+        // dir entries stat
+        int p;
+        uint64_t total_bytes_delete = 0;
+        uint64_t total_dir_delete = 0;
+        uint64_t used_dir_delete = 0;
+
+        for (p = 0; p < gnvol; p++) {
+          if (d->fd == gvol[p]->fd) {
+            total_dir_delete += gvol[p]->buckets * gvol[p]->segments * DIR_DEPTH;
+            used_dir_delete += dir_entries_used(gvol[p]);
+            total_bytes_delete = gvol[p]->len - vol_dirlen(gvol[p]);
+          }
+        }
+
+        RecIncrGlobalRawStat(cache_rsb, cache_bytes_total_stat, -total_bytes_delete);
+        RecIncrGlobalRawStat(cache_rsb, cache_bytes_total_stat, -total_dir_delete);
+        RecIncrGlobalRawStat(cache_rsb, cache_bytes_total_stat, -cache_direntries_used_stat);
+
+        if (theCache) {
+          rebuild_host_table(theCache);
+        }
+        if (theStreamCache) {
+          rebuild_host_table(theStreamCache);
+        }
+      }
+      if (good_disks)
+        return EVENT_DONE;
+    }
+
+    if (!DISK_BAD(d))
+      good_disks++;
+
+  }
+  if (!good_disks) {
+    Warning("all disks are bad, cache disabled");
+    CacheProcessor::cache_ready = 0;
+    delete cb;
+    return EVENT_DONE;
+  }
+
+  if (theCache && !theCache->hosttable->gen_host_rec.vol_hash_table) {
+    unsigned int caches_ready = 0;
+    caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_HTTP);
+    caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_NONE);
+    caches_ready = ~caches_ready;
+    CacheProcessor::cache_ready &= caches_ready;
+    Warning("all volumes for http cache are corrupt, http cache disabled");
+  }
+  if (theStreamCache && !theStreamCache->hosttable->gen_host_rec.vol_hash_table) {
+    unsigned int caches_ready = 0;
+    caches_ready = caches_ready | (1 << CACHE_FRAG_TYPE_RTSP);
+    caches_ready = ~caches_ready;
+    CacheProcessor::cache_ready &= caches_ready;
+    Warning("all volumes for mixt cache are corrupt, mixt cache disabled");
+  }
+  delete cb;
+  return EVENT_DONE;
+}
+
+int
+Cache::open_done()
+{
+#ifdef NON_MODULAR
+  Action *register_ShowCache(Continuation * c, HTTPHdr * h);
+  Action *register_ShowCacheInternal(Continuation *c, HTTPHdr *h);
+  statPagesManager.register_http("cache", register_ShowCache);
+  statPagesManager.register_http("cache-internal", register_ShowCacheInternal);
+#endif
+  if (total_good_nvol == 0) {
+    ready = CACHE_INIT_FAILED;
+    cacheProcessor.cacheInitialized();
+    return 0;
+  }
+
+  hosttable = NEW(new CacheHostTable(this, scheme));
+  hosttable->register_config_callback(&hosttable);
+
+  if (hosttable->gen_host_rec.num_cachevols == 0)
+    ready = CACHE_INIT_FAILED;
+  else
+    ready = CACHE_INITIALIZED;
+  cacheProcessor.cacheInitialized();
+
+  return 0;
+}
+
+int
+Cache::open(bool clear, bool fix)
+{
+  NOWARN_UNUSED(fix);
+  int i;
+  off_t blocks;
+  cache_read_done = 0;
+  total_initialized_vol = 0;
+  total_nvol = 0;
+  total_good_nvol = 0;
+
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_min_average_object_size, "proxy.config.cache.min_average_object_size");
+  Debug("cache_init", "Cache::open - proxy.config.cache.min_average_object_size = %d",
+        (int)cache_config_min_average_object_size);
+
+  CacheVol *cp = cp_list.head;
+  for (; cp; cp = cp->link.next) {
+    if (cp->scheme == scheme) {
+      cp->vols = (Vol **) xmalloc(cp->num_vols * sizeof(Vol *));
+      int vol_no = 0;
+      for (i = 0; i < gndisks; i++) {
+        if (cp->disk_vols[i] && !DISK_BAD(cp->disk_vols[i]->disk)) {
+          DiskVolBlockQueue *q = cp->disk_vols[i]->dpb_queue.head;
+          for (; q; q = q->link.next) {
+            cp->vols[vol_no] = NEW(new Vol());
+            CacheDisk *d = cp->disk_vols[i]->disk;
+            cp->vols[vol_no]->disk = d;
+            cp->vols[vol_no]->fd = d->fd;
+            cp->vols[vol_no]->cache = this;
+            cp->vols[vol_no]->cache_vol = cp;
+            blocks = q->b->len;
+
+            bool vol_clear = clear || d->cleared || q->new_block;
+            cp->vols[vol_no]->init(d->path, blocks, q->b->offset, vol_clear);
+            vol_no++;
+            cache_size += blocks;
+          }
+        }
+      }
+      total_nvol += vol_no;
+    }
+  }
+  if (total_nvol == 0)
+    return open_done();
+  cache_read_done = 1;
+  return 0;
+}
+
+
+int
+Cache::close()
+{
+  return -1;
+}
+
+int
+CacheVC::dead(int event, Event *e)
+{
+  NOWARN_UNUSED(e);
+  NOWARN_UNUSED(event);
+  ink_assert(0);
+  return EVENT_DONE;
+}
+
+#define STORE_COLLISION 1
+
+#ifdef HTTP_CACHE
+static void unmarshal_helper(Doc *doc, Ptr &buf, int &okay) {
+  char *tmp = doc->hdr();
+  int len = doc->hlen;
+  while (len > 0) {
+    int r = HTTPInfo::unmarshal(tmp, len, buf._ptr());
+    if (r < 0) {
+      ink_assert(!"CacheVC::handleReadDone unmarshal failed");
+      okay = 0;
+      break;
+    }
+    len -= r;
+    tmp += r;
+  }
+}
+#endif
+
+int
+CacheVC::handleReadDone(int event, Event *e)
+{
+  NOWARN_UNUSED(e);
+  cancel_trigger();
+  ink_debug_assert(this_ethread() == mutex->thread_holding);
+
+  if (event == AIO_EVENT_DONE)
+    set_io_not_in_progress();
+  else
+    if (is_io_in_progress())
+      return EVENT_CONT;
+  {
+    MUTEX_TRY_LOCK(lock, vol->mutex, mutex->thread_holding);
+    if (!lock)
+      VC_SCHED_LOCK_RETRY();
+    if ((!dir_valid(vol, &dir)) || (!io.ok())) {
+      if (!io.ok()) {
+        Debug("cache_disk_error", "Read error on disk %s\n \
+	    read range : [%" PRIu64 " - %" PRIu64 " bytes]  [%" PRIu64 " - %" PRIu64 " blocks] \n", vol->hash_id, io.aiocb.aio_offset, io.aiocb.aio_offset + io.aiocb.aio_nbytes, io.aiocb.aio_offset / 512, (io.aiocb.aio_offset + io.aiocb.aio_nbytes) / 512);
+      }
+      goto Ldone;
+    }
+
+    ink_assert(vol->mutex->nthread_holding < 1000);
+    ink_assert(((Doc *) buf->data())->magic == DOC_MAGIC);
+#ifdef VERIFY_JTEST_DATA
+    char xx[500];
+    if (read_key && *read_key == ((Doc *) buf->data())->key && request.valid() && !dir_head(&dir) && !vio.ndone) {
+      int ib = 0, xd = 0;
+      request.url_get()->print(xx, 500, &ib, &xd);
+      char *x = xx;
+      for (int q = 0; q < 3; q++)
+        x = strchr(x + 1, '/');
+      ink_assert(!memcmp(((Doc *) buf->data())->data(), x, ib - (x - xx)));
+    }
+#endif
+    Doc *doc = (Doc *) buf->data();
+    // put into ram cache?
+    if (io.ok() &&
+        ((doc->first_key == *read_key) || (doc->key == *read_key) || STORE_COLLISION) && doc->magic == DOC_MAGIC) {
+      int okay = 1;
+      if (!f.doc_from_ram_cache)
+        f.not_from_ram_cache = 1;
+      if (cache_config_enable_checksum && doc->checksum != DOC_NO_CHECKSUM) {
+        // verify that the checksum matches
+        uint32_t checksum = 0;
+        for (char *b = doc->hdr(); b < (char *) doc + doc->len; b++)
+          checksum += *b;
+        ink_assert(checksum == doc->checksum);
+        if (checksum != doc->checksum) {
+          Note("cache: checksum error for [%" PRIu64 " %" PRIu64 "] len %d, hlen %d, disk %s, offset %" PRIu64 " size %d",
+               doc->first_key.b[0], doc->first_key.b[1],
+               doc->len, doc->hlen, vol->path, io.aiocb.aio_offset, io.aiocb.aio_nbytes);
+          doc->magic = DOC_CORRUPT;
+          okay = 0;
+        }
+      }
+      bool http_copy_hdr = false;
+#ifdef HTTP_CACHE
+      http_copy_hdr = cache_config_ram_cache_compress && !f.doc_from_ram_cache &&
+        doc->ftype == CACHE_FRAG_TYPE_HTTP && doc->hlen;
+      // If http doc we need to unmarshal the headers before putting in the ram cache
+      // unless it could be compressed
+      if (!http_copy_hdr && doc->ftype == CACHE_FRAG_TYPE_HTTP && doc->hlen && okay)
+        unmarshal_helper(doc, buf, okay);
+#endif
+      // Put the request in the ram cache only if its a open_read or lookup
+      if (vio.op == VIO::READ && okay) {
+        bool cutoff_check;
+        // cutoff_check :
+        // doc_len == 0 for the first fragment (it is set from the vector)
+        //                The decision on the first fragment is based on
+        //                doc->total_len
+        // After that, the decision is based of doc_len (doc_len != 0)
+        // (cache_config_ram_cache_cutoff == 0) : no cutoffs
+        cutoff_check = ((!doc_len && (int64_t)doc->total_len < cache_config_ram_cache_cutoff)
+                        || (doc_len && (int64_t)doc_len < cache_config_ram_cache_cutoff)
+                        || !cache_config_ram_cache_cutoff);
+        if (cutoff_check && !f.doc_from_ram_cache) {
+          uint64_t o = dir_offset(&dir);
+          vol->ram_cache->put(read_key, buf, doc->len, http_copy_hdr, (uint32_t)(o >> 32), (uint32_t)o);
+        }
+        if (!doc_len) {
+          // keep a pointer to it. In case the state machine decides to
+          // update this document, we don't have to read it back in memory
+          // again
+          vol->first_fragment_key = *read_key;
+          vol->first_fragment_offset = dir_offset(&dir);
+          vol->first_fragment_data = buf;
+        }
+      }                           // end VIO::READ check
+#ifdef HTTP_CACHE
+      // If it could be compressed, unmarshal after
+      if (http_copy_hdr && doc->ftype == CACHE_FRAG_TYPE_HTTP && doc->hlen && okay)
+        unmarshal_helper(doc, buf, okay);
+#endif
+    }                             // end io.ok() check
+  }
+Ldone:
+  POP_HANDLER;
+  return handleEvent(AIO_EVENT_DONE, 0);
+}
+
+
+int
+CacheVC::handleRead(int event, Event *e)
+{
+  NOWARN_UNUSED(event);
+  NOWARN_UNUSED(e);
+  cancel_trigger();
+
+  f.doc_from_ram_cache = false;
+
+  // check ram cache
+  ink_debug_assert(vol->mutex->thread_holding == this_ethread());
+  if (vol->ram_cache->get(read_key, &buf, 0, dir_offset(&dir)))
+    goto LramHit;
+
+  // check if it was read in the last open_read call
+  if (*read_key == vol->first_fragment_key && dir_offset(&dir) == vol->first_fragment_offset) {
+    buf = vol->first_fragment_data;
+    goto LmemHit;
+  }
+
+  // see if its in the aggregation buffer
+  if (dir_agg_buf_valid(vol, &dir)) {
+    int agg_offset = vol_offset(vol, &dir) - vol->header->write_pos;
+    buf = new_IOBufferData(iobuffer_size_to_index(io.aiocb.aio_nbytes, MAX_BUFFER_SIZE_INDEX), MEMALIGNED);
+    ink_assert((agg_offset + io.aiocb.aio_nbytes) <= (unsigned) vol->agg_buf_pos);
+    char *doc = buf->data();
+    char *agg = vol->agg_buffer + agg_offset;
+    memcpy(doc, agg, io.aiocb.aio_nbytes);
+    io.aio_result = io.aiocb.aio_nbytes;
+    SET_HANDLER(&CacheVC::handleReadDone);
+    return EVENT_RETURN;
+  }
+
+  io.aiocb.aio_fildes = vol->fd;
+  io.aiocb.aio_offset = vol_offset(vol, &dir);
+  if ((off_t)(io.aiocb.aio_offset + io.aiocb.aio_nbytes) > (off_t)(vol->skip + vol->len))
+    io.aiocb.aio_nbytes = vol->skip + vol->len - io.aiocb.aio_offset;
+  buf = new_IOBufferData(iobuffer_size_to_index(io.aiocb.aio_nbytes, MAX_BUFFER_SIZE_INDEX), MEMALIGNED);
+  io.aiocb.aio_buf = buf->data();
+  io.action = this;
+  io.thread = mutex->thread_holding;
+  SET_HANDLER(&CacheVC::handleReadDone);
+  ink_assert(ink_aio_read(&io) >= 0);
+  CACHE_DEBUG_INCREMENT_DYN_STAT(cache_pread_count_stat);
+  return EVENT_CONT;
+
+LramHit: {
+    io.aio_result = io.aiocb.aio_nbytes;
+    Doc *doc = (Doc*)buf->data();
+    if (cache_config_ram_cache_compress && doc->ftype == CACHE_FRAG_TYPE_HTTP && doc->hlen) {
+      SET_HANDLER(&CacheVC::handleReadDone);
+      f.doc_from_ram_cache = true;
+      return EVENT_RETURN;
+    }
+  }
+LmemHit:
+  io.aio_result = io.aiocb.aio_nbytes;
+  POP_HANDLER;
+  return EVENT_RETURN; // allow the caller to release the volume lock
+}
+
+Action *
+Cache::lookup(Continuation *cont, CacheKey *key, CacheFragType type, char *hostname, int host_len)
+{
+  if (!CACHE_READY(type)) {
+    cont->handleEvent(CACHE_EVENT_LOOKUP_FAILED, 0);
+    return ACTION_RESULT_DONE;
+  }
+
+  Vol *vol = key_to_vol(key, hostname, host_len);
+  ProxyMutex *mutex = cont->mutex;
+  CacheVC *c = new_CacheVC(cont);
+  SET_CONTINUATION_HANDLER(c, &CacheVC::openReadStartHead);
+  c->vio.op = VIO::READ;
+  c->base_stat = cache_lookup_active_stat;
+  CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE);
+  c->first_key = c->key = *key;
+  c->frag_type = type;
+  c->f.lookup = 1;
+  c->vol = vol;
+  c->last_collision = NULL;
+
+  if (c->handleEvent(EVENT_INTERVAL, 0) == EVENT_CONT)
+    return &c->_action;
+  else
+    return ACTION_RESULT_DONE;
+}
+
+#ifdef NON_MODULAR
+Action *
+Cache::lookup(Continuation *cont, CacheURL *url, CacheFragType type)
+{
+  INK_MD5 md5;
+
+  url->MD5_get(&md5);
+  int len = 0;
+  const char *hostname = url->host_get(&len);
+  return lookup(cont, &md5, type, (char *) hostname, len);
+}
+#endif
+
+int
+CacheVC::removeEvent(int event, Event *e)
+{
+  NOWARN_UNUSED(e);
+  NOWARN_UNUSED(event);
+
+  cancel_trigger();
+  set_io_not_in_progress();
+  {
+    MUTEX_TRY_LOCK(lock, vol->mutex, mutex->thread_holding);
+    if (!lock)
+      VC_SCHED_LOCK_RETRY();
+    if (_action.cancelled) {
+      if (od) {
+        vol->close_write(this);
+        od = 0;
+      }
+      goto Lfree;
+    }
+    if (!f.remove_aborted_writers) {
+      if (vol->open_write(this, true, 1)) {
+        // writer  exists
+        ink_assert(od = vol->open_read(&key));
+        od->dont_update_directory = 1;
+        od = NULL;
+      } else {
+        od->dont_update_directory = 1;
+      }
+      f.remove_aborted_writers = 1;
+    }
+  Lread:
+    if (!buf)
+      goto Lcollision;
+    if (!dir_valid(vol, &dir)) {
+      last_collision = NULL;
+      goto Lcollision;
+    }
+    // check read completed correct FIXME: remove bad vols
+    if ((size_t) io.aio_result != (size_t) io.aiocb.aio_nbytes)
+      goto Ldone;
+    {
+      // verify that this is our document
+      Doc *doc = (Doc *) buf->data();
+      /* should be first_key not key..right?? */
+      if (doc->first_key == key) {
+        ink_assert(doc->magic == DOC_MAGIC);
+        if (dir_delete(&key, vol, &dir) > 0) {
+          if (od)
+            vol->close_write(this);
+          od = NULL;
+          goto Lremoved;
+        }
+        goto Ldone;
+      }
+    }
+  Lcollision:
+    // check for collision
+    if (dir_probe(&key, vol, &dir, &last_collision) > 0) {
+      int ret = do_read_call(&key);
+      if (ret == EVENT_RETURN)
+        goto Lread;
+      return ret;
+    }
+  Ldone:
+    CACHE_INCREMENT_DYN_STAT(cache_remove_failure_stat);
+    if (od)
+      vol->close_write(this);
+  }
+  ink_debug_assert(!vol || this_ethread() != vol->mutex->thread_holding);
+  _action.continuation->handleEvent(CACHE_EVENT_REMOVE_FAILED, (void *) -ECACHE_NO_DOC);
+  goto Lfree;
+Lremoved:
+  _action.continuation->handleEvent(CACHE_EVENT_REMOVE, 0);
+Lfree:
+  return free_CacheVC(this);
+}
+
+Action *
+Cache::remove(Continuation *cont, CacheKey *key, CacheFragType type,
+              bool user_agents, bool link,
+              char *hostname, int host_len)
+{
+  NOWARN_UNUSED(user_agents);
+  NOWARN_UNUSED(link);
+
+  if (!CACHE_READY(type)) {
+    if (cont)
+      cont->handleEvent(CACHE_EVENT_REMOVE_FAILED, 0);
+    return ACTION_RESULT_DONE;
+  }
+
+  ink_assert(this);
+
+  ProxyMutexPtr mutex = NULL;
+  if (!cont)
+    cont = new_CacheRemoveCont();
+
+  CACHE_TRY_LOCK(lock, cont->mutex, this_ethread());
+  ink_assert(lock);
+  Vol *vol = key_to_vol(key, hostname, host_len);
+  // coverity[var_decl]
+  Dir result;
+  dir_clear(&result);           // initialized here, set result empty so we can recognize missed lock
+  mutex = cont->mutex;
+
+  CacheVC *c = new_CacheVC(cont);
+  c->vio.op = VIO::NONE;
+  c->frag_type = type;
+  c->base_stat = cache_remove_active_stat;
+  CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE);
+  c->first_key = c->key = *key;
+  c->vol = vol;
+  c->dir = result;
+  c->f.remove = 1;
+
+  SET_CONTINUATION_HANDLER(c, &CacheVC::removeEvent);
+  int ret = c->removeEvent(EVENT_IMMEDIATE, 0);
+  if (ret == EVENT_DONE)
+    return ACTION_RESULT_DONE;
+  else
+    return &c->_action;
+}
+// CacheVConnection
+
+CacheVConnection::CacheVConnection()
+  : VConnection(NULL)
+{ }
+
+
+void
+cplist_init()
+{
+  cp_list_len = 0;
+  for (int i = 0; i < gndisks; i++) {
+    CacheDisk *d = gdisks[i];
+    DiskVol **dp = d->disk_vols;
+    for (unsigned int j = 0; j < d->header->num_volumes; j++) {
+      ink_assert(dp[j]->dpb_queue.head);
+      CacheVol *p = cp_list.head;
+      while (p) {
+        if (p->vol_number == dp[j]->vol_number) {
+          ink_assert(p->scheme == (int) dp[j]->dpb_queue.head->b->type);
+          p->size += dp[j]->size;
+          p->num_vols += dp[j]->num_volblocks;
+          p->disk_vols[i] = dp[j];
+          break;
+        }
+        p = p->link.next;
+      }
+      if (!p) {
+        // did not find a volume in the cache vol list...create
+        // a new one
+        CacheVol *new_p = NEW(new CacheVol());
+        new_p->vol_number = dp[j]->vol_number;
+        new_p->num_vols = dp[j]->num_volblocks;
+        new_p->size = dp[j]->size;
+        new_p->scheme = dp[j]->dpb_queue.head->b->type;
+        new_p->disk_vols = (DiskVol **) xmalloc(gndisks * sizeof(DiskVol *));
+        memset(new_p->disk_vols, 0, gndisks * sizeof(DiskVol *));
+        new_p->disk_vols[i] = dp[j];
+        cp_list.enqueue(new_p);
+        cp_list_len++;
+      }
+    }
+  }
+}
+
+
+void
+cplist_update()
+{
+  /* go through cplist and delete volumes that are not in the volume.config */
+  CacheVol *cp = cp_list.head;
+
+  while (cp) {
+    ConfigVol *config_vol = config_volumes.cp_queue.head;
+    for (; config_vol; config_vol = config_vol->link.next) {
+      if (config_vol->number == cp->vol_number) {
+        int size_in_blocks = config_vol->size << (20 - STORE_BLOCK_SHIFT);
+        if ((cp->size <= size_in_blocks) && (cp->scheme == config_vol->scheme)) {
+          config_vol->cachep = cp;
+        } else {
+          /* delete this volume from all the disks */
+          int d_no;
+          for (d_no = 0; d_no < gndisks; d_no++) {
+            if (cp->disk_vols[d_no])
+              cp->disk_vols[d_no]->disk->delete_volume(cp->vol_number);
+          }
+          config_vol = NULL;
+        }
+        break;
+      }
+    }
+
+    if (!config_vol) {
+      // did not find a matching volume in the config file.
+      //Delete hte volume from the cache vol list
+      int d_no;
+      for (d_no = 0; d_no < gndisks; d_no++) {
+        if (cp->disk_vols[d_no])
+          cp->disk_vols[d_no]->disk->delete_volume(cp->vol_number);
+      }
+      CacheVol *temp_cp = cp;
+      cp = cp->link.next;
+      cp_list.remove(temp_cp);
+      cp_list_len--;
+      delete temp_cp;
+      continue;
+    } else
+      cp = cp->link.next;
+  }
+}
+
+int
+cplist_reconfigure()
+{
+  int64_t size;
+  int volume_number;
+  off_t size_in_blocks;
+
+  gnvol = 0;
+  if (config_volumes.num_volumes == 0) {
+    /* only the http cache */
+    CacheVol *cp = NEW(new CacheVol());
+    cp->vol_number = 0;
+    cp->scheme = CACHE_HTTP_TYPE;
+    cp->disk_vols = (DiskVol **) xmalloc(gndisks * sizeof(DiskVol *));
+    memset(cp->disk_vols, 0, gndisks * sizeof(DiskVol *));
+    cp_list.enqueue(cp);
+    cp_list_len++;
+    for (int i = 0; i < gndisks; i++) {
+      if (gdisks[i]->header->num_volumes != 1 || gdisks[i]->disk_vols[0]->vol_number != 0) {
+        /* The user had created several volumes before - clear the disk
+           and create one volume for http */
+        Note("Clearing Disk: %s", gdisks[i]->path);
+        gdisks[i]->delete_all_volumes();
+      }
+      if (gdisks[i]->cleared) {
+        uint64_t free_space = gdisks[i]->free_space * STORE_BLOCK_SIZE;
+        int vols = (free_space / MAX_VOL_SIZE) + 1;
+        for (int p = 0; p < vols; p++) {
+          off_t b = gdisks[i]->free_space / (vols - p);
+          Debug("cache_hosting", "blocks = %d\n", b);
+          DiskVolBlock *dpb = gdisks[i]->create_volume(0, b, CACHE_HTTP_TYPE);
+          ink_assert(dpb && dpb->len == (uint64_t)b);
+        }
+        ink_assert(gdisks[i]->free_space == 0);
+      }
+
+      ink_assert(gdisks[i]->header->num_volumes == 1);
+      DiskVol **dp = gdisks[i]->disk_vols;
+      gnvol += dp[0]->num_volblocks;
+      cp->size += dp[0]->size;
+      cp->num_vols += dp[0]->num_volblocks;
+      cp->disk_vols[i] = dp[0];
+    }
+
+  } else {
+    for (int i = 0; i < gndisks; i++) {
+      if (gdisks[i]->header->num_volumes == 1 && gdisks[i]->disk_vols[0]->vol_number == 0) {
+        /* The user had created several volumes before - clear the disk
+           and create one volume for http */
+        Note("Clearing Disk: %s", gdisks[i]->path);
+        gdisks[i]->delete_all_volumes();
+      }
+    }
+
+    /* change percentages in the config patitions to absolute value */
+    off_t tot_space_in_blks = 0;
+    off_t blocks_per_vol = VOL_BLOCK_SIZE / STORE_BLOCK_SIZE;
+    /* sum up the total space available on all the disks.
+       round down the space to 128 megabytes */
+    for (int i = 0; i < gndisks; i++)
+      tot_space_in_blks += (gdisks[i]->num_usable_blocks / blocks_per_vol) * blocks_per_vol;
+
+    double percent_remaining = 100.00;
+    ConfigVol *config_vol = config_volumes.cp_queue.head;
+    for (; config_vol; config_vol = config_vol->link.next) {
+      if (config_vol->in_percent) {
+        if (config_vol->percent > percent_remaining) {
+          Warning("total volume sizes added up to more than 100%%!");
+          Warning("no volumes created");
+          return -1;
+        }
+        int64_t space_in_blks = (int64_t) (((double) (config_vol->percent / percent_remaining)) * tot_space_in_blks);
+
+        space_in_blks = space_in_blks >> (20 - STORE_BLOCK_SHIFT);
+        /* round down to 128 megabyte multiple */
+        space_in_blks = (space_in_blks >> 7) << 7;
+        config_vol->size = space_in_blks;
+        tot_space_in_blks -= space_in_blks << (20 - STORE_BLOCK_SHIFT);
+        percent_remaining -= (config_vol->size < 128) ? 0 : config_vol->percent;
+      }
+      if (config_vol->size < 128) {
+        Warning("the size of volume %d (%d) is less than the minimum required volume size",
+                config_vol->number, config_vol->size, 128);
+        Warning("volume %d is not created", config_vol->number);
+      }
+      Debug("cache_hosting", "Volume: %d Size: %d", config_vol->number, config_vol->size);
+    }
+    cplist_update();
+    /* go through volume config and grow and create volumes */
+
+    config_vol = config_volumes.cp_queue.head;
+
+    for (; config_vol; config_vol = config_vol->link.next) {
+
+      size = config_vol->size;
+      if (size < 128)
+        continue;
+
+      volume_number = config_vol->number;
+
+      size_in_blocks = ((off_t) size * 1024 * 1024) / STORE_BLOCK_SIZE;
+
+      if (!config_vol->cachep) {
+        // we did not find a corresponding entry in cache vol...creat one
+
+        CacheVol *new_cp = NEW(new CacheVol());
+        new_cp->disk_vols = (DiskVol **) xmalloc(gndisks * sizeof(DiskVol *));
+        memset(new_cp->disk_vols, 0, gndisks * sizeof(DiskVol *));
+        if (create_volume(config_vol->number, size_in_blocks, config_vol->scheme, new_cp))
+          return -1;
+        cp_list.enqueue(new_cp);
+        cp_list_len++;
+        config_vol->cachep = new_cp;
+        gnvol += new_cp->num_vols;
+        continue;
+      }
+//    else
+      CacheVol *cp = config_vol->cachep;
+      ink_assert(cp->size <= size_in_blocks);
+      if (cp->size == size_in_blocks) {
+        gnvol += cp->num_vols;
+        continue;
+      }
+      // else the size is greater...
+      /* search the cp_list */
+
+      int *sorted_vols = new int[gndisks];
+      for (int i = 0; i < gndisks; i++)
+        sorted_vols[i] = i;
+      for (int i = 0; i < gndisks - 1; i++) {
+        int smallest = sorted_vols[i];
+        int smallest_ndx = i;
+        for (int j = i + 1; j < gndisks; j++) {
+          int curr = sorted_vols[j];
+          DiskVol *dvol = cp->disk_vols[curr];
+          if (gdisks[curr]->cleared) {
+            ink_assert(!dvol);
+            // disks that are cleared should be filled first
+            smallest = curr;
+            smallest_ndx = j;
+          } else if (!dvol && cp->disk_vols[smallest]) {
+
+            smallest = curr;
+            smallest_ndx = j;
+          } else if (dvol && cp->disk_vols[smallest] && (dvol->size < cp->disk_vols[smallest]->size)) {
+            smallest = curr;
+            smallest_ndx = j;
+          }
+        }
+        sorted_vols[smallest_ndx] = sorted_vols[i];
+        sorted_vols[i] = smallest;
+      }
+
+      int64_t size_to_alloc = size_in_blocks - cp->size;
+      int disk_full = 0;
+      for (int i = 0; (i < gndisks) && size_to_alloc; i++) {
+
+        int disk_no = sorted_vols[i];
+        ink_assert(cp->disk_vols[sorted_vols[gndisks - 1]]);
+        int largest_vol = cp->disk_vols[sorted_vols[gndisks - 1]]->size;
+
+        /* allocate storage on new disk. Find the difference
+           between the biggest volume on any disk and
+           the volume on this disk and try to make
+           them equal */
+        int64_t size_diff = (cp->disk_vols[disk_no]) ? largest_vol - cp->disk_vols[disk_no]->size : largest_vol;
+        size_diff = (size_diff < size_to_alloc) ? size_diff : size_to_alloc;
+        /* if size_diff == 0, then then the disks have volumes of the
+           same sizes, so we don't need to balance the disks */
+        if (size_diff == 0)
+          break;
+
+        DiskVolBlock *dpb;
+        do {
+          dpb = gdisks[disk_no]->create_volume(volume_number, size_diff, cp->scheme);
+          if (dpb) {
+            if (!cp->disk_vols[disk_no]) {
+              cp->disk_vols[disk_no] = gdisks[disk_no]->get_diskvol(volume_number);
+            }
+            size_diff -= dpb->len;
+            cp->size += dpb->len;
+            cp->num_vols++;
+          } else
+            break;
+        } while ((size_diff > 0));
+
+        if (!dpb)
+          disk_full++;
+
+        size_to_alloc = size_in_blocks - cp->size;
+      }
+
+      delete[]sorted_vols;
+
+      if (size_to_alloc) {
+        if (create_volume(volume_number, size_to_alloc, cp->scheme, cp))
+          return -1;
+      }
+      gnvol += cp->num_vols;
+    }
+  }
+  return 0;
+}
+
+// This is some really bad code, and needs to be rewritten!
+int
+create_volume(int volume_number, off_t size_in_blocks, int scheme, CacheVol *cp)
+{
+  static int curr_vol = 0;  // FIXME: this will not reinitialize correctly
+  off_t to_create = size_in_blocks;
+  off_t blocks_per_vol = VOL_BLOCK_SIZE >> STORE_BLOCK_SHIFT;
+  int full_disks = 0;
+
+  int *sp = new int[gndisks];
+  memset(sp, 0, gndisks * sizeof(int));
+
+  int i = curr_vol;
+  while (size_in_blocks > 0) {
+    if (gdisks[i]->free_space >= (sp[i] + blocks_per_vol)) {
+      sp[i] += blocks_per_vol;
+      size_in_blocks -= blocks_per_vol;
+      full_disks = 0;
+    } else {
+      full_disks += 1;
+      if (full_disks == gndisks) {
+        char config_file[PATH_NAME_MAX];
+        IOCORE_ReadConfigString(config_file, "proxy.config.cache.volume_filename", PATH_NAME_MAX);
+        if (cp->size)
+          Warning("not enough space to increase volume: [%d] to size: [%d]",
+                  volume_number, (to_create + cp->size) >> (20 - STORE_BLOCK_SHIFT));
+        else
+          Warning("not enough space to create volume: [%d], size: [%d]",
+                  volume_number, to_create >> (20 - STORE_BLOCK_SHIFT));
+
+        Note("edit the %s file and restart traffic_server", config_file);
+        delete[]sp;
+        return -1;
+      }
+    }
+    i = (i + 1) % gndisks;
+  }
+  cp->vol_number = volume_number;
+  cp->scheme = scheme;
+  curr_vol = i;
+  for (i = 0; i < gndisks; i++) {
+    if (sp[i] > 0) {
+      while (sp[i] > 0) {
+        DiskVolBlock *p = gdisks[i]->create_volume(volume_number, sp[i], scheme);
+        ink_assert(p && (p->len >= (unsigned int) blocks_per_vol));
+        sp[i] -= p->len;
+        cp->num_vols++;
+        cp->size += p->len;
+      }
+      if (!cp->disk_vols[i])
+        cp->disk_vols[i] = gdisks[i]->get_diskvol(volume_number);
+    }
+  }
+  delete[]sp;
+  return 0;
+}
+
+void
+rebuild_host_table(Cache *cache)
+{
+  build_vol_hash_table(&cache->hosttable->gen_host_rec);
+  if (cache->hosttable->m_numEntries != 0) {
+    CacheHostMatcher *hm = cache->hosttable->getHostMatcher();
+    CacheHostRecord *h_rec = hm->getDataArray();
+    int h_rec_len = hm->getNumElements();
+    int i;
+    for (i = 0; i < h_rec_len; i++) {
+      build_vol_hash_table(&h_rec[i]);
+    }
+  }
+}
+
+// if generic_host_rec.vols == NULL, what do we do???
+Vol *
+Cache::key_to_vol(CacheKey *key, char *hostname, int host_len)
+{
+  uint32_t h = (key->word(2) >> DIR_TAG_WIDTH) % VOL_HASH_TABLE_SIZE;
+  unsigned short *hash_table = hosttable->gen_host_rec.vol_hash_table;
+  CacheHostRecord *host_rec = &hosttable->gen_host_rec;
+
+  if (hosttable->m_numEntries > 0 && host_len) {
+    CacheHostResult res;
+    hosttable->Match(hostname, host_len, &res);
+    if (res.record) {
+      unsigned short *host_hash_table = res.record->vol_hash_table;
+      if (host_hash_table) {
+        if (is_debug_tag_set("cache_hosting")) {
+          char format_str[50];
+          snprintf(format_str, sizeof(format_str), "Volume: %%xd for host: %%.%ds", host_len);
+          Debug("cache_hosting", format_str, res.record, hostname);
+        }
+        return res.record->vols[host_hash_table[h]];
+      }
+    }
+  }
+  if (hash_table) {
+    if (is_debug_tag_set("cache_hosting")) {
+      char format_str[50];
+      snprintf(format_str, sizeof(format_str), "Generic volume: %%xd for host: %%.%ds", host_len);
+      Debug("cache_hosting", format_str, host_rec, hostname);
+    }
+    return host_rec->vols[hash_table[h]];
+  } else
+    return host_rec->vols[0];
+}
+
+static void reg_int(const char *str, int stat, RecRawStatBlock *rsb, const char *prefix, RecRawStatSyncCb sync_cb=RecRawStatSyncSum) {
+  char stat_str[256];
+  snprintf(stat_str, sizeof(stat_str), "%s.%s", prefix, str);
+  RecRegisterRawStat(rsb, RECT_PROCESS, stat_str, RECD_INT, RECP_NON_PERSISTENT, stat, sync_cb);
+  DOCACHE_CLEAR_DYN_STAT(stat)
+}
+#define REG_INT(_str, _stat) reg_int(_str, (int)_stat, rsb, prefix)
+
+// Register Stats
+void
+register_cache_stats(RecRawStatBlock *rsb, const char *prefix)
+{
+  char stat_str[256];
+
+  // Special case for this sucker, since it uses its own aggregator.
+  reg_int("bytes_used", cache_bytes_used_stat, rsb, prefix, cache_stats_bytes_used_cb);
+
+  REG_INT("bytes_total", cache_bytes_total_stat);
+  snprintf(stat_str, sizeof(stat_str), "%s.%s", prefix, "ram_cache.total_bytes");
+  RecRegisterRawStat(rsb, RECT_PROCESS, stat_str, RECD_INT, RECP_NULL, (int) cache_ram_cache_bytes_total_stat, RecRawStatSyncSum);
+  REG_INT("ram_cache.bytes_used", cache_ram_cache_bytes_stat);
+  REG_INT("ram_cache.hits", cache_ram_cache_hits_stat);
+  REG_INT("pread_count", cache_pread_count_stat);
+  REG_INT("percent_full", cache_percent_full_stat);
+  REG_INT("lookup.active", cache_lookup_active_stat);
+  REG_INT("lookup.success", cache_lookup_success_stat);
+  REG_INT("lookup.failure", cache_lookup_failure_stat);
+  REG_INT("read.active", cache_read_active_stat);
+  REG_INT("read.success", cache_read_success_stat);
+  REG_INT("read.failure", cache_read_failure_stat);
+  REG_INT("write.active", cache_write_active_stat);
+  REG_INT("write.success", cache_write_success_stat);
+  REG_INT("write.failure", cache_write_failure_stat);
+  REG_INT("write.backlog.failure", cache_write_backlog_failure_stat);
+  REG_INT("update.active", cache_update_active_stat);
+  REG_INT("update.success", cache_update_success_stat);
+  REG_INT("update.failure", cache_update_failure_stat);
+  REG_INT("remove.active", cache_remove_active_stat);
+  REG_INT("remove.success", cache_remove_success_stat);
+  REG_INT("remove.failure", cache_remove_failure_stat);
+  REG_INT("evacuate.active", cache_evacuate_active_stat);
+  REG_INT("evacuate.success", cache_evacuate_success_stat);
+  REG_INT("evacuate.failure", cache_evacuate_failure_stat);
+  REG_INT("scan.active", cache_scan_active_stat);
+  REG_INT("scan.success", cache_scan_success_stat);
+  REG_INT("scan.failure", cache_scan_failure_stat);
+  REG_INT("direntries.total", cache_direntries_total_stat);
+  REG_INT("direntries.used", cache_direntries_used_stat);
+  REG_INT("directory_collision", cache_directory_collision_count_stat);
+  REG_INT("frags_per_doc.1", cache_single_fragment_document_count_stat);
+  REG_INT("frags_per_doc.2", cache_two_fragment_document_count_stat);
+  REG_INT("frags_per_doc.3+", cache_three_plus_plus_fragment_document_count_stat);
+  REG_INT("read_busy.success", cache_read_busy_success_stat);
+  REG_INT("read_busy.failure", cache_read_busy_failure_stat);
+  REG_INT("write_bytes_stat", cache_write_bytes_stat);
+  REG_INT("vector_marshals", cache_hdr_vector_marshal_stat);
+  REG_INT("hdr_marshals", cache_hdr_marshal_stat);
+  REG_INT("hdr_marshal_bytes", cache_hdr_marshal_bytes_stat);
+  REG_INT("gc_bytes_evacuated", cache_gc_bytes_evacuated_stat);
+  REG_INT("gc_frags_evacuated", cache_gc_frags_evacuated_stat);
+}
+
+
+void
+ink_cache_init(ModuleVersion v)
+{
+  ink_release_assert(!checkModuleVersion(v, CACHE_MODULE_VERSION));
+
+  cache_rsb = RecAllocateRawStatBlock((int) cache_stat_count);
+
+  IOCORE_EstablishStaticConfigInteger(cache_config_ram_cache_size, "proxy.config.cache.ram_cache.size");
+  Debug("cache_init", "proxy.config.cache.ram_cache.size = %" PRId64 " = %" PRId64 "Mb",
+        cache_config_ram_cache_size, cache_config_ram_cache_size / (1024 * 1024));
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_ram_cache_algorithm, "proxy.config.cache.ram_cache.algorithm");
+  IOCORE_EstablishStaticConfigInt32(cache_config_ram_cache_compress, "proxy.config.cache.ram_cache.compress");
+  IOCORE_EstablishStaticConfigInt32(cache_config_ram_cache_compress_percent, "proxy.config.cache.ram_cache.compress_percent");
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_http_max_alts, "proxy.config.cache.limits.http.max_alts");
+  Debug("cache_init", "proxy.config.cache.limits.http.max_alts = %d", cache_config_http_max_alts);
+
+  IOCORE_EstablishStaticConfigInteger(cache_config_ram_cache_cutoff, "proxy.config.cache.ram_cache_cutoff");
+  Debug("cache_init", "cache_config_ram_cache_cutoff = %" PRId64 " = %" PRId64 "Mb",
+        cache_config_ram_cache_cutoff, cache_config_ram_cache_cutoff / (1024 * 1024));
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_permit_pinning, "proxy.config.cache.permit.pinning");
+  Debug("cache_init", "proxy.config.cache.permit.pinning = %d", cache_config_permit_pinning);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_dir_sync_frequency, "proxy.config.cache.dir.sync_frequency");
+  Debug("cache_init", "proxy.config.cache.dir.sync_frequency = %d", cache_config_dir_sync_frequency);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_vary_on_user_agent, "proxy.config.cache.vary_on_user_agent");
+  Debug("cache_init", "proxy.config.cache.vary_on_user_agent = %d", cache_config_vary_on_user_agent);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_select_alternate, "proxy.config.cache.select_alternate");
+  Debug("cache_init", "proxy.config.cache.select_alternate = %d", cache_config_select_alternate);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_max_doc_size, "proxy.config.cache.max_doc_size");
+  Debug("cache_init", "proxy.config.cache.max_doc_size = %d = %dMb",
+        cache_config_max_doc_size, cache_config_max_doc_size / (1024 * 1024));
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_mutex_retry_delay, "proxy.config.cache.mutex_retry_delay");
+  Debug("cache_init", "proxy.config.cache.mutex_retry_delay = %dms", cache_config_mutex_retry_delay);
+
+  // This is just here to make sure IOCORE "standalone" works, it's usually configured in RecordsConfig.cc
+  IOCORE_RegisterConfigString(RECT_CONFIG, "proxy.config.config_dir", TS_BUILD_SYSCONFDIR, RECU_DYNAMIC, RECC_NULL, NULL);
+  IOCORE_ReadConfigString(cache_system_config_directory, "proxy.config.config_dir", PATH_NAME_MAX);
+  if (cache_system_config_directory[0] != '/') {
+    // Not an absolute path so use system one
+    Layout::get()->relative(cache_system_config_directory, sizeof(cache_system_config_directory), cache_system_config_directory);
+  }
+  Debug("cache_init", "proxy.config.config_dir = \"%s\"", cache_system_config_directory);
+  if (access(cache_system_config_directory, R_OK) == -1) {
+    ink_strlcpy(cache_system_config_directory, Layout::get()->sysconfdir,
+                sizeof(cache_system_config_directory));
+    Debug("cache_init", "proxy.config.config_dir = \"%s\"", cache_system_config_directory);
+    if (access(cache_system_config_directory, R_OK) == -1) {
+      fprintf(stderr,"unable to access() config dir '%s': %d, %s\n",
+              cache_system_config_directory, errno, strerror(errno));
+      fprintf(stderr, "please set config path via 'proxy.config.config_dir' \n");
+      _exit(1);
+    }
+  }
+  // TODO: These are left here, since they are only registered if HIT_EVACUATE is enabled.
+#ifdef HIT_EVACUATE
+  IOCORE_RegisterConfigInteger(RECT_CONFIG, "proxy.config.cache.hit_evacuate_percent", 0, RECU_DYNAMIC, RECC_NULL, NULL);
+  IOCORE_EstablishStaticConfigInt32(cache_config_hit_evacuate_percent, "proxy.config.cache.hit_evacuate_percent");
+  Debug("cache_init", "proxy.config.cache.hit_evacuate_percent = %d", cache_config_hit_evacuate_percent);
+
+  IOCORE_RegisterConfigInteger(RECT_CONFIG, "proxy.config.cache.hit_evacuate_size_limit", 0, RECU_DYNAMIC, RECC_NULL, NULL);
+  IOCORE_EstablishStaticConfigInt32(cache_config_hit_evacuate_size_limit, "proxy.config.cache.hit_evacuate_size_limit");
+  Debug("cache_init", "proxy.config.cache.hit_evacuate_size_limit = %d", cache_config_hit_evacuate_size_limit);
+#endif
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_force_sector_size, "proxy.config.cache.force_sector_size");
+  IOCORE_EstablishStaticConfigInt32(cache_config_target_fragment_size, "proxy.config.cache.target_fragment_size");
+
+  if (cache_config_target_fragment_size == 0)
+    cache_config_target_fragment_size = DEFAULT_TARGET_FRAGMENT_SIZE;
+
+#ifdef HTTP_CACHE
+  extern int url_hash_method;
+
+  //  # 0 - MD5 hash
+  //  # 1 - MMH hash
+  IOCORE_EstablishStaticConfigInt32(url_hash_method, "proxy.config.cache.url_hash_method");
+  Debug("cache_init", "proxy.config.cache.url_hash_method = %d", url_hash_method);
+#endif
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_max_disk_errors, "proxy.config.cache.max_disk_errors");
+  Debug("cache_init", "proxy.config.cache.max_disk_errors = %d", cache_config_max_disk_errors);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_agg_write_backlog, "proxy.config.cache.agg_write_backlog");
+  Debug("cache_init", "proxy.config.cache.agg_write_backlog = %d", cache_config_agg_write_backlog);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_enable_checksum, "proxy.config.cache.enable_checksum");
+  Debug("cache_init", "proxy.config.cache.enable_checksum = %d", cache_config_enable_checksum);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_alt_rewrite_max_size, "proxy.config.cache.alt_rewrite_max_size");
+  Debug("cache_init", "proxy.config.cache.alt_rewrite_max_size = %d", cache_config_alt_rewrite_max_size);
+
+  IOCORE_EstablishStaticConfigInt32(cache_config_read_while_writer, "proxy.config.cache.enable_read_while_writer");
+  cache_config_read_while_writer = validate_rww(cache_config_read_while_writer);
+  IOCORE_RegisterConfigUpdateFunc("proxy.config.cache.enable_read_while_writer", update_cache_config, NULL);
+  Debug("cache_init", "proxy.config.cache.enable_read_while_writer = %d", cache_config_read_while_writer);
+
+  register_cache_stats(cache_rsb, "proxy.process.cache");
+
+  const char *err = NULL;
+  if ((err = theCacheStore.read_config())) {
+    printf("%s  failed\n", err);
+    exit(1);
+  }
+  // XXX: The read for proxy.config.cache.storage_filename is unused!
+  //
+  if (theCacheStore.n_disks == 0) {
+    char p[PATH_NAME_MAX + 1];
+    snprintf(p, sizeof(p), "%s/", cache_system_config_directory);
+    IOCORE_ReadConfigString(p + strlen(p), "proxy.config.cache.storage_filename", PATH_NAME_MAX - strlen(p) - 1);
+    if (p[strlen(p) - 1] == '/' || p[strlen(p) - 1] == '\\') {
+      ink_strlcat(p, "storage.config", sizeof(p));
+    }
+    Warning("no cache disks specified in %s: cache disabled\n", p);
+    //exit(1);
+  }
+}
+
+#ifdef NON_MODULAR
+//----------------------------------------------------------------------------
+Action *
+CacheProcessor::open_read(Continuation *cont, URL *url, CacheHTTPHdr *request,
+                          CacheLookupHttpConfig *params, time_t pin_in_cache, CacheFragType type)
+{
+#ifdef CLUSTER_CACHE
+  if (cache_clustering_enabled > 0) {
+    return open_read_internal(CACHE_OPEN_READ_LONG, cont, (MIOBuffer *) 0,
+                              url, request, params, (CacheKey *) 0, pin_in_cache, type, (char *) 0, 0);
+  }
+#endif
+  return caches[type]->open_read(cont, url, request, params, type);
+}
+
+
+//----------------------------------------------------------------------------
+Action *
+CacheProcessor::open_write(Continuation *cont, int expected_size, URL *url,
+                           CacheHTTPHdr *request, CacheHTTPInfo *old_info, time_t pin_in_cache, CacheFragType type)
+{
+#ifdef CLUSTER_CACHE
+  if (cache_clustering_enabled > 0) {
+    INK_MD5 url_md5;
+    Cache::generate_key(&url_md5, url, request);
+    ClusterMachine *m = cluster_machine_at_depth(cache_hash(url_md5));
+
+    if (m) {
+      // Do remote open_write()
+      INK_MD5 url_only_md5;
+      Cache::generate_key(&url_only_md5, url, 0);
+      return Cluster_write(cont, expected_size, (MIOBuffer *) 0, m,
+                           &url_only_md5, type,
+                           false, pin_in_cache, CACHE_OPEN_WRITE_LONG,
+                           (CacheKey *) 0, url, request, old_info, (char *) 0, 0);
+    }
+  }
+#endif
+  return caches[type]->open_write(cont, url, request, old_info, pin_in_cache, type);
+}
+
+//----------------------------------------------------------------------------
+// Note: this should not be called from from the cluster processor, or bad
+// recursion could occur. This is merely a convenience wrapper.
+Action *
+CacheProcessor::remove(Continuation *cont, URL *url, CacheFragType frag_type)
+{
+  INK_MD5 md5;
+  int len = 0;
+  const char *hostname;
+
+  url->MD5_get(&md5);
+  hostname = url->host_get(&len);
+
+  Debug("cache_remove", "[CacheProcessor::remove] Issuing cache delete for %s", url->string_get_ref());
+#ifdef CLUSTER_CACHE
+  if (cache_clustering_enabled > 0) {
+    // Remove from cluster
+    return remove(cont, &md5, frag_type, true, false, const_cast(hostname), len);
+  }
+#endif
+
+  // Remove from local cache only.
+  return caches[frag_type]->remove(cont, &md5, frag_type, true, false, const_cast(hostname), len);
+}
+
+#endif
diff --git a/iocore/cache/CacheDir.cc b/iocore/cache/CacheDir.cc
new file mode 100644
index 00000000..680ec01e
--- /dev/null
+++ b/iocore/cache/CacheDir.cc
@@ -0,0 +1,1448 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+
+#include "P_Cache.h"
+
+// #define LOOP_CHECK_MODE 1
+#ifdef LOOP_CHECK_MODE
+#define DIR_LOOP_THRESHOLD	      1000
+#endif
+#include "ink_stack_trace.h"
+
+#define CACHE_INC_DIR_USED(_m) do { \
+ProxyMutex *mutex = _m; \
+CACHE_INCREMENT_DYN_STAT(cache_direntries_used_stat); \
+} while (0) \
+
+#define CACHE_DEC_DIR_USED(_m) do { \
+ProxyMutex *mutex = _m; \
+CACHE_DECREMENT_DYN_STAT(cache_direntries_used_stat); \
+} while (0) \
+
+#define CACHE_INC_DIR_COLLISIONS(_m) do {\
+ProxyMutex *mutex = _m; \
+CACHE_INCREMENT_DYN_STAT(cache_directory_collision_count_stat); \
+} while (0);
+
+
+// Globals
+
+ClassAllocator openDirEntryAllocator("openDirEntry");
+Dir empty_dir;
+
+// OpenDir
+
+OpenDir::OpenDir()
+{
+  SET_HANDLER(&OpenDir::signal_readers);
+}
+
+/*
+   If allow_if_writers is false, open_write fails if there are other writers.
+   max_writers sets the maximum number of concurrent writers that are
+   allowed. Only The first writer can set the max_writers. It is ignored
+   for later writers.
+   Returns 1 on success and 0 on failure.
+   */
+int
+OpenDir::open_write(CacheVC *cont, int allow_if_writers, int max_writers)
+{
+  ink_debug_assert(cont->vol->mutex->thread_holding == this_ethread());
+  unsigned int h = cont->first_key.word(0);
+  int b = h % OPEN_DIR_BUCKETS;
+  for (OpenDirEntry *d = bucket[b].head; d; d = d->link.next) {
+    if (!(d->writers.head->first_key == cont->first_key))
+      continue;
+    if (allow_if_writers && d->num_writers < d->max_writers) {
+      d->writers.push(cont);
+      d->num_writers++;
+      cont->od = d;
+      cont->write_vector = &d->vector;
+      return 1;
+    }
+    return 0;
+  }
+  OpenDirEntry *od = THREAD_ALLOC(openDirEntryAllocator,
+                                  cont->mutex->thread_holding);
+  od->readers.head = NULL;
+  od->writers.push(cont);
+  od->num_writers = 1;
+  od->max_writers = max_writers;
+  od->vector.data.data = &od->vector.data.fast_data[0];
+  od->dont_update_directory = 0;
+  od->move_resident_alt = 0;
+  od->reading_vec = 0;
+  od->writing_vec = 0;
+  dir_clear(&od->first_dir);
+  cont->od = od;
+  cont->write_vector = &od->vector;
+  bucket[b].push(od);
+  return 1;
+}
+
+int
+OpenDir::signal_readers(int event, Event *e)
+{
+  NOWARN_UNUSED(e);
+  NOWARN_UNUSED(event);
+
+  Queue newly_delayed_readers;
+  EThread *t = mutex->thread_holding;
+  CacheVC *c = NULL;
+  while ((c = delayed_readers.dequeue())) {
+    CACHE_TRY_LOCK(lock, c->mutex, t);
+    if (lock) {
+      c->f.open_read_timeout = 0;
+      c->handleEvent(EVENT_IMMEDIATE, 0);
+      continue;
+    }
+    newly_delayed_readers.push(c);
+  }
+  if (newly_delayed_readers.head) {
+    delayed_readers = newly_delayed_readers;
+    EThread *t1 = newly_delayed_readers.head->mutex->thread_holding;
+    if (!t1)
+      t1 = mutex->thread_holding;
+    t1->schedule_in(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay));
+  }
+  return 0;
+}
+
+int
+OpenDir::close_write(CacheVC *cont)
+{
+  ink_debug_assert(cont->vol->mutex->thread_holding == this_ethread());
+  cont->od->writers.remove(cont);
+  cont->od->num_writers--;
+  if (!cont->od->writers.head) {
+    unsigned int h = cont->first_key.word(0);
+    int b = h % OPEN_DIR_BUCKETS;
+    bucket[b].remove(cont->od);
+    delayed_readers.append(cont->od->readers);
+    signal_readers(0, 0);
+    cont->od->vector.clear();
+    THREAD_FREE(cont->od, openDirEntryAllocator, cont->mutex->thread_holding);
+  }
+  cont->od = NULL;
+  return 0;
+}
+
+OpenDirEntry *
+OpenDir::open_read(INK_MD5 *key)
+{
+  unsigned int h = key->word(0);
+  int b = h % OPEN_DIR_BUCKETS;
+  for (OpenDirEntry *d = bucket[b].head; d; d = d->link.next)
+    if (d->writers.head->first_key == *key)
+      return d;
+  return NULL;
+}
+
+int
+OpenDirEntry::wait(CacheVC *cont, int msec)
+{
+  ink_debug_assert(cont->vol->mutex->thread_holding == this_ethread());
+  cont->f.open_read_timeout = 1;
+  ink_assert(!cont->trigger);
+  cont->trigger = cont->vol->mutex->thread_holding->schedule_in_local(cont, HRTIME_MSECONDS(msec));
+  readers.push(cont);
+  return EVENT_CONT;
+}
+
+//
+// Cache Directory
+//
+
+// return value 1 means no loop
+// zero indicates loop
+int
+dir_bucket_loop_check(Dir *start_dir, Dir *seg)
+{
+  if (start_dir == NULL)
+    return 1;
+
+  Dir *p1 = start_dir;
+  Dir *p2 = start_dir;
+
+  while (p2) {
+    // p1 moves by one entry per iteration
+    p1 = next_dir(p1, seg);
+    // p2 moves by two entries per iteration
+    p2 = next_dir(p2, seg);
+    if (p2)
+      p2 = next_dir(p2, seg);
+    else
+      return 1;
+
+    if (p2 == p1)
+      return 0;                 // we have a loop
+  }
+  return 1;
+}
+
+// adds all the directory entries
+// in a segment to the segment freelist
+void
+dir_init_segment(int s, Vol *d)
+{
+  d->header->freelist[s] = 0;
+  Dir *seg = dir_segment(s, d);
+  int l, b;
+  memset(seg, 0, SIZEOF_DIR * DIR_DEPTH * d->buckets);
+  for (l = 1; l < DIR_DEPTH; l++) {
+    for (b = 0; b < d->buckets; b++) {
+      Dir *bucket = dir_bucket(b, seg);
+      dir_free_entry(dir_bucket_row(bucket, l), s, d);
+    }
+  }
+}
+
+
+// break the infinite loop in directory entries
+// Note : abuse of the token bit in dir entries
+int
+dir_bucket_loop_fix(Dir *start_dir, int s, Vol *d)
+{
+  if (!dir_bucket_loop_check(start_dir, dir_segment(s, d))) {
+    Warning("Dir loop exists, clearing segment %d", s);
+    dir_init_segment(s, d);
+    return 1;
+  }
+  return 0;
+}
+
+int
+dir_freelist_length(Vol *d, int s)
+{
+  int free = 0;
+  Dir *seg = dir_segment(s, d);
+  Dir *e = dir_from_offset(d->header->freelist[s], seg);
+  if (dir_bucket_loop_fix(e, s, d))
+    return (DIR_DEPTH - 1) * d->buckets;
+  while (e) {
+    free++;
+    e = next_dir(e, seg);
+  }
+  return free;
+}
+
+int
+dir_bucket_length(Dir *b, int s, Vol *d)
+{
+  Dir *e = b;
+  int i = 0;
+  Dir *seg = dir_segment(s, d);
+#ifdef LOOP_CHECK_MODE
+  if (dir_bucket_loop_fix(b, s, d))
+    return 1;
+#endif
+  while (e) {
+    i++;
+    if (i > 100)
+      return -1;
+    e = next_dir(e, seg);
+  }
+  return i;
+}
+
+int
+check_dir(Vol *d)
+{
+  int i, s;
+  Debug("cache_check_dir", "inside check dir");
+  for (s = 0; s < d->segments; s++) {
+    Dir *seg = dir_segment(s, d);
+    for (i = 0; i < d->buckets; i++) {
+      Dir *b = dir_bucket(i, seg);
+      if (!(dir_bucket_length(b, s, d) >= 0)) return 0;
+      if (!(!dir_next(b) || dir_offset(b))) return 0;
+      if (!(dir_bucket_loop_check(b, seg))) return 0;
+    }
+  }
+  return 1;
+}
+
+inline void
+unlink_from_freelist(Dir *e, int s, Vol *d)
+{
+  Dir *seg = dir_segment(s, d);
+  Dir *p = dir_from_offset(dir_prev(e), seg);
+  if (p)
+    dir_set_next(p, dir_next(e));
+  else
+    d->header->freelist[s] = dir_next(e);
+  Dir *n = dir_from_offset(dir_next(e), seg);
+  if (n)
+    dir_set_prev(n, dir_prev(e));
+}
+
+inline Dir *
+dir_delete_entry(Dir *e, Dir *p, int s, Vol *d)
+{
+  Dir *seg = dir_segment(s, d);
+  int no = dir_next(e);
+  d->header->dirty = 1;
+  if (p) {
+    unsigned int fo = d->header->freelist[s];
+    unsigned int eo = dir_to_offset(e, seg);
+    dir_clear(e);
+    dir_set_next(p, no);
+    dir_set_next(e, fo);
+    if (fo)
+      dir_set_prev(dir_from_offset(fo, seg), eo);
+    d->header->freelist[s] = eo;
+  } else {
+    Dir *n = next_dir(e, seg);
+    if (n) {
+      dir_assign(e, n);
+      dir_delete_entry(n, e, s, d);
+      return e;
+    } else {
+      dir_clear(e);
+      return NULL;
+    }
+  }
+  return dir_from_offset(no, seg);
+}
+
+inline void
+dir_clean_bucket(Dir *b, int s, Vol *vol)
+{
+  Dir *e = b, *p = NULL;
+  Dir *seg = dir_segment(s, vol);
+#ifdef LOOP_CHECK_MODE
+  int loop_count = 0;
+#endif
+  do {
+#ifdef LOOP_CHECK_MODE
+    loop_count++;
+    if (loop_count > DIR_LOOP_THRESHOLD) {
+      if (dir_bucket_loop_fix(b, s, vol))
+        return;
+    }
+#endif
+    if (!dir_valid(vol, e) || !dir_offset(e)) {
+      if (is_debug_tag_set("dir_clean"))
+        Debug("dir_clean", "cleaning %p tag %X boffset %" PRId64 " b %p p %p l %d",
+              e, dir_tag(e), dir_offset(e), b, p, dir_bucket_length(b, s, vol));
+      if (dir_offset(e))
+        CACHE_DEC_DIR_USED(vol->mutex);
+      e = dir_delete_entry(e, p, s, vol);
+      continue;
+    }
+    p = e;
+    e = next_dir(e, seg);
+  } while (e);
+}
+
+void
+dir_clean_segment(int s, Vol *d)
+{
+  Dir *seg = dir_segment(s, d);
+  for (int i = 0; i < d->buckets; i++) {
+    dir_clean_bucket(dir_bucket(i, seg), s, d);
+    ink_assert(!dir_next(dir_bucket(i, seg)) || dir_offset(dir_bucket(i, seg)));
+  }
+}
+
+void
+dir_clean_vol(Vol *d)
+{
+  for (int i = 0; i < d->segments; i++)
+    dir_clean_segment(i, d);
+  CHECK_DIR(d);
+}
+
+void
+dir_clear_range(off_t start, off_t end, Vol *vol)
+{
+  for (int i = 0; i < vol->buckets * DIR_DEPTH * vol->segments; i++) {
+    Dir *e = dir_index(vol, i);
+    if (!dir_token(e) && dir_offset(e) >= (int64_t)start && dir_offset(e) < (int64_t)end) {
+      CACHE_DEC_DIR_USED(vol->mutex);
+      dir_set_offset(e, 0);     // delete
+    }
+  }
+  dir_clean_vol(vol);
+}
+
+void
+check_bucket_not_contains(Dir *b, Dir *e, Dir *seg)
+{
+  Dir *x = b;
+  do {
+    if (x == e)
+      break;
+    x = next_dir(x, seg);
+  } while (x);
+  ink_assert(!x);
+}
+
+void
+freelist_clean(int s, Vol *vol)
+{
+  dir_clean_segment(s, vol);
+  if (vol->header->freelist[s])
+    return;
+  Warning("cache directory overflow on '%s' segment %d, purging...", vol->path, s);
+  int n = 0;
+  Dir *seg = dir_segment(s, vol);
+  for (int bi = 0; bi < vol->buckets; bi++) {
+    Dir *b = dir_bucket(bi, seg);
+    for (int l = 0; l < DIR_DEPTH; l++) {
+      Dir *e = dir_bucket_row(b, l);
+      if (dir_head(e) && !(n++ % 10)) {
+        CACHE_DEC_DIR_USED(vol->mutex);
+        dir_set_offset(e, 0);   // delete
+      }
+    }
+  }
+  dir_clean_segment(s, vol);
+}
+
+inline Dir *
+freelist_pop(int s, Vol *d)
+{
+  Dir *seg = dir_segment(s, d);
+  Dir *e = dir_from_offset(d->header->freelist[s], seg);
+  if (!e) {
+    freelist_clean(s, d);
+    return NULL;
+  }
+  d->header->freelist[s] = dir_next(e);
+  // if the freelist if bad, punt.
+  if (dir_offset(e)) {
+    dir_init_segment(s, d);
+    return NULL;
+  }
+  Dir *h = dir_from_offset(d->header->freelist[s], seg);
+  if (h)
+    dir_set_prev(h, 0);
+  return e;
+}
+
+int
+dir_segment_accounted(int s, Vol *d, int offby, int *f, int *u, int *et, int *v, int *av, int *as)
+{
+  int free = dir_freelist_length(d, s);
+  int used = 0, empty = 0;
+  int valid = 0, agg_valid = 0;
+  int64_t agg_size = 0;
+  Dir *seg = dir_segment(s, d);
+  for (int bi = 0; bi < d->buckets; bi++) {
+    Dir *b = dir_bucket(bi, seg);
+    Dir *e = b;
+    while (e) {
+      if (!dir_offset(e)) {
+        ink_assert(e == b);
+        empty++;
+      } else {
+        used++;
+        if (dir_valid(d, e))
+          valid++;
+        if (dir_agg_valid(d, e))
+          agg_valid++;
+        agg_size += dir_approx_size(e);
+      }
+      e = next_dir(e, seg);
+      if (!e)
+        break;
+    }
+  }
+  if (f)
+    *f = free;
+  if (u)
+    *u = used;
+  if (et)
+    *et = empty;
+  if (v)
+    *v = valid;
+  if (av)
+    *av = agg_valid;
+  if (as)
+    *as = used ? (int) (agg_size / used) : 0;
+  ink_assert(d->buckets * DIR_DEPTH - (free + used + empty) <= offby);
+  return d->buckets * DIR_DEPTH - (free + used + empty) <= offby;
+}
+
+void
+dir_free_entry(Dir *e, int s, Vol *d)
+{
+  Dir *seg = dir_segment(s, d);
+  unsigned int fo = d->header->freelist[s];
+  unsigned int eo = dir_to_offset(e, seg);
+  dir_set_next(e, fo);
+  if (fo)
+    dir_set_prev(dir_from_offset(fo, seg), eo);
+  d->header->freelist[s] = eo;
+}
+
+int
+dir_probe(CacheKey *key, Vol *d, Dir *result, Dir ** last_collision)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int s = key->word(0) % d->segments;
+  int b = key->word(1) % d->buckets;
+  Dir *seg = dir_segment(s, d);
+  Dir *e = NULL, *p = NULL, *collision = *last_collision;
+  Vol *vol = d;
+  CHECK_DIR(d);
+#ifdef LOOP_CHECK_MODE
+  if (dir_bucket_loop_fix(dir_bucket(b, seg), s, d))
+    return 0;
+#endif
+Lagain:
+  e = dir_bucket(b, seg);
+  if (dir_offset(e))
+    do {
+      if (dir_compare_tag(e, key)) {
+        ink_debug_assert(dir_offset(e));
+        // Bug: 51680. Need to check collision before checking
+        // dir_valid(). In case of a collision, if !dir_valid(), we
+        // don't want to call dir_delete_entry.
+        if (collision) {
+          if (collision == e) {
+            collision = NULL;
+            // increment collison stat
+            // Note: dir_probe could be called multiple times
+            // for the same document and so the collision stat
+            // may not accurately reflect the number of documents
+            // having the same first_key
+            DDebug("cache_stats", "Incrementing dir collisions");
+            CACHE_INC_DIR_COLLISIONS(d->mutex);
+          }
+          goto Lcont;
+        }
+        if (dir_valid(d, e)) {
+          DDebug("dir_probe_hit", "found %X %X vol %d bucket %d boffset %" PRId64 "", key->word(0), key->word(1), d->fd, b, dir_offset(e));
+          dir_assign(result, e);
+          *last_collision = e;
+          ink_assert(dir_offset(e) * CACHE_BLOCK_SIZE < d->len);
+          return 1;
+        } else {                // delete the invalid entry
+          CACHE_DEC_DIR_USED(d->mutex);
+          e = dir_delete_entry(e, p, s, d);
+          continue;
+        }
+      } else
+        DDebug("dir_probe_tag", "tag mismatch %X %X vs expected %X", e, dir_tag(e), key->word(3));
+    Lcont:
+      p = e;
+      e = next_dir(e, seg);
+    } while (e);
+  if (collision) {              // last collision no longer in the list, retry
+    DDebug("cache_stats", "Incrementing dir collisions");
+    CACHE_INC_DIR_COLLISIONS(d->mutex);
+    collision = NULL;
+    goto Lagain;
+  }
+  DDebug("dir_probe_miss", "missed %X %X on vol %d bucket %d at %p", key->word(0), key->word(1), d->fd, b, seg);
+  CHECK_DIR(d);
+  return 0;
+}
+
+int
+dir_insert(CacheKey *key, Vol *d, Dir *to_part)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int s = key->word(0) % d->segments, l;
+  int bi = key->word(1) % d->buckets;
+  ink_assert(dir_approx_size(to_part) <= MAX_FRAG_SIZE + sizeofDoc);
+  Dir *seg = dir_segment(s, d);
+  Dir *e = NULL;
+  Dir *b = dir_bucket(bi, seg);
+  Vol *vol = d;
+#if defined(DEBUG) && defined(DO_CHECK_DIR_FAST)
+  unsigned int t = DIR_MASK_TAG(key->word(2));
+  Dir *col = b;
+  while (col) {
+    ink_assert((dir_tag(col) != t) || (dir_offset(col) != dir_offset(to_part)));
+    col = next_dir(col, seg);
+  }
+#endif
+  CHECK_DIR(d);
+
+Lagain:
+  // get from this row first
+  e = b;
+  if (dir_is_empty(e))
+    goto Lfill;
+  for (l = 1; l < DIR_DEPTH; l++) {
+    e = dir_bucket_row(b, l);
+    if (dir_is_empty(e)) {
+      unlink_from_freelist(e, s, d);
+      goto Llink;
+    }
+  }
+  // get one from the freelist
+  e = freelist_pop(s, d);
+  if (!e)
+    goto Lagain;
+Llink:
+  dir_set_next(e, dir_next(b));
+  dir_set_next(b, dir_to_offset(e, seg));
+Lfill:
+  dir_assign_data(e, to_part);
+  dir_set_tag(e, key->word(2));
+  ink_assert(vol_offset(d, e) < (d->skip + d->len));
+  DDebug("dir_insert",
+        "insert %p %X into vol %d bucket %d at %p tag %X %X boffset %" PRId64 "",
+         e, key->word(0), d->fd, bi, e, key->word(1), dir_tag(e), dir_offset(e));
+  CHECK_DIR(d);
+  d->header->dirty = 1;
+  CACHE_INC_DIR_USED(d->mutex);
+  return 1;
+}
+
+int
+dir_overwrite(CacheKey *key, Vol *d, Dir *dir, Dir *overwrite, bool must_overwrite)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int s = key->word(0) % d->segments, l;
+  int bi = key->word(1) % d->buckets;
+  Dir *seg = dir_segment(s, d);
+  Dir *e = NULL;
+  Dir *b = dir_bucket(bi, seg);
+  unsigned int t = DIR_MASK_TAG(key->word(2));
+  int res = 1;
+#ifdef LOOP_CHECK_MODE
+  int loop_count = 0;
+  bool loop_possible = true;
+#endif
+  Vol *vol = d;
+  CHECK_DIR(d);
+
+  ink_assert((unsigned int) dir_approx_size(dir) <= (unsigned int) (MAX_FRAG_SIZE + sizeofDoc));        // XXX - size should be unsigned
+Lagain:
+  // find entry to overwrite
+  e = b;
+  if (dir_offset(e))
+    do {
+#ifdef LOOP_CHECK_MODE
+      loop_count++;
+      if (loop_count > DIR_LOOP_THRESHOLD && loop_possible) {
+        if (dir_bucket_loop_fix(b, s, d)) {
+          loop_possible = false;
+          goto Lagain;
+        }
+      }
+#endif
+      if (dir_tag(e) == t && dir_offset(e) == dir_offset(overwrite))
+        goto Lfill;
+      e = next_dir(e, seg);
+    } while (e);
+  if (must_overwrite)
+    return 0;
+  res = 0;
+  // get from this row first
+  e = b;
+  if (dir_is_empty(e)) {
+    CACHE_INC_DIR_USED(d->mutex);
+    goto Lfill;
+  }
+  for (l = 1; l < DIR_DEPTH; l++) {
+    e = dir_bucket_row(b, l);
+    if (dir_is_empty(e)) {
+      unlink_from_freelist(e, s, d);
+      goto Llink;
+    }
+  }
+  // get one from the freelist
+  e = freelist_pop(s, d);
+  if (!e)
+    goto Lagain;
+Llink:
+  CACHE_INC_DIR_USED(d->mutex);
+  dir_set_next(e, dir_next(b));
+  dir_set_next(b, dir_to_offset(e, seg));
+Lfill:
+  dir_assign_data(e, dir);
+  dir_set_tag(e, t);
+  ink_assert(vol_offset(d, e) < d->skip + d->len);
+  DDebug("dir_overwrite",
+        "overwrite %p %X into vol %d bucket %d at %p tag %X %X boffset %" PRId64 "",
+         e, key->word(0), d->fd, bi, e, t, dir_tag(e), dir_offset(e));
+  CHECK_DIR(d);
+  d->header->dirty = 1;
+  return res;
+}
+
+int
+dir_delete(CacheKey *key, Vol *d, Dir *del)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int s = key->word(0) % d->segments;
+  int b = key->word(1) % d->buckets;
+  Dir *seg = dir_segment(s, d);
+  Dir *e = NULL, *p = NULL;
+#ifdef LOOP_CHECK_MODE
+  int loop_count = 0;
+#endif
+  Vol *vol = d;
+  CHECK_DIR(d);
+
+  e = dir_bucket(b, seg);
+  if (dir_offset(e))
+    do {
+#ifdef LOOP_CHECK_MODE
+      loop_count++;
+      if (loop_count > DIR_LOOP_THRESHOLD) {
+        if (dir_bucket_loop_fix(dir_bucket(b, seg), s, d))
+          return 0;
+      }
+#endif
+      if (dir_compare_tag(e, key) && dir_offset(e) == dir_offset(del)) {
+        CACHE_DEC_DIR_USED(d->mutex);
+        dir_delete_entry(e, p, s, d);
+        CHECK_DIR(d);
+        return 1;
+      }
+      p = e;
+      e = next_dir(e, seg);
+    } while (e);
+  CHECK_DIR(d);
+  return 0;
+}
+
+// Lookaside Cache
+
+int
+dir_lookaside_probe(CacheKey *key, Vol *d, Dir *result, EvacuationBlock ** eblock)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int i = key->word(3) % LOOKASIDE_SIZE;
+  EvacuationBlock *b = d->lookaside[i].head;
+  while (b) {
+    if (b->evac_frags.key == *key) {
+      if (dir_valid(d, &b->new_dir)) {
+        *result = b->new_dir;
+        DDebug("dir_lookaside", "probe %X success", key->word(0));
+        if (eblock)
+          *eblock = b;
+        return 1;
+      }
+    }
+    b = b->link.next;
+  }
+  DDebug("dir_lookaside", "probe %X failed", key->word(0));
+  return 0;
+}
+
+int
+dir_lookaside_insert(EvacuationBlock *eblock, Vol *d, Dir *to)
+{
+  CacheKey *key = &eblock->evac_frags.earliest_key;
+  DDebug("dir_lookaside", "insert %X %X, offset %d phase %d", key->word(0), key->word(1), (int) dir_offset(to), (int) dir_phase(to));
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int i = key->word(3) % LOOKASIDE_SIZE;
+  EvacuationBlock *b = new_EvacuationBlock(d->mutex->thread_holding);
+  b->evac_frags.key = *key;
+  b->evac_frags.earliest_key = *key;
+  b->earliest_evacuator = eblock->earliest_evacuator;
+  ink_assert(b->earliest_evacuator);
+  b->dir = eblock->dir;
+  b->new_dir = *to;
+  d->lookaside[i].push(b);
+  return 1;
+}
+
+int
+dir_lookaside_fixup(CacheKey *key, Vol *d)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int i = key->word(3) % LOOKASIDE_SIZE;
+  EvacuationBlock *b = d->lookaside[i].head;
+  while (b) {
+    if (b->evac_frags.key == *key) {
+      int res = dir_overwrite(key, d, &b->new_dir, &b->dir, false);
+      DDebug("dir_lookaside", "fixup %X %X offset %d phase %d %d",
+            key->word(0), key->word(1), dir_offset(&b->new_dir), dir_phase(&b->new_dir), res);
+      d->ram_cache->fixup(key, 0, dir_offset(&b->dir), 0, dir_offset(&b->new_dir));
+      d->lookaside[i].remove(b);
+      free_EvacuationBlock(b, d->mutex->thread_holding);
+      return res;
+    }
+    b = b->link.next;
+  }
+  DDebug("dir_lookaside", "fixup %X %X failed", key->word(0), key->word(1));
+  return 0;
+}
+
+void
+dir_lookaside_cleanup(Vol *d)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  for (int i = 0; i < LOOKASIDE_SIZE; i++) {
+    EvacuationBlock *b = d->lookaside[i].head;
+    while (b) {
+      if (!dir_valid(d, &b->new_dir)) {
+        EvacuationBlock *nb = b->link.next;
+        DDebug("dir_lookaside", "cleanup %X %X cleaned up",
+              b->evac_frags.earliest_key.word(0), b->evac_frags.earliest_key.word(1));
+        d->lookaside[i].remove(b);
+        free_CacheVC(b->earliest_evacuator);
+        free_EvacuationBlock(b, d->mutex->thread_holding);
+        b = nb;
+        goto Lagain;
+      }
+      b = b->link.next;
+    Lagain:;
+    }
+  }
+}
+
+void
+dir_lookaside_remove(CacheKey *key, Vol *d)
+{
+  ink_debug_assert(d->mutex->thread_holding == this_ethread());
+  int i = key->word(3) % LOOKASIDE_SIZE;
+  EvacuationBlock *b = d->lookaside[i].head;
+  while (b) {
+    if (b->evac_frags.key == *key) {
+      DDebug("dir_lookaside", "remove %X %X offset %d phase %d",
+            key->word(0), key->word(1), dir_offset(&b->new_dir), dir_phase(&b->new_dir));
+      d->lookaside[i].remove(b);
+      free_EvacuationBlock(b, d->mutex->thread_holding);
+      return;
+    }
+    b = b->link.next;
+  }
+  DDebug("dir_lookaside", "remove %X %X failed", key->word(0), key->word(1));
+  return;
+}
+
+// Cache Sync
+//
+
+void
+dir_sync_init()
+{
+  cacheDirSync = NEW(new CacheSync);
+  cacheDirSync->trigger = eventProcessor.schedule_in(cacheDirSync, HRTIME_SECONDS(cache_config_dir_sync_frequency));
+}
+
+void
+CacheSync::aio_write(int fd, char *b, int n, off_t o)
+{
+  io.aiocb.aio_fildes = fd;
+  io.aiocb.aio_offset = o;
+  io.aiocb.aio_nbytes = n;
+  io.aiocb.aio_buf = b;
+  io.action = this;
+  io.thread = AIO_CALLBACK_THREAD_ANY;
+  ink_assert(ink_aio_write(&io) >= 0);
+}
+
+uint64_t
+dir_entries_used(Vol *d)
+{
+  uint64_t full = 0;
+  uint64_t sfull = 0;
+  for (int s = 0; s < d->segments; full += sfull, s++) {
+    Dir *seg = dir_segment(s, d);
+    sfull = 0;
+    for (int b = 0; b < d->buckets; b++) {
+      Dir *e = dir_bucket(b, seg);
+      if (dir_bucket_loop_fix(e, s, d)) {
+        sfull = 0;
+        break;
+      }
+      while (e) {
+        if (dir_offset(e))
+          sfull++;
+        e = next_dir(e, seg);
+        if (!e)
+          break;
+      }
+    }
+  }
+  return full;
+}
+
+/*
+ * this function flushes the cache meta data to disk when
+ * the cache is shutdown. Must *NOT* be used during regular
+ * operation.
+ */
+
+void
+sync_cache_dir_on_shutdown(void)
+{
+  Debug("cache_dir_sync", "sync started");
+  char *buf = NULL;
+  size_t buflen = 0;
+
+  EThread *t = (EThread *) 0xdeadbeef;
+  for (int i = 0; i < gnvol; i++) {
+    // the process is going down, do a blocking call
+    // dont release the volume's lock, there could
+    // be another aggWrite in progress
+    MUTEX_TAKE_LOCK(gvol[i]->mutex, t);
+    Vol *d = gvol[i];
+
+    if (DISK_BAD(d->disk)) {
+      Debug("cache_dir_sync", "Dir %s: ignoring -- bad disk", d->hash_id);
+      continue;
+    }
+    size_t dirlen = vol_dirlen(d);
+    if (!d->header->dirty && !d->dir_sync_in_progress) {
+      Debug("cache_dir_sync", "Dir %s: ignoring -- not dirty", d->hash_id);
+      continue;
+    }
+#ifdef HIT_EVACUATE
+    // recompute hit_evacuate_window
+    d->hit_evacuate_window = (d->data_blocks * cache_config_hit_evacuate_percent) / 100;
+#endif
+
+
+    // check if we have data in the agg buffer
+    // dont worry about the cachevc s in the agg queue
+    // directories have not been inserted for these writes
+    if (d->agg_buf_pos) {
+      Debug("cache_dir_sync", "Dir %s: flushing agg buffer first", d->hash_id);
+
+      // set write limit
+      d->header->agg_pos = d->header->write_pos + d->agg_buf_pos;
+
+      int r = pwrite(d->fd, d->agg_buffer, d->agg_buf_pos,
+                     d->header->write_pos);
+      if (r != d->agg_buf_pos) {
+        ink_debug_assert(!"flusing agg buffer failed");
+        continue;
+      }
+      d->header->last_write_pos = d->header->write_pos;
+      d->header->write_pos += d->agg_buf_pos;
+      ink_debug_assert(d->header->write_pos == d->header->agg_pos);
+      d->agg_buf_pos = 0;
+      d->header->write_serial++;
+    }
+
+    if (buflen < dirlen) {
+      if (buf)
+        ink_memalign_free(buf);
+      buf = (char *) ink_memalign(sysconf(_SC_PAGESIZE), dirlen);       // buf = (char*) valloc (dirlen);
+      buflen = dirlen;
+    }
+
+    if (!d->dir_sync_in_progress) {
+      d->header->sync_serial++;
+    } else {
+      Debug("cache_dir_sync", "Periodic dir sync in progress -- overwriting");
+    }
+    d->footer->sync_serial = d->header->sync_serial;
+    CHECK_DIR(d);
+    memcpy(buf, d->raw_dir, dirlen);
+    size_t B = d->header->sync_serial & 1;
+    off_t start = d->skip + (B ? dirlen : 0);
+    B = pwrite(d->fd, buf, dirlen, start);
+    ink_debug_assert(B == dirlen);
+    Debug("cache_dir_sync", "done syncing dir for vol %s", d->hash_id);
+  }
+  Debug("cache_dir_sync", "sync done");
+  if (buf)
+    ink_memalign_free(buf);
+}
+
+
+
+int
+CacheSync::mainEvent(int event, Event *e)
+{
+  NOWARN_UNUSED(e);
+  NOWARN_UNUSED(event);
+
+  if (trigger) {
+    trigger->cancel_action();
+    trigger = NULL;
+  }
+
+Lrestart:
+  if (vol >= gnvol) {
+    vol = 0;
+    if (buf) {
+      ink_memalign_free(buf);
+      buf = 0;
+      buflen = 0;
+    }
+    Debug("cache_dir_sync", "sync done");
+    if (event == EVENT_INTERVAL)
+      trigger = e->ethread->schedule_in(this, HRTIME_SECONDS(cache_config_dir_sync_frequency));
+    else
+      trigger = eventProcessor.schedule_in(this, HRTIME_SECONDS(cache_config_dir_sync_frequency));
+    return EVENT_CONT;
+  }
+  if (event == AIO_EVENT_DONE) {
+    // AIO Thread
+    if (io.aio_result != (int64_t)io.aiocb.aio_nbytes) {
+      Warning("vol write error during directory sync '%s'", gvol[vol]->hash_id);
+      event = EVENT_NONE;
+      goto Ldone;
+    }
+    trigger = eventProcessor.schedule_in(this, SYNC_DELAY);
+    return EVENT_CONT;
+  }
+  {
+    CACHE_TRY_LOCK(lock, gvol[vol]->mutex, mutex->thread_holding);
+    if (!lock) {
+      trigger = eventProcessor.schedule_in(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay));
+      return EVENT_CONT;
+    }
+    Vol *d = gvol[vol];
+
+#ifdef HIT_EVACUATE
+    // recompute hit_evacuate_window
+    d->hit_evacuate_window = (d->data_blocks * cache_config_hit_evacuate_percent) / 100;
+#endif
+
+    if (DISK_BAD(d->disk))
+      goto Ldone;
+
+    int headerlen = ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter));
+    size_t dirlen = vol_dirlen(d);
+    if (!writepos) {
+      // start
+      Debug("cache_dir_sync", "sync started");
+      /* Don't sync the directory to disk if its not dirty. Syncing the
+         clean directory to disk is also the cause of INKqa07151. Increasing
+         the serial serial causes the cache to recover more data
+         than necessary.
+         The dirty bit it set in dir_insert, dir_overwrite and dir_delete_entry
+       */
+      if (!d->header->dirty) {
+        Debug("cache_dir_sync", "Dir %s not dirty", d->hash_id);
+        goto Ldone;
+      }
+      if (d->is_io_in_progress() || d->agg_buf_pos) {
+        Debug("cache_dir_sync", "Dir %s: waiting for agg buffer", d->hash_id);
+        d->dir_sync_waiting = 1;
+        if (!d->is_io_in_progress())
+          d->aggWrite(EVENT_IMMEDIATE, 0);
+        return EVENT_CONT;
+      }
+      Debug("cache_dir_sync", "pos: %" PRIu64 " Dir %s dirty...syncing to disk", d->header->write_pos, d->hash_id);
+      d->header->dirty = 0;
+      if (buflen < dirlen) {
+        if (buf)
+          ink_memalign_free(buf);
+        buf = (char *) ink_memalign(sysconf(_SC_PAGESIZE), dirlen);
+        buflen = dirlen;
+      }
+      d->header->sync_serial++;
+      d->footer->sync_serial = d->header->sync_serial;
+      CHECK_DIR(d);
+      memcpy(buf, d->raw_dir, dirlen);
+      d->dir_sync_in_progress = 1;
+    }
+    size_t B = d->header->sync_serial & 1;
+    off_t start = d->skip + (B ? dirlen : 0);
+
+    if (!writepos) {
+      // write header
+      aio_write(d->fd, buf + writepos, headerlen, start + writepos);
+      writepos += headerlen;
+    } else if (writepos < (off_t)dirlen - headerlen) {
+      // write part of body
+      int l = SYNC_MAX_WRITE;
+      if (writepos + l > (off_t)dirlen - headerlen)
+        l = dirlen - headerlen - writepos;
+      aio_write(d->fd, buf + writepos, l, start + writepos);
+      writepos += l;
+    } else if (writepos < (off_t)dirlen) {
+      ink_assert(writepos == (off_t)dirlen - headerlen);
+      // write footer
+      aio_write(d->fd, buf + writepos, headerlen, start + writepos);
+      writepos += headerlen;
+    } else {
+      d->dir_sync_in_progress = 0;
+      goto Ldone;
+    }
+    return EVENT_CONT;
+  }
+Ldone:
+  // done
+  writepos = 0;
+  vol++;
+  goto Lrestart;
+}
+
+//
+// Check
+//
+
+#define HIST_DEPTH 8
+int
+Vol::dir_check(bool fix)
+{
+  NOWARN_UNUSED(fix);
+  int hist[HIST_DEPTH + 1] = { 0 };
+  int *shist = (int*)xmalloc(segments * sizeof(int));
+  memset(shist, 0, segments * sizeof(int));
+  int j;
+  int stale = 0, full = 0, empty = 0;
+  int last = 0, free = 0;
+  for (int s = 0; s < segments; s++) {
+    Dir *seg = dir_segment(s, this);
+    for (int b = 0; b < buckets; b++) {
+      int h = 0;
+      Dir *e = dir_bucket(b, seg);
+      while (e) {
+        if (!dir_offset(e))
+          empty++;
+        else {
+          h++;
+          if (!dir_valid(this, e))
+            stale++;
+          else
+            full++;
+        }
+        e = next_dir(e, seg);
+        if (!e)
+          break;
+      }
+      if (h > HIST_DEPTH)
+        h = HIST_DEPTH;
+      hist[h]++;
+    }
+    int t = stale + full;
+    shist[s] = t - last;
+    last = t;
+    free += dir_freelist_length(this, s);
+  }
+  int total = buckets * segments * DIR_DEPTH;
+  printf("    Directory for [%s]\n", hash_id);
+  printf("        Bytes:     %d\n", total * SIZEOF_DIR);
+  printf("        Segments:  %" PRIu64 "\n", (uint64_t)segments);
+  printf("        Buckets:   %" PRIu64 "\n", (uint64_t)buckets);
+  printf("        Entries:   %d\n", total);
+  printf("        Full:      %d\n", full);
+  printf("        Empty:     %d\n", empty);
+  printf("        Stale:     %d\n", stale);
+  printf("        Free:      %d\n", free);
+  printf("        Bucket Fullness:   ");
+  for (j = 0; j < HIST_DEPTH; j++) {
+    printf("%8d ", hist[j]);
+    if ((j % 4 == 3))
+      printf("\n" "                           ");
+  }
+  printf("\n");
+  printf("        Segment Fullness:  ");
+  for (j = 0; j < segments; j++) {
+    printf("%5d ", shist[j]);
+    if ((j % 5 == 4))
+      printf("\n" "                           ");
+  }
+  printf("\n");
+  printf("        Freelist Fullness: ");
+  for (j = 0; j < segments; j++) {
+    printf("%5d ", dir_freelist_length(this, j));
+    if ((j % 5 == 4))
+      printf("\n" "                           ");
+  }
+  printf("\n");
+  ::xfree(shist);
+  return 0;
+}
+
+//
+// Static Tables
+//
+
+// permutation table
+uint8_t CacheKey_next_table[256] = {
+  21, 53, 167, 51, 255, 126, 241, 151,
+  115, 66, 155, 174, 226, 215, 80, 188,
+  12, 95, 8, 24, 162, 201, 46, 104,
+  79, 172, 39, 68, 56, 144, 142, 217,
+  101, 62, 14, 108, 120, 90, 61, 47,
+  132, 199, 110, 166, 83, 125, 57, 65,
+  19, 130, 148, 116, 228, 189, 170, 1,
+  71, 0, 252, 184, 168, 177, 88, 229,
+  242, 237, 183, 55, 13, 212, 240, 81,
+  211, 74, 195, 205, 147, 93, 30, 87,
+  86, 63, 135, 102, 233, 106, 118, 163,
+  107, 10, 243, 136, 160, 119, 43, 161,
+  206, 141, 203, 78, 175, 36, 37, 140,
+  224, 197, 185, 196, 248, 84, 122, 73,
+  152, 157, 18, 225, 219, 145, 45, 2,
+  171, 249, 173, 32, 143, 137, 69, 41,
+  35, 89, 33, 98, 179, 214, 114, 231,
+  251, 123, 180, 194, 29, 3, 178, 31,
+  192, 164, 15, 234, 26, 230, 91, 156,
+  5, 16, 23, 244, 58, 50, 4, 67,
+  134, 165, 60, 235, 250, 7, 138, 216,
+  49, 139, 191, 154, 11, 52, 239, 59,
+  111, 245, 9, 64, 25, 129, 247, 232,
+  190, 246, 109, 22, 112, 210, 221, 181,
+  92, 169, 48, 100, 193, 77, 103, 133,
+  70, 220, 207, 223, 176, 204, 76, 186,
+  200, 208, 158, 182, 227, 222, 131, 38,
+  187, 238, 6, 34, 253, 128, 146, 44,
+  94, 127, 105, 153, 113, 20, 27, 124,
+  159, 17, 72, 218, 96, 149, 213, 42,
+  28, 254, 202, 40, 117, 82, 97, 209,
+  54, 236, 121, 75, 85, 150, 99, 198,
+};
+
+// permutation table
+uint8_t CacheKey_prev_table[256] = {
+  57, 55, 119, 141, 158, 152, 218, 165,
+  18, 178, 89, 172, 16, 68, 34, 146,
+  153, 233, 114, 48, 229, 0, 187, 154,
+  19, 180, 148, 230, 240, 140, 78, 143,
+  123, 130, 219, 128, 101, 102, 215, 26,
+  243, 127, 239, 94, 223, 118, 22, 39,
+  194, 168, 157, 3, 173, 1, 248, 67,
+  28, 46, 156, 175, 162, 38, 33, 81,
+  179, 47, 9, 159, 27, 126, 200, 56,
+  234, 111, 73, 251, 206, 197, 99, 24,
+  14, 71, 245, 44, 109, 252, 80, 79,
+  62, 129, 37, 150, 192, 77, 224, 17,
+  236, 246, 131, 254, 195, 32, 83, 198,
+  23, 226, 85, 88, 35, 186, 42, 176,
+  188, 228, 134, 8, 51, 244, 86, 93,
+  36, 250, 110, 137, 231, 45, 5, 225,
+  221, 181, 49, 214, 40, 199, 160, 82,
+  91, 125, 166, 169, 103, 97, 30, 124,
+  29, 117, 222, 76, 50, 237, 253, 7,
+  112, 227, 171, 10, 151, 113, 210, 232,
+  92, 95, 20, 87, 145, 161, 43, 2,
+  60, 193, 54, 120, 25, 122, 11, 100,
+  204, 61, 142, 132, 138, 191, 211, 66,
+  59, 106, 207, 216, 15, 53, 184, 170,
+  144, 196, 139, 74, 107, 105, 255, 41,
+  208, 21, 242, 98, 205, 75, 96, 202,
+  209, 247, 189, 72, 69, 238, 133, 13,
+  167, 31, 235, 116, 201, 190, 213, 203,
+  104, 115, 12, 212, 52, 63, 149, 135,
+  183, 84, 147, 163, 249, 65, 217, 174,
+  70, 6, 64, 90, 155, 177, 185, 182,
+  108, 121, 164, 136, 58, 220, 241, 4,
+};
+
+//
+// Regression
+//
+unsigned int regress_rand_seed = 0;
+void
+regress_rand_init(unsigned int i)
+{
+  regress_rand_seed = i;
+}
+
+void
+regress_rand_CacheKey(CacheKey *key)
+{
+  unsigned int *x = (unsigned int *) key;
+  for (int i = 0; i < 4; i++)
+    x[i] = next_rand(®ress_rand_seed);
+}
+
+void
+dir_corrupt_bucket(Dir *b, int s, Vol *d)
+{
+  // coverity[secure_coding]
+  int l = ((int) (dir_bucket_length(b, s, d) * drand48()));
+  Dir *e = b;
+  Dir *seg = dir_segment(s, d);
+  for (int i = 0; i < l; i++) {
+    ink_release_assert(e);
+    e = next_dir(e, seg);
+  }
+  dir_set_next(e, dir_to_offset(e, seg));
+}
+
+EXCLUSIVE_REGRESSION_TEST(Cache_dir) (RegressionTest *t, int atype, int *status) {
+  NOWARN_UNUSED(atype);
+  ink_hrtime ttime;
+  int ret = REGRESSION_TEST_PASSED;
+
+  if ((CacheProcessor::IsCacheEnabled() != CACHE_INITIALIZED) || gnvol < 1) {
+    rprintf(t, "cache not ready/configured");
+    *status = REGRESSION_TEST_FAILED;
+    return;
+  }
+  Vol *d = gvol[0];
+  EThread *thread = this_ethread();
+  MUTEX_TRY_LOCK(lock, d->mutex, thread);
+  ink_release_assert(lock);
+  rprintf(t, "clearing vol 0\n", free);
+  vol_dir_clear(d);
+
+  // coverity[var_decl]
+  Dir dir;
+  dir_clear(&dir);
+  dir_set_phase(&dir, 0);
+  dir_set_head(&dir, true);
+  dir_set_offset(&dir, 1);
+
+  d->header->agg_pos = d->header->write_pos += 1024;
+
+  CacheKey key;
+  rand_CacheKey(&key, thread->mutex);
+
+  int s = key.word(0) % d->segments, i, j;
+  Dir *seg = dir_segment(s, d);
+
+  // test insert
+  rprintf(t, "insert test\n", free);
+  int inserted = 0;
+  int free = dir_freelist_length(d, s);
+  int n = free;
+  rprintf(t, "free: %d\n", free);
+  while (n--) {
+    if (!dir_insert(&key, d, &dir))
+      break;
+    inserted++;
+  }
+  rprintf(t, "inserted: %d\n", inserted);
+  if ((unsigned int) (inserted - free) > 1)
+    ret = REGRESSION_TEST_FAILED;
+
+  // test delete
+  rprintf(t, "delete test\n");
+  for (i = 0; i < d->buckets; i++)
+    for (j = 0; j < DIR_DEPTH; j++)
+      dir_set_offset(dir_bucket_row(dir_bucket(i, seg), j), 0); // delete
+  dir_clean_segment(s, d);
+  int newfree = dir_freelist_length(d, s);
+  rprintf(t, "newfree: %d\n", newfree);
+  if ((unsigned int) (newfree - free) > 1)
+    ret = REGRESSION_TEST_FAILED;
+
+  // test insert-delete
+  rprintf(t, "insert-delete test\n");
+  regress_rand_init(13);
+  ttime = ink_get_hrtime_internal();
+  for (i = 0; i < newfree; i++) {
+    regress_rand_CacheKey(&key);
+    dir_insert(&key, d, &dir);
+  }
+  uint64_t us = (ink_get_hrtime_internal() - ttime) / HRTIME_USECOND;
+  //On windows us is sometimes 0. I don't know why.
+  //printout the insert rate only if its not 0
+  if (us)
+    rprintf(t, "insert rate = %d / second\n", (int) ((newfree * (uint64_t) 1000000) / us));
+  regress_rand_init(13);
+  ttime = ink_get_hrtime_internal();
+  for (i = 0; i < newfree; i++) {
+    Dir *last_collision = 0;
+    regress_rand_CacheKey(&key);
+    if (!dir_probe(&key, d, &dir, &last_collision))
+      ret = REGRESSION_TEST_FAILED;
+  }
+  us = (ink_get_hrtime_internal() - ttime) / HRTIME_USECOND;
+  //On windows us is sometimes 0. I don't know why.
+  //printout the probe rate only if its not 0
+  if (us)
+    rprintf(t, "probe rate = %d / second\n", (int) ((newfree * (uint64_t) 1000000) / us));
+
+
+  for (int c = 0; c < vol_direntries(d) * 0.75; c++) {
+    regress_rand_CacheKey(&key);
+    dir_insert(&key, d, &dir);
+  }
+
+
+  Dir dir1;
+  memset(&dir1, 0, sizeof(dir1));
+  int s1, b1;
+
+  rprintf(t, "corrupt_bucket test\n");
+  for (int ntimes = 0; ntimes < 10; ntimes++) {
+#ifdef LOOP_CHECK_MODE
+    // dir_probe in bucket with loop
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    b1 = key.word(1) % d->buckets;
+    dir_corrupt_bucket(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+    dir_insert(&key, d, &dir);
+    Dir *last_collision = 0;
+    dir_probe(&key, d, &dir, &last_collision);
+
+
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    b1 = key.word(1) % d->buckets;
+    dir_corrupt_bucket(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+
+    last_collision = 0;
+    dir_probe(&key, d, &dir, &last_collision);
+
+    // dir_overwrite in bucket with loop
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    b1 = key.word(1) % d->buckets;
+    CacheKey key1;
+    key1.b[1] = 127;
+    dir1 = dir;
+    dir_set_offset(&dir1, 23);
+    dir_insert(&key1, d, &dir1);
+    dir_insert(&key, d, &dir);
+    key1.b[1] = 80;
+    dir_insert(&key1, d, &dir1);
+    dir_corrupt_bucket(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+    dir_overwrite(&key, d, &dir, &dir, 1);
+
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    b1 = key.word(1) % d->buckets;
+    key.b[1] = 23;
+    dir_insert(&key, d, &dir1);
+    dir_corrupt_bucket(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+    dir_overwrite(&key, d, &dir, &dir, 0);
+
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    Dir *seg1 = dir_segment(s1, d);
+    // dir_freelist_length in freelist with loop
+    dir_corrupt_bucket(dir_from_offset(d->header->freelist[s], seg1), s1, d);
+    dir_freelist_length(d, s1);
+
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    b1 = key.word(1) % d->buckets;
+    // dir_bucket_length in bucket with loop
+    dir_corrupt_bucket(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+    dir_bucket_length(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+    if (!check_dir(d))
+      ret = REGRESSION_TEST_FAILED;
+#else
+    // test corruption detection
+    rand_CacheKey(&key, thread->mutex);
+    s1 = key.word(0) % d->segments;
+    b1 = key.word(1) % d->buckets;
+
+    dir_insert(&key, d, &dir1);
+    dir_insert(&key, d, &dir1);
+    dir_insert(&key, d, &dir1);
+    dir_insert(&key, d, &dir1);
+    dir_insert(&key, d, &dir1);
+    dir_corrupt_bucket(dir_bucket(b1, dir_segment(s1, d)), s1, d);
+    if (check_dir(d))
+      ret = REGRESSION_TEST_FAILED;
+#endif
+  }
+  vol_dir_clear(d);
+  *status = ret;
+}
diff --git a/iocore/cache/CacheDisk.cc b/iocore/cache/CacheDisk.cc
new file mode 100644
index 00000000..38ea5e39
--- /dev/null
+++ b/iocore/cache/CacheDisk.cc
@@ -0,0 +1,422 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "P_Cache.h"
+
+
+int
+CacheDisk::open(char *s, off_t blocks, off_t askip, int ahw_sector_size, int fildes, bool clear)
+{
+  path = xstrdup(s);
+  hw_sector_size = ahw_sector_size;
+  fd = fildes;
+  skip = askip;
+  start = skip;
+  /* we can't use fractions of store blocks. */
+  len = blocks;
+  io.aiocb.aio_fildes = fd;
+  io.aiocb.aio_reqprio = 0;
+  io.action = this;
+  // determine header size and hence start point by successive approximation
+  uint64_t l;
+  for (int i = 0; i < 3; i++) {
+    l = (len * STORE_BLOCK_SIZE) - (start - skip);
+    if (l >= MIN_VOL_SIZE) {
+      header_len = sizeof(DiskHeader) + (l / MIN_VOL_SIZE - 1) * sizeof(DiskVolBlock);
+    } else {
+      header_len = sizeof(DiskHeader);
+    }
+    start = skip + header_len;
+  }
+
+  disk_vols = (DiskVol **) xmalloc((l / MIN_VOL_SIZE + 1) * sizeof(DiskVol **));
+  memset(disk_vols, 0, (l / MIN_VOL_SIZE + 1) * sizeof(DiskVol **));
+  header_len = ROUND_TO_STORE_BLOCK(header_len);
+  start = skip + header_len;
+  num_usable_blocks = (off_t(len * STORE_BLOCK_SIZE) - (start - askip)) >> STORE_BLOCK_SHIFT;
+
+#if defined(_WIN32)
+  header = (DiskHeader *) malloc(header_len);
+#else
+  header = (DiskHeader *) valloc(header_len);
+#endif
+
+  memset(header, 0, header_len);
+  if (clear) {
+    SET_HANDLER(&CacheDisk::clearDone);
+    return clearDisk();
+  }
+
+  SET_HANDLER(&CacheDisk::openStart);
+  io.aiocb.aio_offset = skip;
+  io.aiocb.aio_buf = (char *) header;
+  io.aiocb.aio_nbytes = header_len;
+  io.thread = AIO_CALLBACK_THREAD_ANY;
+  ink_aio_read(&io);
+  return 0;
+}
+
+CacheDisk::~CacheDisk()
+{
+  if (path) {
+    xfree(path);
+    for (int i = 0; i < (int) header->num_volumes; i++) {
+      DiskVolBlockQueue *q = NULL;
+      while (disk_vols[i] && (q = (disk_vols[i]->dpb_queue.pop()))) {
+        delete q;
+      }
+    }
+    xfree(disk_vols);
+    free(header);
+  }
+  if (free_blocks) {
+    DiskVolBlockQueue *q = NULL;
+    while ((q = (free_blocks->dpb_queue.pop()))) {
+      delete q;
+    }
+    delete free_blocks;
+  }
+}
+
+int
+CacheDisk::clearDisk()
+{
+  delete_all_volumes();
+
+  io.aiocb.aio_offset = skip;
+  io.aiocb.aio_buf = header;
+  io.aiocb.aio_nbytes = header_len;
+  io.thread = AIO_CALLBACK_THREAD_ANY;
+  ink_aio_write(&io);
+  return 0;
+}
+
+int
+CacheDisk::clearDone(int event, void *data)
+{
+  NOWARN_UNUSED(data);
+  ink_assert(event == AIO_EVENT_DONE);
+
+  if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
+    Warning("Could not clear disk header for disk %s: declaring disk bad", path);
+    SET_DISK_BAD(this);
+  }
+//  update_header();
+
+  SET_HANDLER(&CacheDisk::openDone);
+  return openDone(EVENT_IMMEDIATE, 0);
+}
+
+int
+CacheDisk::openStart(int event, void *data)
+{
+  NOWARN_UNUSED(data);
+  ink_assert(event == AIO_EVENT_DONE);
+
+  if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
+    Warning("could not read disk header for disk %s: declaring disk bad", path);
+    SET_DISK_BAD(this);
+    SET_HANDLER(&CacheDisk::openDone);
+    return openDone(EVENT_IMMEDIATE, 0);
+  }
+
+  if (header->magic != DISK_HEADER_MAGIC || header->num_blocks != (uint64_t)len) {
+    Warning("disk header different for disk %s: clearing the disk", path);
+    SET_HANDLER(&CacheDisk::clearDone);
+    clearDisk();
+    return EVENT_DONE;
+  }
+
+  cleared = 0;
+  /* populate disk_vols */
+  update_header();
+
+  SET_HANDLER(&CacheDisk::openDone);
+  return openDone(EVENT_IMMEDIATE, 0);
+}
+
+int
+CacheDisk::openDone(int event, void *data)
+{
+  NOWARN_UNUSED(data);
+  NOWARN_UNUSED(event);
+  if (cacheProcessor.start_done) {
+    SET_HANDLER(&CacheDisk::syncDone);
+    cacheProcessor.diskInitialized();
+    return EVENT_DONE;
+  } else {
+    eventProcessor.schedule_in(this, HRTIME_MSECONDS(5), ET_CALL);
+    return EVENT_CONT;
+  }
+}
+
+int
+CacheDisk::sync()
+{
+  io.aiocb.aio_offset = skip;
+  io.aiocb.aio_buf = header;
+  io.aiocb.aio_nbytes = header_len;
+  io.thread = AIO_CALLBACK_THREAD_ANY;
+  ink_aio_write(&io);
+  return 0;
+}
+
+int
+CacheDisk::syncDone(int event, void *data)
+{
+  NOWARN_UNUSED(data);
+
+  ink_assert(event == AIO_EVENT_DONE);
+
+  if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
+    Warning("Error writing disk header for disk %s:disk bad", path);
+    SET_DISK_BAD(this);
+    return EVENT_DONE;
+  }
+
+  return EVENT_DONE;
+}
+
+/* size is in store blocks */
+DiskVolBlock *
+CacheDisk::create_volume(int number, off_t size_in_blocks, int scheme)
+{
+  if (size_in_blocks == 0)
+    return NULL;
+
+  DiskVolBlockQueue *q = free_blocks->dpb_queue.head;
+  DiskVolBlockQueue *closest_match = q;
+
+  if (!q)
+    return NULL;
+
+  off_t max_blocks = MAX_VOL_SIZE >> STORE_BLOCK_SHIFT;
+  size_in_blocks = (size_in_blocks <= max_blocks) ? size_in_blocks : max_blocks;
+
+  int blocks_per_vol = VOL_BLOCK_SIZE / STORE_BLOCK_SIZE;
+//  ink_assert(!(size_in_blocks % blocks_per_vol));
+  DiskVolBlock *p = 0;
+  for (; q; q = q->link.next) {
+    if ((off_t)q->b->len >= size_in_blocks) {
+      p = q->b;
+      q->new_block = 1;
+      break;
+    } else {
+      if (closest_match->b->len < q->b->len)
+        closest_match = q;
+    }
+  }
+
+  if (!p && !closest_match)
+    return NULL;
+
+  if (!p && closest_match) {
+    /* allocate from the closest match */
+    q = closest_match;
+    p = q->b;
+    q->new_block = 1;
+    ink_assert(size_in_blocks > (off_t) p->len);
+    /* allocate in 128 megabyte chunks. The Remaining space should
+       be thrown away */
+    size_in_blocks = (p->len - (p->len % blocks_per_vol));
+    wasted_space += p->len % blocks_per_vol;
+  }
+
+  free_blocks->dpb_queue.remove(q);
+  free_space -= p->len;
+  free_blocks->size -= p->len;
+
+  size_t new_size = p->len - size_in_blocks;
+  if (new_size >= (size_t)blocks_per_vol) {
+    /* create a new volume */
+    DiskVolBlock *dpb = &header->vol_info[header->num_diskvol_blks];
+    *dpb = *p;
+    dpb->len -= size_in_blocks;
+    dpb->offset += ((off_t) size_in_blocks * STORE_BLOCK_SIZE);
+
+    DiskVolBlockQueue *new_q = NEW(new DiskVolBlockQueue());
+    new_q->b = dpb;
+    free_blocks->dpb_queue.enqueue(new_q);
+    free_blocks->size += dpb->len;
+    free_space += dpb->len;
+    header->num_diskvol_blks++;
+  } else
+    header->num_free--;
+
+  p->len = size_in_blocks;
+  p->free = 0;
+  p->number = number;
+  p->type = scheme;
+  header->num_used++;
+
+  unsigned int i;
+  /* add it to its disk_vol */
+  for (i = 0; i < header->num_volumes; i++) {
+    if (disk_vols[i]->vol_number == number) {
+      disk_vols[i]->dpb_queue.enqueue(q);
+      disk_vols[i]->num_volblocks++;
+      disk_vols[i]->size += q->b->len;
+      break;
+    }
+  }
+  if (i == header->num_volumes) {
+    disk_vols[i] = NEW(new DiskVol());
+    disk_vols[i]->num_volblocks = 1;
+    disk_vols[i]->vol_number = number;
+    disk_vols[i]->disk = this;
+    disk_vols[i]->dpb_queue.enqueue(q);
+    disk_vols[i]->size = q->b->len;
+    header->num_volumes++;
+  }
+  return p;
+}
+
+
+int
+CacheDisk::delete_volume(int number)
+{
+  unsigned int i;
+  for (i = 0; i < header->num_volumes; i++) {
+    if (disk_vols[i]->vol_number == number) {
+
+      DiskVolBlockQueue *q;
+      for (q = disk_vols[i]->dpb_queue.head; q;) {
+        DiskVolBlock *p = q->b;
+        p->type = CACHE_NONE_TYPE;
+        p->free = 1;
+        free_space += p->len;
+        header->num_free++;
+        header->num_used--;
+        DiskVolBlockQueue *temp_q = q->link.next;
+        disk_vols[i]->dpb_queue.remove(q);
+        free_blocks->dpb_queue.enqueue(q);
+        q = temp_q;
+      }
+      free_blocks->num_volblocks += disk_vols[i]->num_volblocks;
+      free_blocks->size += disk_vols[i]->size;
+
+      delete disk_vols[i];
+      /* move all the other disk vols */
+      for (unsigned int j = i; j < (header->num_volumes - 1); j++) {
+        disk_vols[j] = disk_vols[j + 1];
+      }
+      header->num_volumes--;
+      return 0;
+    }
+  }
+  return -1;
+}
+
+void
+CacheDisk::update_header()
+{
+  unsigned int n = 0;
+  unsigned int i, j;
+  if (free_blocks) {
+    DiskVolBlockQueue *q = NULL;
+    while ((q = (free_blocks->dpb_queue.pop()))) {
+      delete q;
+    }
+    delete free_blocks;
+  }
+  free_blocks = NEW(new DiskVol());
+  free_blocks->vol_number = -1;
+  free_blocks->disk = this;
+  free_blocks->num_volblocks = 0;
+  free_blocks->size = 0;
+  free_space = 0;
+
+  for (i = 0; i < header->num_diskvol_blks; i++) {
+    DiskVolBlockQueue *dpbq = NEW(new DiskVolBlockQueue());
+    bool dpbq_referenced = false;
+    dpbq->b = &header->vol_info[i];
+    if (header->vol_info[i].free) {
+      free_blocks->num_volblocks++;
+      free_blocks->size += dpbq->b->len;
+      free_blocks->dpb_queue.enqueue(dpbq);
+      dpbq_referenced = true;
+      free_space += dpbq->b->len;
+      continue;
+    }
+    int vol_number = header->vol_info[i].number;
+    for (j = 0; j < n; j++) {
+      if (disk_vols[j]->vol_number == vol_number) {
+        disk_vols[j]->dpb_queue.enqueue(dpbq);
+        dpbq_referenced = true;
+        disk_vols[j]->num_volblocks++;
+        disk_vols[j]->size += dpbq->b->len;
+        break;
+      }
+    }
+    if (j == n) {
+      // did not find a matching volume number. create a new
+      // one
+      disk_vols[j] = NEW(new DiskVol());
+      disk_vols[j]->vol_number = vol_number;
+      disk_vols[j]->disk = this;
+      disk_vols[j]->num_volblocks = 1;
+      disk_vols[j]->size = dpbq->b->len;
+      disk_vols[j]->dpb_queue.enqueue(dpbq);
+      dpbq_referenced = true;
+      n++;
+    }
+    // check to see if we even used the dpbq allocated
+    if (dpbq_referenced == false) {
+      delete dpbq;
+    }
+  }
+
+  ink_assert(n == header->num_volumes);
+}
+
+DiskVol *
+CacheDisk::get_diskvol(int vol_number)
+{
+  unsigned int i;
+  for (i = 0; i < header->num_volumes; i++) {
+    if (disk_vols[i]->vol_number == vol_number) {
+      return disk_vols[i];
+    }
+  }
+  return NULL;
+}
+
+int
+CacheDisk::delete_all_volumes()
+{
+  header->vol_info[0].offset = start;
+  header->vol_info[0].len = num_usable_blocks;
+  header->vol_info[0].type = CACHE_NONE_TYPE;
+  header->vol_info[0].free = 1;
+
+  header->magic = DISK_HEADER_MAGIC;
+  header->num_used = 0;
+  header->num_volumes = 0;
+  header->num_free = 1;
+  header->num_diskvol_blks = 1;
+  header->num_blocks = len;
+  cleared = 1;
+  update_header();
+
+  return 0;
+}
diff --git a/iocore/cache/CacheHosting.cc b/iocore/cache/CacheHosting.cc
new file mode 100644
index 00000000..180b736c
--- /dev/null
+++ b/iocore/cache/CacheHosting.cc
@@ -0,0 +1,1224 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "P_Cache.h"
+#include "I_Layout.h"
+
+extern int gndisks;
+
+matcher_tags CacheHosting_tags = {
+  "hostname", "domain"
+};
+
+
+bool alarmAlready = false;
+
+/*************************************************************
+ *   Begin class HostMatcher
+ *************************************************************/
+
+CacheHostMatcher::CacheHostMatcher(const char *name, const char *filename, int typ):
+data_array(NULL),
+array_len(-1),
+num_el(-1),
+matcher_name(name),
+file_name(filename),
+type(typ)
+{
+  host_lookup = NEW(new HostLookup(name));
+}
+
+CacheHostMatcher::~CacheHostMatcher()
+{
+
+  delete host_lookup;
+  delete[]data_array;
+}
+
+//
+// template 
+// void HostMatcher::Print()
+//
+//  Debugging Method
+//
+void
+CacheHostMatcher::Print()
+{
+
+  printf("\tHost/Domain Matcher with %d elements\n", num_el);
+  host_lookup->Print(PrintFunc);
+}
+
+//
+// template 
+// void CacheHostMatcher::PrintFunc(void* opaque_data)
+//
+//  Debugging Method
+//
+void
+CacheHostMatcher::PrintFunc(void *opaque_data)
+{
+  CacheHostRecord *d = (CacheHostRecord *) opaque_data;
+  d->Print();
+}
+
+// void CacheHostMatcher::AllocateSpace(int num_entries)
+//
+//  Allocates the the HostLeaf and Data arrays
+//
+void
+CacheHostMatcher::AllocateSpace(int num_entries)
+{
+  // Should not have been allocated before
+  ink_assert(array_len == -1);
+
+  host_lookup->AllocateSpace(num_entries);
+
+  data_array = NEW(new CacheHostRecord[num_entries]);
+
+  array_len = num_entries;
+  num_el = 0;
+}
+
+// void CacheHostMatcher::Match(RD* rdata, Result* result)
+//
+//  Searches our tree and updates argresult for each element matching
+//    arg hostname
+//
+void
+CacheHostMatcher::Match(char *rdata, int rlen, CacheHostResult * result)
+{
+
+  void *opaque_ptr;
+  CacheHostRecord *data_ptr;
+  bool r;
+
+  // Check to see if there is any work to do before makeing
+  //   the stirng copy
+  if (num_el <= 0) {
+    return;
+  }
+
+  if (rlen == 0)
+    return;
+  char *data = (char *) xmalloc(rlen + 1);
+  memcpy(data, rdata, rlen);
+  *(data + rlen) = '\0';
+  HostLookupState s;
+
+  r = host_lookup->MatchFirst(data, &s, &opaque_ptr);
+
+  while (r == true) {
+    ink_assert(opaque_ptr != NULL);
+    data_ptr = (CacheHostRecord *) opaque_ptr;
+    data_ptr->UpdateMatch(result, data);
+
+    r = host_lookup->MatchNext(&s, &opaque_ptr);
+  }
+  xfree(data);
+}
+
+//
+// char* CacheHostMatcher::NewEntry(bool domain_record,
+//          char* match_data, char* match_info, int line_num)
+//
+//   Creates a new host/domain record
+//
+
+void
+CacheHostMatcher::NewEntry(matcher_line * line_info)
+{
+
+  CacheHostRecord *cur_d;
+  int errNo;
+  char *match_data;
+
+  // Make sure space has been allocated
+  ink_assert(num_el >= 0);
+  ink_assert(array_len >= 0);
+
+  // Make sure we do not overrun the array;
+  ink_assert(num_el < array_len);
+
+  match_data = line_info->line[1][line_info->dest_entry];
+
+  // Make sure that the line_info is not bogus
+  ink_assert(line_info->dest_entry < MATCHER_MAX_TOKENS);
+  ink_assert(match_data != NULL);
+
+  // Remove our consumed label from the parsed line
+  if (line_info->dest_entry < MATCHER_MAX_TOKENS)
+    line_info->line[0][line_info->dest_entry] = NULL;
+  line_info->num_el--;
+
+  // Fill in the parameter info
+  cur_d = data_array + num_el;
+  errNo = cur_d->Init(line_info, type);
+
+  if (errNo) {
+    // There was a problem so undo the effects this function
+    memset(cur_d, 0, sizeof(CacheHostRecord));
+    return;
+  }
+  Debug("cache_hosting", "hostname: %s, host record: %xd", match_data, cur_d);
+  // Fill in the matching info
+  host_lookup->NewEntry(match_data, (line_info->type == MATCH_DOMAIN) ? true : false, cur_d);
+
+  num_el++;
+  return;
+}
+
+/*************************************************************
+ *   End class HostMatcher
+ *************************************************************/
+
+CacheHostTable::CacheHostTable(Cache * c, int typ)
+{
+
+
+  config_tags = &CacheHosting_tags;
+  ink_assert(config_tags != NULL);
+
+  type = typ;
+  cache = c;
+  matcher_name = "[CacheHosting]";;
+  config_file_path[0] = '\0';
+  char *config_file = NULL;
+  IOCORE_ReadConfigStringAlloc(config_file, "proxy.config.cache.hosting_filename");
+  ink_release_assert(config_file != NULL);
+  Layout::relative_to(config_file_path, sizeof(config_file_path),
+                      cache_system_config_directory, config_file);
+  xfree(config_file);
+  hostMatch = NULL;
+
+  m_numEntries = this->BuildTable();
+}
+
+CacheHostTable::~CacheHostTable()
+{
+
+  if (hostMatch != NULL) {
+    delete hostMatch;
+  }
+}
+
+// void ControlMatcher::Print()
+//
+//   Debugging method
+//
+void
+CacheHostTable::Print()
+{
+  printf("Control Matcher Table: %s\n", matcher_name);
+  if (hostMatch != NULL) {
+    hostMatch->Print();
+  }
+}
+
+
+// void ControlMatcher::Match(RD* rdata
+//                                          Result* result)
+//
+//   Queries each table for the Result*
+//
+void
+CacheHostTable::Match(char *rdata, int rlen, CacheHostResult * result)
+{
+
+  hostMatch->Match(rdata, rlen, result);
+}
+
+int
+CacheHostTable::config_callback(const char *name, RecDataT data_type, RecData data, void *cookie)
+{
+  NOWARN_UNUSED(name);
+  NOWARN_UNUSED(data);
+  NOWARN_UNUSED(data_type);
+  CacheHostTable **ppt = (CacheHostTable **) cookie;
+  eventProcessor.schedule_imm(NEW(new CacheHostTableConfig(ppt)));
+  return 0;
+}
+
+int fstat_wrapper(int fd, struct stat *s);
+
+// int ControlMatcher::BuildTable() {
+//
+//    Reads the cache.config file and build the records array
+//      from it
+//
+int
+CacheHostTable::BuildTableFromString(char *file_buf)
+{
+  // Table build locals
+  Tokenizer bufTok("\n");
+  tok_iter_state i_state;
+  const char *tmp;
+  matcher_line *first = NULL;
+  matcher_line *current;
+  matcher_line *last = NULL;
+  int line_num = 0;
+  int second_pass = 0;
+  int numEntries = 0;
+  char errBuf[1024];
+  const char *errPtr = NULL;
+
+  // type counts
+  int hostDomain = 0;
+
+  if (bufTok.Initialize(file_buf, SHARE_TOKS | ALLOW_EMPTY_TOKS) == 0) {
+    // We have an empty file
+    /* no hosting customers -- put all the volumes in the
+       generic table */
+    if (gen_host_rec.Init(type))
+      Warning("Problems encountered while initializing the Generic Volume");
+    return 0;
+  }
+  // First get the number of entries
+  tmp = bufTok.iterFirst(&i_state);
+  while (tmp != NULL) {
+
+    line_num++;
+
+    // skip all blank spaces at beginning of line
+    while (*tmp && isspace(*tmp)) {
+      tmp++;
+    }
+
+    if (*tmp != '#' && *tmp != '\0') {
+
+      current = (matcher_line *) xmalloc(sizeof(matcher_line));
+      errPtr = parseConfigLine((char *) tmp, current, config_tags);
+
+      if (errPtr != NULL) {
+        snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : %s",
+                 matcher_name, config_file_path, line_num, errPtr);
+        IOCORE_SignalError(errBuf, alarmAlready);
+        xfree(current);
+      } else {
+
+        // Line parsed ok.  Figure out what the destination
+        //  type is and link it into our list
+        numEntries++;
+        current->line_num = line_num;
+
+        switch (current->type) {
+        case MATCH_HOST:
+        case MATCH_DOMAIN:
+          hostDomain++;
+          break;
+        case MATCH_NONE:
+        default:
+          ink_assert(0);
+        }
+
+        if (first == NULL) {
+          ink_assert(last == NULL);
+          first = last = current;
+        } else {
+          last->next = current;
+          last = current;
+        }
+      }
+    }
+    tmp = bufTok.iterNext(&i_state);
+  }
+
+  // Make we have something to do before going on
+  if (numEntries == 0) {
+    /* no hosting customers -- put all the volumes in the
+       generic table */
+
+    if (gen_host_rec.Init(type)) {
+      Warning("Problems encountered while initializing the Generic Volume");
+    }
+
+    if (first != NULL) {
+      xfree(first);
+    }
+    return 0;
+  }
+
+  if (hostDomain > 0) {
+    hostMatch = NEW(new CacheHostMatcher(matcher_name, config_file_path, type));
+    hostMatch->AllocateSpace(hostDomain);
+  }
+  // Traverse the list and build the records table
+  int generic_rec_initd = 0;
+  current = first;
+  while (current != NULL) {
+    second_pass++;
+    if ((current->type == MATCH_DOMAIN) || (current->type == MATCH_HOST)) {
+
+      char *match_data = current->line[1][current->dest_entry];
+      ink_assert(match_data != NULL);
+
+      if (!strcasecmp(match_data, "*")) {
+        // generic volume - initialize the generic hostrecord */
+        // Make sure that the line_info is not bogus
+        ink_assert(current->dest_entry < MATCHER_MAX_TOKENS);
+
+        // Remove our consumed label from the parsed line
+        if (current->dest_entry < MATCHER_MAX_TOKENS)
+          current->line[0][current->dest_entry] = NULL;
+        else
+          Warning("Problems encountered while initializing the Generic Volume");
+
+        current->num_el--;
+        if (!gen_host_rec.Init(current, type))
+          generic_rec_initd = 1;
+        else
+          Warning("Problems encountered while initializing the Generic Volume");
+
+      } else {
+        hostMatch->NewEntry(current);
+      }
+    } else {
+      snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry with unknown type at line %d",
+               matcher_name, config_file_path, current->line_num);
+      IOCORE_SignalError(errBuf, alarmAlready);
+    }
+
+    // Deallocate the parsing structure
+    last = current;
+    current = current->next;
+    xfree(last);
+  }
+
+  if (!generic_rec_initd) {
+    const char *cache_type = (type == CACHE_HTTP_TYPE) ? "http" : "mixt";
+    snprintf(errBuf, sizeof(errBuf),
+             "No Volumes specified for Generic Hostnames for %s documents: %s cache will be disabled", cache_type,
+             cache_type);
+    IOCORE_SignalError(errBuf, alarmAlready);
+  }
+
+  ink_assert(second_pass == numEntries);
+
+  if (is_debug_tag_set("matcher")) {
+    Print();
+  }
+  return numEntries;
+}
+
+int
+CacheHostTable::BuildTable()
+{
+
+  // File I/O Locals
+  char *file_buf;
+  int ret;
+
+  file_buf = readIntoBuffer(config_file_path, matcher_name, NULL);
+
+  if (file_buf == NULL) {
+    Warning("Cannot read the config file: %s", config_file_path);
+    gen_host_rec.Init(type);
+    return 0;
+  }
+
+  ret = BuildTableFromString(file_buf);
+  xfree(file_buf);
+  return ret;
+}
+
+int
+CacheHostRecord::Init(int typ)
+{
+
+  int i, j;
+  extern Queue cp_list;
+  extern int cp_list_len;
+  char err[1024];
+
+  err[0] = 0;
+  num_vols = 0;
+  type = typ;
+  cp = (CacheVol **) xmalloc(cp_list_len * sizeof(CacheVol *));
+  memset(cp, 0, cp_list_len * sizeof(CacheVol *));
+  num_cachevols = 0;
+  CacheVol *cachep = cp_list.head;
+  for (; cachep; cachep = cachep->link.next) {
+    if (cachep->scheme == type) {
+      Debug("cache_hosting", "Host Record: %xd, Volume: %d, size: %u", this, cachep->vol_number, cachep->size);
+      cp[num_cachevols] = cachep;
+      num_cachevols++;
+      num_vols += cachep->num_vols;
+    }
+  }
+  if (!num_cachevols) {
+    snprintf(err, 1024, "error: No volumes found for Cache Type %d\n", type);
+    IOCORE_SignalError(err, alarmAlready);
+    return -1;
+  }
+  vols = (Vol **) xmalloc(num_vols * sizeof(Vol *));
+  int counter = 0;
+  for (i = 0; i < num_cachevols; i++) {
+    CacheVol *cachep1 = cp[i];
+    for (j = 0; j < cachep1->num_vols; j++) {
+      vols[counter++] = cachep1->vols[j];
+    }
+  }
+  ink_assert(counter == num_vols);
+
+  build_vol_hash_table(this);
+  return 0;
+}
+
+int
+CacheHostRecord::Init(matcher_line * line_info, int typ)
+{
+  int i, j;
+  extern Queue cp_list;
+  char err[1024];
+  err[0] = 0;
+  int is_vol_present = 0;
+  char config_file[PATH_NAME_MAX];
+
+  IOCORE_ReadConfigString(config_file, "proxy.config.cache.hosting_filename", PATH_NAME_MAX);
+  type = typ;
+  for (i = 0; i < MATCHER_MAX_TOKENS; i++) {
+    char *label = line_info->line[0][i];
+    if (!label)
+      continue;
+    char *val;
+
+    if (!strcasecmp(label, "volume")) {
+      /* parse the list of volumes */
+      val = xstrdup(line_info->line[1][i]);
+      char *vol_no = val;
+      char *s = val;
+      int volume_number;
+      CacheVol *cachep;
+
+      /* first find out the number of volumes */
+      while (*s) {
+        if ((*s == ',')) {
+          num_cachevols++;
+          s++;
+          if (!(*s)) {
+            const char *errptr = "A volume number expected";
+            snprintf(err, 1024,
+                         "%s discarding %s entry at line %d :%s",
+                         "[CacheHosting]", config_file, line_info->line_num, errptr);
+            IOCORE_SignalError(err, alarmAlready);
+            if (val != NULL) {
+              xfree(val);
+            }
+            return -1;
+          }
+        }
+        if ((*s<'0') || (*s> '9')) {
+          snprintf(err, 1024,
+                       "%s discarding %s entry at line %d : bad token [%c]",
+                       "[CacheHosting]", config_file, line_info->line_num, *s);
+          IOCORE_SignalError(err, alarmAlready);
+          if (val != NULL) {
+            xfree(val);
+          }
+          return -1;
+        }
+        s++;
+      }
+      s = val;
+      num_cachevols++;
+      cp = (CacheVol **) xmalloc(num_cachevols * sizeof(CacheVol *));
+      memset(cp, 0, num_cachevols * sizeof(CacheVol *));
+      num_cachevols = 0;
+      while (1) {
+        char c = *s;
+        if ((c == ',') || (c == '\0')) {
+          *s = '\0';
+          volume_number = atoi(vol_no);
+
+          cachep = cp_list.head;
+          for (; cachep; cachep = cachep->link.next) {
+            if (cachep->vol_number == volume_number) {
+              is_vol_present = 1;
+              if ((cachep->scheme == type)) {
+                Debug("cache_hosting",
+                      "Host Record: %xd, Volume: %d, size: %ld",
+                      this, volume_number, cachep->size * STORE_BLOCK_SIZE);
+                cp[num_cachevols] = cachep;
+                num_cachevols++;
+                num_vols += cachep->num_vols;
+                break;
+              }
+            }
+          }
+          if (!is_vol_present) {
+            snprintf(err, 1024,
+                         "%s discarding %s entry at line %d : bad volume number [%d]",
+                         "[CacheHosting]", config_file, line_info->line_num, volume_number);
+            IOCORE_SignalError(err, alarmAlready);
+            if (val != NULL) {
+              xfree(val);
+            }
+            return -1;
+          }
+          if (c == '\0')
+            break;
+          vol_no = s + 1;
+        }
+        s++;
+      }
+      if (val != NULL) {
+        xfree(val);
+      }
+      break;
+    }
+
+    snprintf(err, 1024,
+                 "%s discarding %s entry at line %d : bad token [%s]",
+                 "[CacheHosting]", config_file, line_info->line_num, label);
+    IOCORE_SignalError(err, alarmAlready);
+    return -1;
+  }
+
+  if (i == MATCHER_MAX_TOKENS) {
+    snprintf(err, 1024,
+                 "%s discarding %s entry at line %d : No volumes specified",
+                 "[CacheHosting]", config_file, line_info->line_num);
+    IOCORE_SignalError(err, alarmAlready);
+    return -1;
+  }
+
+  if (!num_vols) {
+    return -1;
+  }
+  vols = (Vol **) xmalloc(num_vols * sizeof(Vol *));
+  int counter = 0;
+  for (i = 0; i < num_cachevols; i++) {
+    CacheVol *cachep = cp[i];
+    for (j = 0; j < cp[i]->num_vols; j++) {
+      vols[counter++] = cachep->vols[j];
+    }
+  }
+  ink_assert(counter == num_vols);
+
+  build_vol_hash_table(this);
+  return 0;
+}
+
+void
+CacheHostRecord::UpdateMatch(CacheHostResult * r, char *rd)
+{
+  NOWARN_UNUSED(rd);
+  r->record = this;
+}
+
+void
+CacheHostRecord::Print()
+{
+}
+
+
+
+void
+ConfigVolumes::read_config_file()
+{
+
+// File I/O Locals
+  char *file_buf;
+  char config_file_path[PATH_NAME_MAX];
+  char *config_file = NULL;
+  config_file_path[0] = '\0';
+
+  IOCORE_ReadConfigStringAlloc(config_file, "proxy.config.cache.volume_filename");
+  ink_release_assert(config_file != NULL);
+  Layout::relative_to(config_file_path, sizeof(config_file_path),
+                      cache_system_config_directory, config_file);
+  xfree(config_file);
+
+  file_buf = readIntoBuffer(config_file_path, "[CacheVolition]", NULL);
+
+  if (file_buf == NULL) {
+    Warning("Cannot read the config file: %s", config_file_path);
+    return;
+  }
+
+  BuildListFromString(config_file_path, file_buf);
+  xfree(file_buf);
+  return;
+}
+
+void
+ConfigVolumes::BuildListFromString(char *config_file_path, char *file_buf)
+{
+
+#define PAIR_ZERO 0
+#define PAIR_ONE 1
+#define PAIR_TWO 2
+#define DONE 3
+#define INK_ERROR -1
+
+#define INK_ERROR_VOLUME -2  //added by YTS Team, yamsat for bug id 59632
+// Table build locals
+  Tokenizer bufTok("\n");
+  tok_iter_state i_state;
+  const char *tmp;
+  char *end;
+  char *line_end = NULL;
+  int line_num = 0;
+  int total = 0;                //added by YTS Team, yamsat for bug id 59632
+  char errBuf[1024];
+
+  char volume_seen[256];
+  int state = 0;                //changed by YTS Team, yamsat for bug id 59632
+  int manager_alarmed = false;
+  int volume_number = 0;
+  int scheme = CACHE_NONE_TYPE;
+  int size = 0;
+  int in_percent = 0;
+  const char *matcher_name = "[CacheVolition]";
+
+  memset(volume_seen, 0, sizeof(volume_seen));
+  num_volumes = 0;
+  num_stream_volumes = 0;
+  num_http_volumes = 0;
+
+  if (bufTok.Initialize(file_buf, SHARE_TOKS | ALLOW_EMPTY_TOKS) == 0) {
+    // We have an empty file
+    /* no volumes */
+    return;
+  }
+  // First get the number of entries
+  tmp = bufTok.iterFirst(&i_state);
+  while (tmp != NULL) {
+    state = PAIR_ZERO;
+    line_num++;
+
+    // skip all blank spaces at beginning of line
+    while (1) {
+      while (*tmp && isspace(*tmp)) {
+        tmp++;
+      }
+
+      if (!(*tmp) && state == DONE) {
+        /* add the config */
+
+        ConfigVol *configp = NEW(new ConfigVol());
+        configp->number = volume_number;
+        if (in_percent) {
+          configp->percent = size;
+          configp->in_percent = 1;
+        } else {
+          configp->in_percent = 0;
+        }
+        configp->scheme = scheme;
+        configp->size = size;
+        configp->cachep = NULL;
+        cp_queue.enqueue(configp);
+        num_volumes++;
+        if (scheme == CACHE_HTTP_TYPE)
+          num_http_volumes++;
+        else
+          num_stream_volumes++;
+        Debug("cache_hosting",
+              "added volume=%d, scheme=%d, size=%d percent=%d\n", volume_number, scheme, size, in_percent);
+        break;
+      }
+
+      if (state == PAIR_ZERO) {
+        if (*tmp == '\0' || *tmp == '#')
+          break;
+      } else {
+        if (!(*tmp)) {
+          snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : Unexpected end of line",
+                   matcher_name, config_file_path, line_num);
+          IOCORE_SignalError(errBuf, manager_alarmed);
+
+          break;
+        }
+      }
+
+      end = (char *) tmp;
+      while (*end && !isspace(*end))
+        end++;
+
+      if (!(*end))
+        line_end = end;
+      else {
+        line_end = end + 1;
+        *end = '\0';
+      }
+      char *eq_sign;
+
+      eq_sign = (char *) strchr(tmp, '=');
+      if (!eq_sign) {
+        state = INK_ERROR;
+      } else
+        *eq_sign = '\0';
+
+      switch (state) {
+      case PAIR_ZERO:
+        if (strcasecmp(tmp, "volume")) {
+          state = INK_ERROR;
+          break;
+        }
+        tmp += 7;              //size of string volume including null
+        volume_number = atoi(tmp);
+
+        if (volume_number<1 || volume_number> 255 || volume_seen[volume_number]) {
+          const char *err;
+
+          if (volume_number<1 || volume_number> 255) {
+            err = "Bad Volume Number";
+          } else {
+            err = "Volume Already Specified";
+          }
+
+          snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : %s [%d]",
+                   matcher_name, config_file_path, line_num, err, volume_number);
+          IOCORE_SignalError(errBuf, manager_alarmed);
+          state = INK_ERROR;
+          break;
+        }
+
+        volume_seen[volume_number] = 1;
+        while (ParseRules::is_digit(*tmp))
+          tmp++;
+        state = PAIR_ONE;
+        break;
+
+      case PAIR_ONE:
+        if (strcasecmp(tmp, "scheme")) {
+          state = INK_ERROR;
+          break;
+        }
+        tmp += 7;               //size of string scheme including null
+
+        if (!strcasecmp(tmp, "http")) {
+          tmp += 4;
+          scheme = CACHE_HTTP_TYPE;
+        } else if (!strcasecmp(tmp, "mixt")) {
+          tmp += 4;
+          scheme = CACHE_RTSP_TYPE;
+        } else {
+          state = INK_ERROR;
+          break;
+        }
+
+        state = PAIR_TWO;
+        break;
+
+      case PAIR_TWO:
+
+        if (strcasecmp(tmp, "size")) {
+          state = INK_ERROR;
+          break;
+        }
+        tmp += 5;
+        size = atoi(tmp);
+
+        while (ParseRules::is_digit(*tmp))
+          tmp++;
+
+        if (*tmp == '%') {
+          //added by YTS Team, yamsat for bug id 59632
+          total += size;
+          if (size > 100 || total > 100) {
+            state = INK_ERROR_VOLUME;
+            if (state == INK_ERROR_VOLUME || *tmp) {
+              snprintf(errBuf, sizeof(errBuf),
+                       "Total volume size added upto more than 100 percent,No volumes created");
+              IOCORE_SignalError(errBuf, manager_alarmed);
+              break;
+            }
+          }
+          //ends here
+          in_percent = 1;
+          tmp++;
+        } else
+          in_percent = 0;
+        state = DONE;
+        break;
+
+      }
+
+      if (state == INK_ERROR || *tmp) {
+        snprintf(errBuf, sizeof(errBuf), "%s discarding %s entry at line %d : Invalid token [%s]",
+                 matcher_name, config_file_path, line_num, tmp);
+        IOCORE_SignalError(errBuf, manager_alarmed);
+
+        break;
+      }
+      //added by YTS Team, yamsat for bug id 59632
+      if (state == INK_ERROR_VOLUME || *tmp) {
+        snprintf(errBuf, sizeof(errBuf), "Total volume size added upto more than 100 percent,No volumes created");
+        IOCORE_SignalError(errBuf, manager_alarmed);
+        break;
+      }
+      // ends here
+      if (end < line_end)
+        tmp++;
+    }
+    tmp = bufTok.iterNext(&i_state);
+  }
+
+  return;
+}
+
+
+
+/* Test the cache volumeing with different configurations */
+#define MEGS_128 (128 * 1024 * 1024)
+#define ROUND_TO_VOL_SIZE(_x) (((_x) + (MEGS_128 - 1)) &~ (MEGS_128 - 1))
+extern CacheDisk **gdisks;
+extern Queue cp_list;
+extern int cp_list_len;
+extern ConfigVolumes config_volumes;
+extern volatile int gnvol;
+
+extern void cplist_init();
+extern int cplist_reconfigure();
+static int configs = 4;
+
+Queue saved_cp_list;
+int saved_cp_list_len;
+ConfigVolumes saved_config_volumes;
+int saved_gnvol;
+
+int ClearConfigVol(ConfigVolumes * configp);
+int ClearCacheVolList(Queue *cpl, int len);
+int create_config(RegressionTest * t, int i);
+int execute_and_verify(RegressionTest * t);
+void save_state();
+void restore_state();
+
+EXCLUSIVE_REGRESSION_TEST(Cache_vol) (RegressionTest * t, int atype, int *status) {
+  NOWARN_UNUSED(atype);
+  save_state();
+  srand48(time(NULL));
+  *status = REGRESSION_TEST_PASSED;
+  for (int i = 0; i < configs; i++) {
+    if (create_config(t, i)) {
+      if (execute_and_verify(t) == REGRESSION_TEST_FAILED) {
+        *status = REGRESSION_TEST_FAILED;
+      }
+    }
+  }
+  restore_state();
+  return;
+}
+
+int
+create_config(RegressionTest * t, int num)
+{
+  int i = 0;
+  int vol_num = 1;
+  // clear all old configurations before adding new test cases
+  config_volumes.clear_all();
+  switch (num) {
+  case 0:
+    for (i = 0; i < gndisks; i++) {
+      CacheDisk *d = gdisks[i];
+      int blocks = d->num_usable_blocks;
+      if (blocks < STORE_BLOCKS_PER_VOL) {
+        rprintf(t, "Cannot run Cache_vol regression: not enough disk space\n");
+        return 0;
+      }
+      /* create 128 MB volumes */
+      for (; blocks >= STORE_BLOCKS_PER_VOL; blocks -= STORE_BLOCKS_PER_VOL) {
+        if (vol_num > 255)
+          break;
+        ConfigVol *cp = NEW(new ConfigVol());
+        cp->number = vol_num++;
+        cp->scheme = CACHE_HTTP_TYPE;
+        cp->size = 128;
+        cp->in_percent = 0;
+        cp->cachep = 0;
+        config_volumes.cp_queue.enqueue(cp);
+        config_volumes.num_volumes++;
+        config_volumes.num_http_volumes++;
+      }
+
+    }
+    rprintf(t, "%d 128 Megabyte Volumes\n", vol_num - 1);
+    break;
+
+  case 1:
+    {
+      for (i = 0; i < gndisks; i++) {
+        gdisks[i]->delete_all_volumes();
+      }
+
+      // calculate the total free space
+      off_t total_space = 0;
+      for (i = 0; i < gndisks; i++) {
+        off_t vol_blocks = gdisks[i]->num_usable_blocks;
+        /* round down the blocks to the nearest
+           multiple of STORE_BLOCKS_PER_VOL */
+        vol_blocks = (vol_blocks / STORE_BLOCKS_PER_VOL)
+          * STORE_BLOCKS_PER_VOL;
+        total_space += vol_blocks;
+      }
+
+      // make sure we have atleast 1280 M bytes
+      if (total_space<(10 << 27)>> STORE_BLOCK_SHIFT) {
+        rprintf(t, "Not enough space for 10 volume\n");
+        return 0;
+      }
+
+      vol_num = 1;
+      rprintf(t, "Cleared  disk\n");
+      for (i = 0; i < 10; i++) {
+        ConfigVol *cp = NEW(new ConfigVol());
+        cp->number = vol_num++;
+        cp->scheme = CACHE_HTTP_TYPE;
+        cp->size = 10;
+        cp->percent = 10;
+        cp->in_percent = 1;
+        cp->cachep = 0;
+        config_volumes.cp_queue.enqueue(cp);
+        config_volumes.num_volumes++;
+        config_volumes.num_http_volumes++;
+      }
+      rprintf(t, "10 volume, 10 percent each\n");
+    }
+    break;
+
+  case 2:
+  case 3:
+
+    {
+      /* calculate the total disk space */
+      InkRand *gen = &this_ethread()->generator;
+      off_t total_space = 0;
+      vol_num = 1;
+      if (num == 2) {
+        rprintf(t, "Random Volumes after clearing the disks\n");
+      } else {
+        rprintf(t, "Random Volumes without clearing the disks\n");
+      }
+
+      for (i = 0; i < gndisks; i++) {
+        off_t vol_blocks = gdisks[i]->num_usable_blocks;
+        /* round down the blocks to the nearest
+           multiple of STORE_BLOCKS_PER_VOL */
+        vol_blocks = (vol_blocks / STORE_BLOCKS_PER_VOL)
+          * STORE_BLOCKS_PER_VOL;
+        total_space += vol_blocks;
+
+        if (num == 2) {
+          gdisks[i]->delete_all_volumes();
+        } else {
+          gdisks[i]->cleared = 0;
+        }
+      }
+      while (total_space > 0) {
+        if (vol_num > 255)
+          break;
+        off_t modu = MAX_VOL_SIZE;
+        if (total_space<(MAX_VOL_SIZE>> STORE_BLOCK_SHIFT)) {
+          modu = total_space * STORE_BLOCK_SIZE;
+        }
+
+        off_t random_size = (gen->random() % modu) + 1;
+        /* convert to 128 megs multiple */
+        int scheme = (random_size % 2) ? CACHE_HTTP_TYPE : CACHE_RTSP_TYPE;
+        random_size = ROUND_TO_VOL_SIZE(random_size);
+        off_t blocks = random_size / STORE_BLOCK_SIZE;
+        ink_assert(blocks <= (int) total_space);
+        total_space -= blocks;
+
+        ConfigVol *cp = NEW(new ConfigVol());
+
+        cp->number = vol_num++;
+        cp->scheme = scheme;
+        cp->size = random_size >> 20;
+        cp->percent = 0;
+        cp->in_percent = 0;
+        cp->cachep = 0;
+        config_volumes.cp_queue.enqueue(cp);
+        config_volumes.num_volumes++;
+        if (cp->scheme == CACHE_HTTP_TYPE) {
+          config_volumes.num_http_volumes++;
+          rprintf(t, "volume=%d scheme=http size=%d\n", cp->number, cp->size);
+        } else {
+          config_volumes.num_stream_volumes++;
+          rprintf(t, "volume=%d scheme=rtsp size=%d\n", cp->number, cp->size);
+
+        }
+      }
+    }
+    break;
+
+  default:
+    return 1;
+  }
+  return 1;
+}
+
+int
+execute_and_verify(RegressionTest * t)
+{
+  cplist_init();
+  cplist_reconfigure();
+
+  /* compare the volumes */
+  if (cp_list_len != config_volumes.num_volumes)
+    return REGRESSION_TEST_FAILED;
+
+  /* check that the volumes and sizes
+     match the configuration */
+  int matched = 0;
+  ConfigVol *cp = config_volumes.cp_queue.head;
+  CacheVol *cachep;
+
+  for (int i = 0; i < config_volumes.num_volumes; i++) {
+    cachep = cp_list.head;
+    while (cachep) {
+      if (cachep->vol_number == cp->number) {
+        if ((cachep->scheme != cp->scheme) ||
+            (cachep->size != (cp->size << (20 - STORE_BLOCK_SHIFT))) || (cachep != cp->cachep)) {
+          rprintf(t, "Configuration and Actual volumes don't match\n");
+          return REGRESSION_TEST_FAILED;
+        }
+
+        /* check that the number of volumes match the ones
+           on disk */
+        int d_no;
+        int m_vols = 0;
+        for (d_no = 0; d_no < gndisks; d_no++) {
+          if (cachep->disk_vols[d_no]) {
+            DiskVol *dp = cachep->disk_vols[d_no];
+            if (dp->vol_number != cachep->vol_number) {
+              rprintf(t, "DiskVols and CacheVols don't match\n");
+              return REGRESSION_TEST_FAILED;
+            }
+
+            /* check the diskvolblock queue */
+            DiskVolBlockQueue *dpbq = dp->dpb_queue.head;
+            while (dpbq) {
+              if (dpbq->b->number != cachep->vol_number) {
+                rprintf(t, "DiskVol and DiskVolBlocks don't match\n");
+                return REGRESSION_TEST_FAILED;
+              }
+              dpbq = dpbq->link.next;
+            }
+
+            m_vols += dp->num_volblocks;
+          }
+        }
+        if (m_vols != cachep->num_vols) {
+          rprintf(t, "Num volumes in CacheVol and DiskVol don't match\n");
+          return REGRESSION_TEST_FAILED;
+        }
+        matched++;
+        break;
+      }
+      cachep = cachep->link.next;
+    }
+  }
+
+  if (matched != config_volumes.num_volumes) {
+    rprintf(t, "Num of Volumes created and configured don't match\n");
+    return REGRESSION_TEST_FAILED;
+  }
+
+  ClearConfigVol(&config_volumes);
+
+  ClearCacheVolList(&cp_list, cp_list_len);
+
+  for (int i = 0; i < gndisks; i++) {
+    CacheDisk *d = gdisks[i];
+    if (is_debug_tag_set("cache_hosting")) {
+
+      Debug("cache_hosting", "Disk: %d: Vol Blocks: %ld: Free space: %ld",
+            i, d->header->num_diskvol_blks, d->free_space);
+      for (int j = 0; j < (int) d->header->num_volumes; j++) {
+
+        Debug("cache_hosting", "\tVol: %d Size: %d", d->disk_vols[j]->vol_number, d->disk_vols[j]->size);
+      }
+      for (int j = 0; j < (int) d->header->num_diskvol_blks; j++) {
+        Debug("cache_hosting", "\tBlock No: %d Size: %d Free: %d",
+              d->header->vol_info[j].number, d->header->vol_info[j].len, d->header->vol_info[j].free);
+      }
+    }
+  }
+  return REGRESSION_TEST_PASSED;
+}
+
+int
+ClearConfigVol(ConfigVolumes * configp)
+{
+
+  int i = 0;
+  ConfigVol *cp = NULL;
+  while ((cp = configp->cp_queue.dequeue())) {
+    delete cp;
+    i++;
+  }
+  if (i != configp->num_volumes) {
+    Warning("failed");
+    return 0;
+  }
+  configp->num_volumes = 0;
+  configp->num_http_volumes = 0;
+  configp->num_stream_volumes = 0;
+  return 1;
+}
+
+int
+ClearCacheVolList(Queue *cpl, int len)
+{
+
+  int i = 0;
+  CacheVol *cp = NULL;
+  while ((cp = cpl->dequeue())) {
+    if (cp->disk_vols)
+      xfree(cp->disk_vols);
+    if (cp->vols)
+      xfree(cp->vols);
+    delete(cp);
+    i++;
+  }
+
+  if (i != len) {
+    Warning("Failed");
+    return 0;
+  }
+  return 1;
+}
+
+
+void
+save_state()
+{
+  saved_cp_list = cp_list;
+  saved_cp_list_len = cp_list_len;
+  memcpy(&saved_config_volumes, &config_volumes, sizeof(ConfigVolumes));
+  saved_gnvol = gnvol;
+  memset(&cp_list, 0, sizeof(Queue));
+  memset(&config_volumes, 0, sizeof(ConfigVolumes));
+  gnvol = 0;
+}
+
+void
+restore_state()
+{
+  cp_list = saved_cp_list;
+  cp_list_len = saved_cp_list_len;
+  memcpy(&config_volumes, &saved_config_volumes, sizeof(ConfigVolumes));
+  gnvol = saved_gnvol;
+}
diff --git a/iocore/cache/CacheHttp.cc b/iocore/cache/CacheHttp.cc
new file mode 100644
index 00000000..36db36a5
--- /dev/null
+++ b/iocore/cache/CacheHttp.cc
@@ -0,0 +1,355 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "ink_config.h"
+#include 
+#include "P_Cache.h"
+
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+static vec_info default_vec_info;
+
+#ifdef HTTP_CACHE
+static CacheHTTPInfo default_http_info;
+
+CacheHTTPInfoVector::CacheHTTPInfoVector()
+:magic(NULL), data(&default_vec_info, 4), xcount(0)
+{
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+CacheHTTPInfoVector::~CacheHTTPInfoVector()
+{
+  int i;
+
+  for (i = 0; i < xcount; i++) {
+    data[i].alternate.destroy();
+  }
+  vector_buf.clear();
+  magic = NULL;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+int
+CacheHTTPInfoVector::insert(CacheHTTPInfo * info, int index)
+{
+  if (index == CACHE_ALT_INDEX_DEFAULT)
+    index = xcount++;
+
+  data(index).alternate.copy_shallow(info);
+  return index;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+
+void
+CacheHTTPInfoVector::detach(int idx, CacheHTTPInfo * r)
+{
+  int i;
+
+  ink_assert(idx >= 0);
+  ink_assert(idx < xcount);
+
+  r->copy_shallow(&data[idx].alternate);
+  data[idx].alternate.destroy();
+
+  for (i = idx; i < (xcount - 1); i++) {
+    data[i] = data[i + i];
+  }
+
+  xcount -= 1;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+void
+CacheHTTPInfoVector::remove(int idx, bool destroy)
+{
+  if (destroy)
+    data[idx].alternate.destroy();
+
+  for (; idx < (xcount - 1); idx++)
+    data[idx] = data[idx + 1];
+
+  xcount--;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+void
+CacheHTTPInfoVector::clear(bool destroy)
+{
+  int i;
+
+  if (destroy) {
+    for (i = 0; i < xcount; i++) {
+      data[i].alternate.destroy();
+    }
+  }
+  xcount = 0;
+  data.clear();
+  vector_buf.clear();
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+void
+CacheHTTPInfoVector::print(char *buffer, size_t buf_size, bool temps)
+{
+  char buf[33], *p;
+  int purl;
+  int i, tmp;
+
+  p = buffer;
+  purl = 1;
+
+  for (i = 0; i < xcount; i++) {
+    if (data[i].alternate.valid()) {
+      if (purl) {
+        Arena arena;
+        char *url;
+
+        purl = 0;
+        URL u;
+        data[i].alternate.request_url_get(&u);
+        url = u.string_get(&arena);
+        if (url) {
+          snprintf(p, buf_size, "[%s] ", url);
+          tmp = strlen(p);
+          p += tmp;
+          buf_size -= tmp;
+        }
+      }
+
+      if (temps || !(data[i].alternate.object_key_get() == zero_key)) {
+        snprintf(p, buf_size, "[%d %s]", data[i].alternate.id_get(),
+                     CacheKey(data[i].alternate.object_key_get()).string(buf));
+        tmp = strlen(p);
+        p += tmp;
+        buf_size -= tmp;
+      }
+    }
+  }
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+int
+CacheHTTPInfoVector::marshal_length()
+{
+  int length = 0;
+
+  for (int i = 0; i < xcount; i++) {
+    length += data[i].alternate.marshal_length();
+  }
+
+  return length;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+int
+CacheHTTPInfoVector::marshal(char *buf, int length)
+{
+  char *start = buf;
+  int count = 0;
+
+  ink_assert(!(((intptr_t) buf) & 3));      // buf must be aligned
+
+  for (int i = 0; i < xcount; i++) {
+    int tmp = data[i].alternate.marshal(buf, length);
+    length -= tmp;
+    buf += tmp;
+    count++;
+  }
+
+  GLOBAL_CACHE_SUM_GLOBAL_DYN_STAT(cache_hdr_vector_marshal_stat, 1);
+  GLOBAL_CACHE_SUM_GLOBAL_DYN_STAT(cache_hdr_marshal_stat, count);
+  GLOBAL_CACHE_SUM_GLOBAL_DYN_STAT(cache_hdr_marshal_bytes_stat, buf - start);
+  return buf - start;
+}
+
+int
+CacheHTTPInfoVector::unmarshal(const char *buf, int length, RefCountObj * block_ptr)
+{
+  ink_assert(!(((intptr_t) buf) & 3));      // buf must be aligned
+
+  const char *start = buf;
+  CacheHTTPInfo info;
+  xcount = 0;
+
+  while (length - (buf - start) > (int) sizeof(HTTPCacheAlt)) {
+
+    int tmp = HTTPInfo::unmarshal((char *) buf, length - (buf - start), block_ptr);
+    if (tmp < 0) {
+      return -1;
+    }
+    info.m_alt = (HTTPCacheAlt *) buf;
+    buf += tmp;
+
+    data(xcount).alternate = info;
+    xcount++;
+  }
+
+  return ((caddr_t) buf - (caddr_t) start);
+}
+
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+uint32_t
+CacheHTTPInfoVector::get_handles(const char *buf, int length, RefCountObj * block_ptr)
+{
+  ink_assert(!(((intptr_t) buf) & 3));      // buf must be aligned
+
+  const char *start = buf;
+  CacheHTTPInfo info;
+  xcount = 0;
+
+  vector_buf = block_ptr;
+
+  while (length - (buf - start) > (int) sizeof(HTTPCacheAlt)) {
+
+    int tmp = info.get_handle((char *) buf, length - (buf - start));
+    if (tmp < 0) {
+      ink_assert(!"CacheHTTPInfoVector::unmarshal get_handle() failed");
+      return (uint32_t) -1;
+    }
+    buf += tmp;
+
+    data(xcount).alternate = info;
+    xcount++;
+  }
+
+  return ((caddr_t) buf - (caddr_t) start);
+}
+
+#else //HTTP_CACHE
+
+CacheHTTPInfoVector::CacheHTTPInfoVector()
+:data(&default_vec_info, 4), xcount(0)
+{
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+CacheHTTPInfoVector::~CacheHTTPInfoVector()
+{
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+int
+CacheHTTPInfoVector::insert(CacheHTTPInfo * info, int index)
+{
+  ink_assert(0);
+  return index;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+
+void
+CacheHTTPInfoVector::detach(int idx, CacheHTTPInfo * r)
+{
+  ink_assert(0);
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+void
+CacheHTTPInfoVector::remove(int idx, bool destroy)
+{
+  ink_assert(0);
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+void
+CacheHTTPInfoVector::clear(bool destroy)
+{
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+void
+CacheHTTPInfoVector::print(char *buffer, size_t buf_size, bool temps)
+{
+  ink_assert(0);
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+int
+CacheHTTPInfoVector::marshal_length()
+{
+  ink_assert(0);
+  return 0;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+int
+CacheHTTPInfoVector::marshal(char *buf, int length)
+{
+  ink_assert(0);
+  return length;
+}
+
+int
+CacheHTTPInfoVector::unmarshal(const char *buf, int length, RefCountObj * block_ptr)
+{
+  ink_assert(0);
+  return 0;
+}
+
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+uint32_t
+CacheHTTPInfoVector::get_handles(const char *buf, int length, RefCountObj * block_ptr)
+{
+  ink_assert(0);
+  return 0;
+}
+
+#endif //HTTP_CACHE
diff --git a/iocore/cache/CacheLink.cc b/iocore/cache/CacheLink.cc
new file mode 100644
index 00000000..b36df91a
--- /dev/null
+++ b/iocore/cache/CacheLink.cc
@@ -0,0 +1,170 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "P_Cache.h"
+
+Action *
+Cache::link(Continuation * cont, CacheKey * from, CacheKey * to, CacheFragType type, char *hostname, int host_len)
+{
+
+  if (!CACHE_READY(type)) {
+    cont->handleEvent(CACHE_EVENT_LINK_FAILED, 0);
+    return ACTION_RESULT_DONE;
+  }
+
+  ink_assert(caches[type] == this);
+
+  CacheVC *c = new_CacheVC(cont);
+  c->vol = key_to_vol(from, hostname, host_len);
+  c->write_len = sizeof(*to);   // so that the earliest_key will be used
+  c->f.use_first_key = 1;
+  c->first_key = *from;
+  c->earliest_key = *to;
+
+  c->buf = new_IOBufferData(BUFFER_SIZE_INDEX_512);
+#ifdef DEBUG
+  Doc *doc = (Doc *) c->buf->data();
+  memcpy(doc->data(), to, sizeof(*to)); // doublecheck
+#endif
+
+  SET_CONTINUATION_HANDLER(c, &CacheVC::linkWrite);
+
+  if (c->do_write_lock() == EVENT_DONE)
+    return ACTION_RESULT_DONE;
+  else
+    return &c->_action;
+}
+
+int
+CacheVC::linkWrite(int event, Event * e)
+{
+  NOWARN_UNUSED(e);
+  NOWARN_UNUSED(event);
+  ink_assert(event == AIO_EVENT_DONE);
+  set_io_not_in_progress();
+  dir_insert(&first_key, vol, &dir);
+  if (_action.cancelled)
+    goto Ldone;
+  if (io.ok())
+    _action.continuation->handleEvent(CACHE_EVENT_LINK, NULL);
+  else
+    _action.continuation->handleEvent(CACHE_EVENT_LINK_FAILED, NULL);
+Ldone:
+  return free_CacheVC(this);
+}
+
+Action *
+Cache::deref(Continuation * cont, CacheKey * key, CacheFragType type, char *hostname, int host_len)
+{
+
+  if (!CACHE_READY(type)) {
+    cont->handleEvent(CACHE_EVENT_DEREF_FAILED, 0);
+    return ACTION_RESULT_DONE;
+  }
+
+  ink_assert(caches[type] == this);
+
+  Vol *vol = key_to_vol(key, hostname, host_len);
+  Dir result;
+  Dir *last_collision = NULL;
+  CacheVC *c = NULL;
+  {
+    MUTEX_TRY_LOCK(lock, vol->mutex, cont->mutex->thread_holding);
+    if (lock) {
+      if (!dir_probe(key, vol, &result, &last_collision)) {
+        cont->handleEvent(CACHE_EVENT_DEREF_FAILED, (void *) -ECACHE_NO_DOC);
+        return ACTION_RESULT_DONE;
+      }
+    }
+    c = new_CacheVC(cont);
+    SET_CONTINUATION_HANDLER(c, &CacheVC::derefRead);
+    c->first_key = c->key = *key;
+    c->vol = vol;
+    c->dir = result;
+    c->last_collision = last_collision;
+
+    if (!lock) {
+      c->mutex->thread_holding->schedule_in_local(c, HRTIME_MSECONDS(cache_config_mutex_retry_delay));
+      return &c->_action;
+    }
+
+    switch (c->do_read_call(&c->key)) {
+      case EVENT_DONE: return ACTION_RESULT_DONE;
+      case EVENT_RETURN: goto Lcallreturn;
+      default: return &c->_action;
+    }
+  }
+Lcallreturn:
+  if (c->handleEvent(AIO_EVENT_DONE, 0) == EVENT_DONE)
+    return ACTION_RESULT_DONE;
+  else
+    return &c->_action;
+}
+
+int
+CacheVC::derefRead(int event, Event * e)
+{
+  NOWARN_UNUSED(e);
+  NOWARN_UNUSED(event);
+  Doc *doc = NULL;
+
+  cancel_trigger();
+  set_io_not_in_progress();
+  if (_action.cancelled)
+    return free_CacheVC(this);
+  if (!buf)
+    goto Lcollision;
+  if ((int) io.aio_result != (int) io.aiocb.aio_nbytes)
+    goto Ldone;
+  if (!dir_agg_valid(vol, &dir)) {
+    last_collision = NULL;
+    goto Lcollision;
+  }
+  doc = (Doc *) buf->data();
+  if (!(doc->first_key == key))
+    goto Lcollision;
+#ifdef DEBUG
+  ink_debug_assert(!memcmp(doc->data(), &doc->key, sizeof(doc->key)));
+#endif
+  _action.continuation->handleEvent(CACHE_EVENT_DEREF, (void *) &doc->key);
+  return free_CacheVC(this);
+
+Lcollision:{
+    CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding);
+    if (!lock) {
+      mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay));
+      return EVENT_CONT;
+    }
+    if (dir_probe(&key, vol, &dir, &last_collision)) {
+      int ret = do_read_call(&first_key);
+      if (ret == EVENT_RETURN)
+        goto Lcallreturn;
+      return ret;
+    }
+  }
+Ldone:
+  _action.continuation->handleEvent(CACHE_EVENT_DEREF_FAILED, (void *) -ECACHE_NO_DOC);
+  return free_CacheVC(this);
+Lcallreturn:
+  return handleEvent(AIO_EVENT_DONE, 0); // hopefully a tail call
+}
diff --git a/iocore/cache/CachePages.cc b/iocore/cache/CachePages.cc
new file mode 100644
index 00000000..16bfb709
--- /dev/null
+++ b/iocore/cache/CachePages.cc
@@ -0,0 +1,629 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "P_Cache.h"
+
+#ifdef NON_MODULAR
+#include "api/ts/ts.h"
+#include "Show.h"
+#include "I_Tasks.h"
+
+struct ShowCache: public ShowCont {
+  int vol_index;
+  int seg_index;
+  int scan_flag;
+  int urlstrs_index;
+  int linecount;
+  char (*show_cache_urlstrs)[500];
+  URL url;
+  CacheKey show_cache_key;
+  CacheVC *cache_vc;
+  MIOBuffer *buffer;
+  IOBufferReader *buffer_reader;
+  int64_t content_length;
+  VIO *cvio;
+  int showMain(int event, Event *e);
+  int lookup_url_form(int event, Event *e);
+  int delete_url_form(int event, Event *e);
+  int lookup_regex_form(int event, Event *e);
+  int delete_regex_form(int event, Event *e);
+  int invalidate_regex_form(int event, Event *e);
+
+  int lookup_url(int event, Event *e);
+  int delete_url(int event, Event *e);
+  int lookup_regex(int event, Event *e);
+  int delete_regex(int event, Event *e);
+  int invalidate_regex(int event, Event *e);
+
+  int handleCacheEvent(int event, Event *e);
+  int handleCacheDeleteComplete(int event, Event *e);
+  int handleCacheScanCallback(int event, Event *e);
+
+  ShowCache(Continuation *c, HTTPHdr *h): 
+    ShowCont(c, h), vol_index(0), seg_index(0), scan_flag(0),
+    cache_vc(0), buffer(0), buffer_reader(0), content_length(0), cvio(0)
+  {
+    urlstrs_index = 0;
+    linecount = 0;
+    int query_len;
+    char query[4096];
+    char unescapedQuery[4096];
+    show_cache_urlstrs = NULL;
+    URL *u = h->url_get();
+
+    // process the query string
+    if (u->query_get(&query_len)) {
+      strncpy(query, u->query_get(&query_len), query_len);
+      query[query_len] = '\0';
+      strncpy(unescapedQuery, query, query_len);
+      unescapedQuery[query_len] = '\0';
+
+      query_len = unescapifyStr(query);
+
+      Debug("cache_inspector", "query params: %s [unescaped]", unescapedQuery);
+      Debug("cache_inspector", "query params: %s [escaped]", query);
+      // remove 'C-m' s
+      int l, m;
+      for (l = 0, m = 0; l < query_len; l++)
+        if (query[l] != '\015')
+            query[m++] = query[l];
+        query[m] = '\0';
+
+      int nstrings = 1;
+      char *p = strstr(query, "url=");
+      // count the no of urls
+      if (p) {
+        while ((p = strstr(p, "\n"))) {
+          nstrings++;
+          if ((size_t) (p - query) >= strlen(query) - 1)
+            break;
+          else
+            p++;
+        }
+      }
+      // initialize url array
+      show_cache_urlstrs = NEW(new char[nstrings + 1][500]);
+      for (int si = 0; si < nstrings + 1; si++)
+        for (int sj = 0; sj < 500; sj++)
+          show_cache_urlstrs[si][sj] = '\0';    // zeroing out mem
+
+      char *q, *t;
+      p = strstr(unescapedQuery, "url=");
+      if (p) {
+        p += 4;                 // 4 ==> strlen("url=")
+        t = strchr(p, '&');
+        if (!t)
+          t = (char *) unescapedQuery + strlen(unescapedQuery);
+        for (int s = 0; p < t; s++) {
+          show_cache_urlstrs[s][0] = '\0';
+          q = strstr(p, "%0D%0A");      // we used this in the JS to separate urls
+          if (!q)
+            q = t;
+          strncpy(show_cache_urlstrs[s], p, q - p);
+          show_cache_urlstrs[s][q - p] = '\0';
+          p = q + 6;            // +6 ==> strlen(%0D%0A)
+        }
+      }
+
+      Debug("cache_inspector", "there were %d url(s) passed in", nstrings == 1 ? 1 : nstrings - 1);
+
+      for (int i = 0; i < nstrings; i++) {
+        if (show_cache_urlstrs[i][0] == '\0')
+          continue;
+        unescapifyStr(show_cache_urlstrs[i]);
+        Debug("cache_inspector", "URL %d: %s", i + 1, &show_cache_urlstrs[i]);
+      }
+
+    }
+
+    SET_HANDLER(&ShowCache::showMain);
+  }
+
+  ~ShowCache() {
+    if (show_cache_urlstrs)
+      delete[]show_cache_urlstrs;
+    url.destroy();
+  }
+
+};
+
+extern ShowCache *theshowcache;
+
+// Stat Pages
+ShowCache *theshowcache = NULL;
+
+#define STREQ_PREFIX(_x,_s) (!strncasecmp(_x,_s,sizeof(_s)-1))
+#define STREQ_LEN_PREFIX(_x,_l,_s) (path_len < sizeof(_s) && !strncasecmp(_x,_s,sizeof(_s)-1))
+
+
+Action *
+register_ShowCache(Continuation *c, HTTPHdr *h) {
+  theshowcache = NEW(new ShowCache(c, h));
+  URL *u = h->url_get();
+  int path_len;
+  const char *path = u->path_get(&path_len);
+
+  if (!path) {
+  } else if (STREQ_PREFIX(path, "lookup_url_form")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_url_form);
+  } else if (STREQ_PREFIX(path, "delete_url_form")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_url_form);
+  } else if (STREQ_PREFIX(path, "lookup_regex_form")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_regex_form);
+  } else if (STREQ_PREFIX(path, "delete_regex_form")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_regex_form);
+  } else if (STREQ_PREFIX(path, "invalidate_regex_form")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::invalidate_regex_form);
+  }
+
+  else if (STREQ_PREFIX(path, "lookup_url")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_url);
+  } else if (STREQ_PREFIX(path, "delete_url")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_url);
+  } else if (STREQ_PREFIX(path, "lookup_regex")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_regex);
+  } else if (STREQ_PREFIX(path, "delete_regex")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_regex);
+  } else if (STREQ_PREFIX(path, "invalidate_regex")) {
+    SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::invalidate_regex);
+  }
+
+  if (theshowcache->mutex->thread_holding)
+    CONT_SCHED_LOCK_RETRY(theshowcache);
+  else
+    eventProcessor.schedule_imm(theshowcache, ET_TASK);
+  return &theshowcache->action;
+}
+
+int
+ShowCache::showMain(int event, Event *e) {
+  CHECK_SHOW(begin("Cache"));
+  CHECK_SHOW(show("

Lookup url

\n" + "

Delete url

\n" + "

Regex lookup

\n" + "

Regex delete

\n" + "

Regex invalidate

\n\n")); + return complete(event, e); +} + +int +ShowCache::lookup_url_form(int event, Event *e) +{ + CHECK_SHOW(begin("Cache Lookup")); + CHECK_SHOW(show("\n" + "

Lookup

\n" + "\n" + "\n" "\n\n")); + return complete(event, e); +} + +int +ShowCache::delete_url_form(int event, Event *e) { + CHECK_SHOW(begin("Cache Delete")); + CHECK_SHOW(show("
\n" + "

Type the list urls that you want to delete\n" + "in the box below. The urls MUST be separated by\n" + "new lines

\n\n" + "\n" "\n" "
\n\n")); + return complete(event, e); +} + +int +ShowCache::lookup_regex_form(int event, Event *e) +{ + CHECK_SHOW(begin("Cache Regex Lookup")); + CHECK_SHOW(show("
\n" + "

Type the list of regular expressions that you want to lookup\n" + "in the box below. The regular expressions MUST be separated by\n" + "new lines

\n\n" + "\n" "\n" "
\n\n")); + return complete(event, e); +} + +int +ShowCache::delete_regex_form(int event, Event *e) { + CHECK_SHOW(begin("Cache Regex delete")); + CHECK_SHOW(show("
\n" + "

Type the list of regular expressions that you want to delete\n" + "in the box below. The regular expressions MUST be separated by\n" + "new lines

\n\n" + "\n" "\n" "
\n\n")); + return complete(event, e); +} + +int +ShowCache::invalidate_regex_form(int event, Event *e) { + CHECK_SHOW(begin("Cache Regex Invalidate")); + CHECK_SHOW(show("
\n" + "

Type the list of regular expressions that you want to invalidate\n" + "in the box below. The regular expressions MUST be separated by\n" + "new lines

\n\n" + "\n" "\n" "
\n")); + return complete(event, e); +} + + +int +ShowCache::handleCacheEvent(int event, Event *e) { + // we use VC_EVENT_xxx to finish the cluster read in cluster mode + switch (event) { + case VC_EVENT_EOS: + case VC_EVENT_READ_COMPLETE: { + // cluster read done, we just print hit in cluster + CHECK_SHOW(show("

")); + CHECK_SHOW(show("\n")); + CHECK_SHOW(show("\n", content_length)); + + // delete button + CHECK_SHOW(show("\n" + "\n", + show_cache_urlstrs[0])); + CHECK_SHOW(show("
Doc Hit from Cluster
Size%" PRId64 "
Action
\n" + "\n" + "\n" "

")); + + if (buffer_reader) { + buffer->dealloc_reader(buffer_reader); + buffer_reader = 0; + } + if (buffer) { + free_MIOBuffer(buffer); + buffer = 0; + } + cvio = 0; + cache_vc->do_io_close(-1); + cache_vc = 0; + return complete(event, e); + } + case CACHE_EVENT_OPEN_READ: { + // get the vector + cache_vc = (CacheVC *) e; + CacheHTTPInfoVector *vec = &(cache_vc->vector); + int alt_count = vec->count(); + if (alt_count) { + Doc *d = (Doc *) (cache_vc->first_buf->data()); + time_t t; + char tmpstr[4096]; + + // print the Doc + CHECK_SHOW(show("

")); + CHECK_SHOW(show("\n")); + CHECK_SHOW(show("\n", d->first_key.string(tmpstr))); + CHECK_SHOW(show("\n", d->key.string(tmpstr))); + CHECK_SHOW(show("\n", d->sync_serial)); + CHECK_SHOW(show("\n", d->write_serial)); + CHECK_SHOW(show("\n", d->hlen)); + CHECK_SHOW(show("\n", d->ftype)); + CHECK_SHOW(show("\n", d->flen)); + CHECK_SHOW(show("\n", alt_count)); + + CHECK_SHOW(show("\n" + "\n", + show_cache_urlstrs[0])); + CHECK_SHOW(show("
Doc
first key %s
key %s
sync_serial%lu
write_serial%lu
header length%lu
fragment type%lu
fragment table length%lu
No of Alternates%d
Action
\n" + "\n" + "\n" "

")); + + for (int i = 0; i < alt_count; i++) { + // unmarshal the alternate?? + CHECK_SHOW(show("

\n")); + CHECK_SHOW(show("\n", i + 1)); + CacheHTTPInfo *obj = vec->get(i); + CacheKey obj_key = obj->object_key_get(); + HTTPHdr *cached_request = obj->request_get(); + HTTPHdr *cached_response = obj->response_get(); + int64_t obj_size = obj->object_size_get(); + int offset, tmp, used, done; + char b[4096]; + + // print request header + CHECK_SHOW(show("\n")); + + // print response header + CHECK_SHOW(show("\n")); + CHECK_SHOW(show("\n", obj_size)); + CHECK_SHOW(show("\n", obj_key.string(tmpstr))); + t = obj->request_sent_time_get(); + ink_ctime_r(&t, tmpstr); + CHECK_SHOW(show("\n", tmpstr)); + t = obj->response_received_time_get(); + ink_ctime_r(&t, tmpstr); + + CHECK_SHOW(show("\n", tmpstr)); + CHECK_SHOW(show("
Alternate %d
Request Header
"));
+          offset = 0;
+          do {
+            used = 0;
+            tmp = offset;
+            done = cached_request->print(b, 4095, &used, &tmp);
+            offset += used;
+            b[used] = '\0';
+            CHECK_SHOW(show("%s", b));
+          } while (!done);
+          CHECK_SHOW(show("
Response Header
"));
+          offset = 0;
+          do {
+            used = 0;
+            tmp = offset;
+            done = cached_response->print(b, 4095, &used, &tmp);
+            offset += used;
+            b[used] = '\0';
+            CHECK_SHOW(show("%s", b));
+          } while (!done);
+          CHECK_SHOW(show("
Size%" PRId64 "
Key%s
Request sent time%s
Response received time%s

")); + } + + cache_vc->do_io_close(-1); + return complete(event, e); + } + // open success but no vector, that is the Cluster open read, pass through + } + case VC_EVENT_READ_READY: + if (!cvio) { + buffer = new_empty_MIOBuffer(); + buffer_reader = buffer->alloc_reader(); + content_length = cache_vc->get_object_size(); + cvio = cache_vc->do_io_read(this, content_length, buffer); + } else + buffer_reader->consume(buffer_reader->read_avail()); + return EVENT_DONE; + case CACHE_EVENT_OPEN_READ_FAILED: + // something strange happen, or cache miss in cluster mode. + CHECK_SHOW(show("

Cache Lookup Failed, or missing in cluster

\n")); + return complete(event, e); + default: + CHECK_SHOW(show("

Cache Miss

\n")); + return complete(event, e); + } +} + +int +ShowCache::lookup_url(int event, Event *e) { + char header_str[300]; + + snprintf(header_str, sizeof(header_str), "%s", show_cache_urlstrs[0]); + CHECK_SHOW(begin(header_str)); + url.create(NULL); + const char *s; + s = show_cache_urlstrs[0]; + url.parse(&s, s + strlen(s)); + INK_MD5 md5; + int len; + url.MD5_get(&md5); + const char *hostname = url.host_get(&len); + SET_HANDLER(&ShowCache::handleCacheEvent); + Action *lookup_result = cacheProcessor.open_read(this, &md5, CACHE_FRAG_TYPE_HTTP, (char *) hostname, len); + if (!lookup_result) + lookup_result = ACTION_IO_ERROR; + if (lookup_result == ACTION_RESULT_DONE) + return EVENT_DONE; // callback complete + else if (lookup_result == ACTION_IO_ERROR) { + handleEvent(CACHE_EVENT_OPEN_READ_FAILED, 0); + return EVENT_DONE; // callback complete + } else + return EVENT_CONT; // callback pending, will be a cluster read. +} + + +int +ShowCache::delete_url(int event, Event *e) +{ + if (urlstrs_index == 0) { + // print the header the first time delete_url is called + CHECK_SHOW(begin("Delete URL")); + CHECK_SHOW(show("\n")); + } + + + if (strcmp(show_cache_urlstrs[urlstrs_index], "") == 0) { + // close the page when you reach the end of the + // url list + CHECK_SHOW(show("
\n")); + return complete(event, e); + } + url.create(NULL); + const char *s; + s = show_cache_urlstrs[urlstrs_index]; + CHECK_SHOW(show("%s", s)); + url.parse(&s, s + strlen(s)); + SET_HANDLER(&ShowCache::handleCacheDeleteComplete); + // increment the index so that the next time + // delete_url is called you delete the next url + urlstrs_index++; + cacheProcessor.remove(this, &url, CACHE_FRAG_TYPE_HTTP); + return EVENT_DONE; +} + +int +ShowCache::handleCacheDeleteComplete(int event, Event *e) +{ + + if (event == CACHE_EVENT_REMOVE) { + CHECK_SHOW(show("Delete succeeded\n")); + } else { + CHECK_SHOW(show("Delete failed\n")); + } + return delete_url(event, e); + +} + + +int +ShowCache::lookup_regex(int event, Event *e) +{ + CHECK_SHOW(begin("Regex Lookup")); + CHECK_SHOW(show("\n")); + + CHECK_SHOW(show("
\n" + "\n" "\n")); + + scan_flag = 0; //lookup + SET_HANDLER(&ShowCache::handleCacheScanCallback); + cacheProcessor.scan(this); + return EVENT_DONE; +} + +int +ShowCache::delete_regex(int event, Event *e) +{ + CHECK_SHOW(begin("Regex Delete")); + CHECK_SHOW(show("
\n")); + scan_flag = 1; // delete + SET_HANDLER(&ShowCache::handleCacheScanCallback); + cacheProcessor.scan(this); + return EVENT_DONE; + +} + + +int +ShowCache::invalidate_regex(int event, Event *e) +{ + CHECK_SHOW(begin("Regex Invalidate")); + CHECK_SHOW(show("
\n")); + scan_flag = 2; // invalidate + SET_HANDLER(&ShowCache::handleCacheScanCallback); + cacheProcessor.scan(this); + return EVENT_DONE; + +} + + + +int +ShowCache::handleCacheScanCallback(int event, Event *e) +{ + switch (event) { + case CACHE_EVENT_SCAN:{ + cache_vc = (CacheVC *) e; + return EVENT_CONT; + } + case CACHE_EVENT_SCAN_OBJECT:{ + HTTPInfo *alt = (HTTPInfo *) e; + char xx[501], m[501]; + int ib = 0, xd = 0, ml = 0; + + alt->request_get()->url_get()->print(xx, 500, &ib, &xd); + xx[ib] = '\0'; + + const char *mm = alt->request_get()->method_get(&ml); + + memcpy(m, mm, ml); + m[ml] = 0; + Debug("cache_scan", "scan url '%s' '%s'\n", m, xx); + + int res = CACHE_SCAN_RESULT_CONTINUE; + + for (int s = 0; show_cache_urlstrs[s][0] != '\0'; s++) { + const char* error; + int erroffset; + pcre* preq = pcre_compile(show_cache_urlstrs[s], 0, &error, &erroffset, NULL); + + if (preq) { + int r = pcre_exec(preq, NULL, xx, ib, 0, 0, NULL, 0); + + pcre_free(preq); + if (r != -1) { + linecount++; + if ((linecount % 5) == 0) { + CHECK_SHOW(show("")); + } else { + CHECK_SHOW(show("")); + } + if (scan_flag == 0) { + /*Y! Bug: 2249781: using onClick() because i need encodeURIComponent() and YTS doesn't have something like that */ + CHECK_SHOW(show("" + "\n", xx, xx, xx)); + } + if (scan_flag == 1) { + CHECK_SHOW(show("" "\n", xx)); + res = CACHE_SCAN_RESULT_DELETE; + } else if (scan_flag == 2) { + HTTPInfo new_info; + res = CACHE_SCAN_RESULT_UPDATE; + new_info.copy(alt); + new_info.response_get()->set_cooked_cc_need_revalidate_once(); + CHECK_SHOW(show("" "" "\n", xx)); + cache_vc->set_http_info(&new_info); + } + break; + } + } else { + // TODO: Regex didn't compile, show errors ? + } + } + return res; + } + case CACHE_EVENT_SCAN_DONE: + CHECK_SHOW(show("
" + "%s
%sdeleted
%sInvalidate
\n")); + if (scan_flag == 0) + if (linecount) { + CHECK_SHOW(show("

" "\n")); + } + CHECK_SHOW(show("

Done

\n")); + Debug("cache_scan", "scan done"); + complete(event, e); + return EVENT_DONE; + case CACHE_EVENT_SCAN_FAILED: + default: + CHECK_SHOW(show("

Error while scanning disk

\n")); + return EVENT_DONE; + } +} + +#endif // NON_MODULAR diff --git a/iocore/cache/CachePagesInternal.cc b/iocore/cache/CachePagesInternal.cc new file mode 100644 index 00000000..16e822d6 --- /dev/null +++ b/iocore/cache/CachePagesInternal.cc @@ -0,0 +1,344 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Cache.h" + +#ifdef NON_MODULAR +#include "Show.h" +#include "I_Tasks.h" + +struct ShowCacheInternal: public ShowCont +{ + int vol_index; + int seg_index; + CacheKey show_cache_key; + CacheVC *cache_vc; + + + int showMain(int event, Event * e); + int showEvacuations(int event, Event * e); + int showVolEvacuations(int event, Event * e); + int showVolumes(int event, Event * e); + int showVolVolumes(int event, Event * e); + int showSegments(int event, Event * e); + int showSegSegment(int event, Event * e); +#ifdef CACHE_STAT_PAGES + int showConnections(int event, Event * e); + int showVolConnections(int event, Event * e); +#endif + + ShowCacheInternal(Continuation * c, HTTPHdr * h) + : ShowCont(c, h), vol_index(0), seg_index(0) + { + SET_HANDLER(&ShowCacheInternal::showMain); + } + + ~ShowCacheInternal() { + } + +}; +extern ShowCacheInternal *theshowcacheInternal; +Action *register_ShowCacheInternal(Continuation * c, HTTPHdr * h); + + + + +extern Vol **gvol; +extern volatile int gnvol; + + +// Stat Pages +ShowCacheInternal *theshowcacheInternal = NULL; + + +#define STREQ_PREFIX(_x,_s) (!strncasecmp(_x,_s,sizeof(_s)-1)) +#define STREQ_LEN_PREFIX(_x,_l,_s) (path_len < sizeof(_s) && !strncasecmp(_x,_s,sizeof(_s)-1)) + + +Action * +register_ShowCacheInternal(Continuation * c, HTTPHdr * h) +{ + theshowcacheInternal = NEW(new ShowCacheInternal(c, h)); + URL *u = h->url_get(); + + int path_len; + const char *path = u->path_get(&path_len); + + if (!path) { + } +#ifdef CACHE_STAT_PAGES + else if (STREQ_LEN_PREFIX(path, path_len, "connections")) { + SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showConnections); + } +#endif + else if (STREQ_PREFIX(path, "evacuations")) { + SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showEvacuations); + } else if (STREQ_PREFIX(path, "volumes")) { + SET_CONTINUATION_HANDLER(theshowcacheInternal, &ShowCacheInternal::showVolumes); + } + + if (theshowcacheInternal->mutex->thread_holding) + CONT_SCHED_LOCK_RETRY(theshowcacheInternal); + else + eventProcessor.schedule_imm(theshowcacheInternal, ET_TASK); + return &theshowcacheInternal->action; +} + + +int +ShowCacheInternal::showMain(int event, Event * e) +{ + CHECK_SHOW(begin("Cache")); +#ifdef CACHE_STAT_PAGES + CHECK_SHOW(show("

Show Connections

\n" + "

Show Evacuations

\n" + "

Show Volumes

\n")); +#else + CHECK_SHOW(show("

Show Evacuations

\n" + "

Show Volumes

\n")); +#endif + return complete(event, e); +} + +#ifdef CACHE_STAT_PAGES +int +ShowCacheInternal::showConnections(int event, Event * e) +{ + CHECK_SHOW(begin("Cache VConnections")); + CHECK_SHOW(show("

Cache Connections

\n" + "" + "" + "" + "" "" "" "" "\n")); + + SET_HANDLER(&ShowCacheInternal::showVolConnections); + CONT_SCHED_LOCK_RETRY_RET(this); +} + + +int +ShowCacheInternal::showVolConnections(int event, Event * e) +{ + CACHE_TRY_LOCK(lock, gvol[vol_index]->mutex, mutex->thread_holding); + if (!lock) { + CONT_SCHED_LOCK_RETRY_RET(this); + } + for (CacheVC * vc = (CacheVC *) gvol[vol_index]->stat_cache_vcs.head; vc; vc = vc->stat_link.next) { + + char nbytes[60], todo[60], url[81092]; + int ib = 0, xd = 0; + URL uu; + + MUTEX_LOCK(lock2, vc->mutex, mutex->thread_holding); + // if vc is closed ignore - Ramki 08/30/2000 + if (vc->closed == 1) + continue; + sprintf(nbytes, "%d", vc->vio.nbytes); + sprintf(todo, "%d", vc->vio.ntodo()); + + if (vc->f.frag_type == CACHE_FRAG_TYPE_HTTP && vc->request.valid()) { + URL *u = vc->request.url_get(&uu); + u->print(url, 8000, &ib, &xd); + url[ib] = 0; + } else if (vc->alternate.valid()) { + URL *u = vc->alternate.request_url_get(&uu); + u->print(url, 8000, &ib, &xd); + url[ib] = 0; + } else + vc->key.string(url); + CHECK_SHOW(show("" "" // operation + "" // Vol + "" // URL/Hash + "" + "" + "" + "\n", + ((vc->vio.op == VIO::READ) ? "Read" : "Write"), + vc->vol->hash_id, + url, + vc->vio.ndone, + vc->vio.nbytes == INT64_MAX ? "all" : nbytes, vc->vio.nbytes == INT64_MAX ? "all" : todo)); + } + vol_index++; + if (vol_index < gnvol) + CONT_SCHED_LOCK_RETRY(this); + else { + CHECK_SHOW(show("
OperationVolumeURL/HashBytes DoneTotal BytesBytes Todo
%s%s%s%d%s%s
\n")); + return complete(event, e); + } + return EVENT_CONT; +} + +#endif + + +int +ShowCacheInternal::showEvacuations(int event, Event * e) +{ + CHECK_SHOW(begin("Cache Pending Evacuations")); + CHECK_SHOW(show("

Cache Evacuations

\n" + "" + "" "" "" "" "\n")); + + SET_HANDLER(&ShowCacheInternal::showVolEvacuations); + CONT_SCHED_LOCK_RETRY_RET(this); +} + + +int +ShowCacheInternal::showVolEvacuations(int event, Event * e) +{ + Vol *p = gvol[vol_index]; + CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding); + if (!lock) + CONT_SCHED_LOCK_RETRY_RET(this); + + EvacuationBlock *b; + int last = (p->len - (p->start - p->skip)) / EVACUATION_BUCKET_SIZE; + for (int i = 0; i < last; i++) { + for (b = p->evacuate[i].head; b; b = b->link.next) { + char offset[60]; + sprintf(offset, "%" PRIu64 "", (uint64_t) vol_offset(p, &b->dir)); + CHECK_SHOW(show("" "" // offset + "" // estimated size + "" // reader count + "" // done + "\n", offset, (int) dir_approx_size(&b->dir), b->readers, b->f.done ? "yes" : "no")); + } + } + vol_index++; + if (vol_index < gnvol) + CONT_SCHED_LOCK_RETRY(this); + else { + CHECK_SHOW(show("
OffsetEstimated SizeReader CountDone
%s%d%d%s
\n")); + return complete(event, e); + } + return EVENT_CONT; +} + +int +ShowCacheInternal::showVolumes(int event, Event * e) +{ + CHECK_SHOW(begin("Cache Volumes")); + CHECK_SHOW(show("

Cache Volumes

\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" "" "" "" "\n")); + + SET_HANDLER(&ShowCacheInternal::showVolVolumes); + CONT_SCHED_LOCK_RETRY_RET(this); +} + + +int +ShowCacheInternal::showVolVolumes(int event, Event * e) +{ + Vol *p = gvol[vol_index]; + CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding); + if (!lock) + CONT_SCHED_LOCK_RETRY_RET(this); + + char ctime[256]; + ink_ctime_r(&p->header->create_time, ctime); + ctime[strlen(ctime) - 1] = 0; + int agg_todo = 0; + int agg_done = p->agg_buf_pos; + CacheVC *c = 0; + for (c = p->agg.head; c; c = (CacheVC *) c->link.next) + agg_todo++; + CHECK_SHOW(show("" "" // ID + "" // blocks + "" // directory entries + "" // write position + "" // write agg to do + "" // write agg to do size + "" // write agg done + "" // phase + "" // create time + "" // sync serial + "" // write serial + "\n", + p->hash_id, + (uint64_t)((p->len - (p->start - p->skip)) / CACHE_BLOCK_SIZE), + (uint64_t)(p->buckets * DIR_DEPTH * p->segments), + (uint64_t)((p->header->write_pos - p->start) / CACHE_BLOCK_SIZE), + agg_todo, + p->agg_todo_size, + agg_done, p->header->phase, ctime, p->header->sync_serial, p->header->write_serial)); + CHECK_SHOW(show("
IDBlocksDirectory EntriesWrite PositionWrite Agg TodoWrite Agg Todo SizeWrite Agg DonePhaseCreate TimeSync SerialWrite Serial
%s%" PRId64 "%" PRId64 "%" PRId64 "%d%d%d%d%s%u%u
\n")); + SET_HANDLER(&ShowCacheInternal::showSegments); + return showSegments(event, e); +} + +int +ShowCacheInternal::showSegments(int event, Event * e) +{ + CHECK_SHOW(show("

Cache Volume Segments

\n" + "" + "" + "" + "" "" "" "" "\n")); + + SET_HANDLER(&ShowCacheInternal::showSegSegment); + seg_index = 0; + CONT_SCHED_LOCK_RETRY_RET(this); +} + +int +ShowCacheInternal::showSegSegment(int event, Event * e) +{ + Vol *p = gvol[vol_index]; + CACHE_TRY_LOCK(lock, p->mutex, mutex->thread_holding); + if (!lock) + CONT_SCHED_LOCK_RETRY_RET(this); + int free = 0, used = 0, empty = 0, valid = 0, agg_valid = 0, avg_size = 0; + dir_segment_accounted(seg_index, p, 0, &free, &used, &empty, &valid, &agg_valid, &avg_size); + CHECK_SHOW(show("" + "" + "" + "" + "" "" "" "\n", free, used, empty, valid, agg_valid, avg_size)); + seg_index++; + if (seg_index < p->segments) + CONT_SCHED_LOCK_RETRY(this); + else { + CHECK_SHOW(show("
FreeUsedEmptyValidAgg ValidAvg Size
%d%d%d%d%d%d
\n")); + seg_index = 0; + vol_index++; + if (vol_index < gnvol) + CONT_SCHED_LOCK_RETRY(this); + else + return complete(event, e); + } + return EVENT_CONT; +} + + + +#endif // NON_MODULAR diff --git a/iocore/cache/CacheRead.cc b/iocore/cache/CacheRead.cc new file mode 100644 index 00000000..c1177556 --- /dev/null +++ b/iocore/cache/CacheRead.cc @@ -0,0 +1,1127 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Cache.h" + +#ifdef HTTP_CACHE +#include "HttpCacheSM.h" //Added to get the scope of HttpCacheSM object. +#endif + +#define READ_WHILE_WRITER 1 + +Action * +Cache::open_read(Continuation * cont, CacheKey * key, CacheFragType type, char *hostname, int host_len) +{ + if (!CACHE_READY(type)) { + cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NOT_READY); + return ACTION_RESULT_DONE; + } + ink_assert(caches[type] == this); + + Vol *vol = key_to_vol(key, hostname, host_len); + Dir result, *last_collision = NULL; + ProxyMutex *mutex = cont->mutex; + OpenDirEntry *od = NULL; + CacheVC *c = NULL; + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock || (od = vol->open_read(key)) || dir_probe(key, vol, &result, &last_collision)) { + c = new_CacheVC(cont); + SET_CONTINUATION_HANDLER(c, &CacheVC::openReadStartHead); + c->vio.op = VIO::READ; + c->base_stat = cache_read_active_stat; + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE); + c->first_key = c->key = c->earliest_key = *key; + c->vol = vol; + c->frag_type = type; + c->od = od; + } + if (!c) + goto Lmiss; + if (!lock) { + CONT_SCHED_LOCK_RETRY(c); + return &c->_action; + } + if (c->od) + goto Lwriter; + c->dir = result; + c->last_collision = last_collision; + switch(c->do_read_call(&c->key)) { + case EVENT_DONE: return ACTION_RESULT_DONE; + case EVENT_RETURN: goto Lcallreturn; + default: return &c->_action; + } + } +Lmiss: + CACHE_INCREMENT_DYN_STAT(cache_read_failure_stat); + cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NO_DOC); + return ACTION_RESULT_DONE; +Lwriter: + SET_CONTINUATION_HANDLER(c, &CacheVC::openReadFromWriter); + if (c->handleEvent(EVENT_IMMEDIATE, 0) == EVENT_DONE) + return ACTION_RESULT_DONE; + return &c->_action; +Lcallreturn: + if (c->handleEvent(AIO_EVENT_DONE, 0) == EVENT_DONE) + return ACTION_RESULT_DONE; + return &c->_action; +} + +#ifdef HTTP_CACHE +Action * +Cache::open_read(Continuation * cont, CacheKey * key, CacheHTTPHdr * request, + CacheLookupHttpConfig * params, CacheFragType type, char *hostname, int host_len) +{ + + if (!CACHE_READY(type)) { + cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NOT_READY); + return ACTION_RESULT_DONE; + } + ink_assert(caches[type] == this); + + Vol *vol = key_to_vol(key, hostname, host_len); + Dir result, *last_collision = NULL; + ProxyMutex *mutex = cont->mutex; + OpenDirEntry *od = NULL; + CacheVC *c = NULL; + + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock || (od = vol->open_read(key)) || dir_probe(key, vol, &result, &last_collision)) { + c = new_CacheVC(cont); + c->first_key = c->key = c->earliest_key = *key; + c->vol = vol; + c->vio.op = VIO::READ; + c->base_stat = cache_read_active_stat; + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE); + c->request.copy_shallow(request); + c->frag_type = CACHE_FRAG_TYPE_HTTP; + c->params = params; + c->od = od; + } + if (!lock) { + SET_CONTINUATION_HANDLER(c, &CacheVC::openReadStartHead); + CONT_SCHED_LOCK_RETRY(c); + return &c->_action; + } + if (!c) + goto Lmiss; + if (c->od) + goto Lwriter; + // hit + c->dir = c->first_dir = result; + c->last_collision = last_collision; + SET_CONTINUATION_HANDLER(c, &CacheVC::openReadStartHead); + switch(c->do_read_call(&c->key)) { + case EVENT_DONE: return ACTION_RESULT_DONE; + case EVENT_RETURN: goto Lcallreturn; + default: return &c->_action; + } + } +Lmiss: + CACHE_INCREMENT_DYN_STAT(cache_read_failure_stat); + cont->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NO_DOC); + return ACTION_RESULT_DONE; +Lwriter: + // this is a horrible violation of the interface and should be fixed (FIXME) + ((HttpCacheSM *)cont)->set_readwhilewrite_inprogress(true); + SET_CONTINUATION_HANDLER(c, &CacheVC::openReadFromWriter); + if (c->handleEvent(EVENT_IMMEDIATE, 0) == EVENT_DONE) + return ACTION_RESULT_DONE; + return &c->_action; +Lcallreturn: + if (c->handleEvent(AIO_EVENT_DONE, 0) == EVENT_DONE) + return ACTION_RESULT_DONE; + return &c->_action; +} +#endif + +int +CacheVC::openReadFromWriterFailure(int event, Event * e) +{ + + od = NULL; + vector.clear(false); + CACHE_INCREMENT_DYN_STAT(cache_read_failure_stat); + CACHE_INCREMENT_DYN_STAT(cache_read_busy_failure_stat); + _action.continuation->handleEvent(event, e); + free_CacheVC(this); + return EVENT_DONE; +} + +int +CacheVC::openReadChooseWriter(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + intptr_t err = ECACHE_DOC_BUSY; + CacheVC *w = NULL; + + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); + od = vol->open_read(&first_key); // recheck in case the lock failed + if (!od) { + MUTEX_RELEASE(lock); + write_vc = NULL; + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(event, e); + } + if (frag_type != CACHE_FRAG_TYPE_HTTP) { + ink_assert(od->num_writers == 1); + w = od->writers.head; + if (w->start_time > start_time || w->closed < 0) { + MUTEX_RELEASE(lock); + od = NULL; + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(EVENT_IMMEDIATE, 0); + } + if (!w->closed) { + MUTEX_RELEASE(lock); + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) -err); + } + write_vc = w; + } +#ifdef HTTP_CACHE + else { + write_vector = &od->vector; + int write_vec_cnt = write_vector->count(); + for (int c = 0; c < write_vec_cnt; c++) + vector.insert(write_vector->get(c)); + // check if all the writers who came before this reader have + // set the http_info. + for (w = (CacheVC *) od->writers.head; w; w = (CacheVC *) w->opendir_link.next) { + if (w->start_time > start_time || w->closed < 0) + continue; + if (!w->closed && !cache_config_read_while_writer) { + MUTEX_RELEASE(lock); + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) - err); + } + if (w->alternate_index != CACHE_ALT_INDEX_DEFAULT) + continue; + + if (!w->closed && !w->alternate.valid()) { + od = NULL; + vector.clear(false); + VC_SCHED_LOCK_RETRY(); + } + // construct the vector from the writers. + int alt_ndx = CACHE_ALT_INDEX_DEFAULT; + if (w->f.update) { + // all Update cases. Need to get the alternate index. + alt_ndx = get_alternate_index(&vector, w->update_key); + // if its an alternate delete + if (!w->alternate.valid()) { + if (alt_ndx >= 0) + vector.remove(alt_ndx, false); + continue; + } + } + ink_assert(w->alternate.valid()); + if (w->alternate.valid()) + vector.insert(&w->alternate, alt_ndx); + } + + if (!vector.count()) { + if (od->reading_vec) { + MUTEX_RELEASE(lock); + // the writer(s) are reading the vector, so there is probably + // an old vector. Since this reader came before any of the + // current writers, we should return the old data + od = NULL; + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(EVENT_IMMEDIATE, 0); + } else { + MUTEX_RELEASE(lock); + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) - ECACHE_NO_DOC); + } + } +#ifdef FIXME_NONMODULAR + if (cache_config_select_alternate) { + alternate_index = HttpTransactCache::SelectFromAlternates(&vector, &request, params); + if (alternate_index < 0) + MUTEX_RELEASE(lock); + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) - ECACHE_ALT_MISS); + } else +#endif + alternate_index = 0; + CacheHTTPInfo *obj = vector.get(alternate_index); + for (w = (CacheVC *) od->writers.head; w; w = (CacheVC *) w->opendir_link.next) { + if (obj->m_alt == w->alternate.m_alt) { + write_vc = w; + break; + } + } + vector.clear(false); + if (!write_vc) { + MUTEX_RELEASE(lock); + DDebug("cache_read_agg", "%x: key: %X %X writer alternate different: %d", this, first_key.word(1), alternate_index); + od = NULL; + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(EVENT_IMMEDIATE, 0); + } + + DDebug("cache_read_agg", + "%x: key: %X eKey: %d # alts: %d, ndx: %d, # writers: %d writer: %x", + this, first_key.word(1), write_vc->earliest_key.word(1), + vector.count(), alternate_index, od->num_writers, write_vc); + } +#endif //HTTP_CACHE + return EVENT_CONT; +} + +int +CacheVC::openReadFromWriter(int event, Event * e) +{ + if (!f.read_from_writer_called) { + // The assignment to last_collision as NULL was + // made conditional after INKqa08411 + last_collision = NULL; + // Let's restart the clock from here - the first time this a reader + // gets in this state. Its possible that the open_read was called + // before the open_write, but the reader could not get the volume + // lock. If we don't reset the clock here, we won't choose any writer + // and hence fail the read request. + start_time = ink_get_hrtime(); + f.read_from_writer_called = 1; + } + cancel_trigger(); + intptr_t err = ECACHE_DOC_BUSY; + DDebug("cache_read_agg", "%x: key: %X In openReadFromWriter", this, first_key.word(1)); +#ifndef READ_WHILE_WRITER + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) -err); +#else + if (_action.cancelled) { + od = NULL; // only open for read so no need to close + return free_CacheVC(this); + } + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); + od = vol->open_read(&first_key); // recheck in case the lock failed + if (!od) { + MUTEX_RELEASE(lock); + write_vc = NULL; + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(event, e); + } else + ink_debug_assert(od == vol->open_read(&first_key)); + if (!write_vc) { + MUTEX_RELEASE(lock); + int ret = openReadChooseWriter(event, e); + if (ret == EVENT_DONE || !write_vc) + return ret; + } else { + if (writer_done()) { + MUTEX_RELEASE(lock); + DDebug("cache_read_agg", + "%x: key: %X writer %x has left, continuing as normal read", this, first_key.word(1), write_vc); + od = NULL; + write_vc = NULL; + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(event, e); + } + } +#ifdef HTTP_CACHE + OpenDirEntry *cod = od; +#endif + od = NULL; + // someone is currently writing the document + if (write_vc->closed < 0) { + MUTEX_RELEASE(lock); + write_vc = NULL; + //writer aborted, continue as if there is no writer + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(EVENT_IMMEDIATE, 0); + } + // allow reading from unclosed writer for http requests only. + ink_assert(frag_type == CACHE_FRAG_TYPE_HTTP || write_vc->closed); + if (!write_vc->closed && !write_vc->fragment) { + if (!cache_config_read_while_writer || frag_type != CACHE_FRAG_TYPE_HTTP) + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) - err); + DDebug("cache_read_agg", + "%x: key: %X writer: closed:%d, fragment:%d, retry: %d", + this, first_key.word(1), write_vc->closed, write_vc->fragment, writer_lock_retry); + VC_SCHED_WRITER_RETRY(); + } + + CACHE_TRY_LOCK(writer_lock, write_vc->mutex, mutex->thread_holding); + if (!writer_lock) { + DDebug("cache_read_agg", "%x: key: %X lock miss", this, first_key.word(1)); + VC_SCHED_LOCK_RETRY(); + } + MUTEX_RELEASE(lock); + + if (!write_vc->io.ok()) + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) - err); +#ifdef HTTP_CACHE + if (frag_type == CACHE_FRAG_TYPE_HTTP) { + DDebug("cache_read_agg", + "%x: key: %X http passed stage 1, closed: %d, frag: %d", + this, first_key.word(1), write_vc->closed, write_vc->fragment); + if (!write_vc->alternate.valid()) + return openReadFromWriterFailure(CACHE_EVENT_OPEN_READ_FAILED, (Event *) - err); + alternate.copy(&write_vc->alternate); + vector.insert(&alternate); + alternate.object_key_get(&key); + write_vc->f.readers = 1; + if (!(write_vc->f.update && write_vc->total_len == 0)) { + key = write_vc->earliest_key; + if (!write_vc->closed) + alternate.object_size_set(write_vc->vio.nbytes); + else + alternate.object_size_set(write_vc->total_len); + } else { + key = write_vc->update_key; + ink_assert(write_vc->closed); + DDebug("cache_read_agg", "%x: key: %X writer header update", this, first_key.word(1)); + // Update case (b) : grab doc_len from the writer's alternate + doc_len = alternate.object_size_get(); + if (write_vc->update_key == cod->single_doc_key && + (cod->move_resident_alt || write_vc->f.rewrite_resident_alt) && write_vc->first_buf._ptr()) { + // the resident alternate is being updated and its a + // header only update. The first_buf of the writer has the + // document body. + Doc *doc = (Doc *) write_vc->first_buf->data(); + writer_buf = new_IOBufferBlock(write_vc->first_buf, doc->data_len(), doc->prefix_len()); + MUTEX_RELEASE(writer_lock); + ink_assert(doc_len == doc->data_len()); + length = doc_len; + f.single_fragment = 1; + doc_pos = 0; + earliest_key = key; + dir_clean(&first_dir); + dir_clean(&earliest_dir); + SET_HANDLER(&CacheVC::openReadFromWriterMain); + CACHE_INCREMENT_DYN_STAT(cache_read_busy_success_stat); + return callcont(CACHE_EVENT_OPEN_READ); + } + // want to snarf the new headers from the writer + // and then continue as if nothing happened + last_collision = NULL; + MUTEX_RELEASE(writer_lock); + SET_HANDLER(&CacheVC::openReadStartEarliest); + return openReadStartEarliest(event, e); + } + } else { +#endif //HTTP_CACHE + DDebug("cache_read_agg", "%x: key: %X non-http passed stage 1", this, first_key.word(1)); + key = write_vc->earliest_key; +#ifdef HTTP_CACHE + } +#endif + if (write_vc->fragment) { + doc_len = write_vc->vio.nbytes; + last_collision = NULL; + DDebug("cache_read_agg", + "%x: key: %X closed: %d, fragment: %d, len: %d starting first fragment", + this, first_key.word(1), write_vc->closed, write_vc->fragment, (int)doc_len); + MUTEX_RELEASE(writer_lock); + // either a header + body update or a new document + SET_HANDLER(&CacheVC::openReadStartEarliest); + return openReadStartEarliest(event, e); + } + writer_buf = write_vc->blocks; + writer_offset = write_vc->offset; + length = write_vc->length; + // copy the vector + f.single_fragment = !write_vc->fragment; // single fragment doc + doc_pos = 0; + earliest_key = write_vc->earliest_key; + ink_assert(earliest_key == key); + doc_len = write_vc->total_len; + dir_clean(&first_dir); + dir_clean(&earliest_dir); + DDebug("cache_read_agg", "%x key: %X %X: single fragment read", first_key.word(1), key.word(0)); + MUTEX_RELEASE(writer_lock); + SET_HANDLER(&CacheVC::openReadFromWriterMain); + CACHE_INCREMENT_DYN_STAT(cache_read_busy_success_stat); + return callcont(CACHE_EVENT_OPEN_READ); +#endif //READ_WHILE_WRITER +} + +int +CacheVC::openReadFromWriterMain(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + if (seek_to) { + vio.ndone = seek_to; + seek_to = 0; + } + IOBufferBlock *b = NULL; + int64_t ntodo = vio.ntodo(); + if (ntodo <= 0) + return EVENT_CONT; + if (length < ((int64_t)doc_len) - vio.ndone) { + DDebug("cache_read_agg", "truncation %X", first_key.word(1)); + if (is_action_tag_set("cache")) { + ink_release_assert(false); + } + Warning("Document %X truncated at %d of %d, reading from writer", first_key.word(1), (int)vio.ndone, (int)doc_len); + return calluser(VC_EVENT_ERROR); + } + /* its possible that the user did a do_io_close before + openWriteWriteDone was called. */ + if (length > ((int64_t)doc_len) - vio.ndone) { + int64_t skip_bytes = length - (doc_len - vio.ndone); + iobufferblock_skip(writer_buf, &writer_offset, &length, skip_bytes); + } + int64_t bytes = length; + if (bytes > vio.ntodo()) + bytes = vio.ntodo(); + if (vio.ndone >= (int64_t)doc_len) { + ink_assert(bytes <= 0); + // reached the end of the document and the user still wants more + return calluser(VC_EVENT_EOS); + } + b = iobufferblock_clone(writer_buf, writer_offset, bytes); + writer_buf = iobufferblock_skip(writer_buf, &writer_offset, &length, bytes); + vio.buffer.mbuf->append_block(b); + vio.ndone += bytes; + if (vio.ntodo() <= 0) + return calluser(VC_EVENT_READ_COMPLETE); + else + return calluser(VC_EVENT_READ_READY); +} + +int +CacheVC::openReadClose(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + if (is_io_in_progress()) { + if (event != AIO_EVENT_DONE) + return EVENT_CONT; + set_io_not_in_progress(); + } + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); +#ifdef HIT_EVACUATE + if (f.hit_evacuate && dir_valid(vol, &first_dir) && closed > 0) { + if (f.single_fragment) + vol->force_evacuate_head(&first_dir, dir_pinned(&first_dir)); + else if (dir_valid(vol, &earliest_dir)) { + vol->force_evacuate_head(&first_dir, dir_pinned(&first_dir)); + vol->force_evacuate_head(&earliest_dir, dir_pinned(&earliest_dir)); + } + } +#endif + vol->close_read(this); + return free_CacheVC(this); +} + +int +CacheVC::openReadReadDone(int event, Event * e) +{ + Doc *doc = NULL; + + cancel_trigger(); + if (event == EVENT_IMMEDIATE) + return EVENT_CONT; + set_io_not_in_progress(); + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); + if (event == AIO_EVENT_DONE && !io.ok()) { + dir_delete(&earliest_key, vol, &earliest_dir); + goto Lerror; + } + if (last_collision && // no missed lock + dir_valid(vol, &dir)) // object still valid + { + doc = (Doc *) buf->data(); + if (doc->magic != DOC_MAGIC) { + char tmpstring[100]; + if (doc->magic == DOC_CORRUPT) + Warning("Middle: Doc checksum does not match for %s", key.string(tmpstring)); + else + Warning("Middle: Doc magic does not match for %s", key.string(tmpstring)); + goto Lerror; + } + if (doc->key == key) + goto LreadMain; + } + if (last_collision && dir_offset(&dir) != dir_offset(last_collision)) + last_collision = 0; // object has been/is being overwritten + if (dir_probe(&key, vol, &dir, &last_collision)) { + int ret = do_read_call(&key); + if (ret == EVENT_RETURN) + goto Lcallreturn; + return EVENT_CONT; + } else if (write_vc) { + if (writer_done()) { + last_collision = NULL; + while (dir_probe(&earliest_key, vol, &dir, &last_collision)) { + if (dir_offset(&dir) == dir_offset(&earliest_dir)) { + DDebug("cache_read_agg", "%x: key: %X ReadRead complete: %d", + this, first_key.word(1), (int)vio.ndone); + doc_len = vio.ndone; + goto Ldone; + } + } + DDebug("cache_read_agg", "%x: key: %X ReadRead writer aborted: %d", + this, first_key.word(1), (int)vio.ndone); + goto Lerror; + } + DDebug("cache_read_agg", "%x: key: %X ReadRead retrying: %d", this, first_key.word(1), (int)vio.ndone); + VC_SCHED_WRITER_RETRY(); // wait for writer + } + // fall through for truncated documents + } +Lerror: + char tmpstring[100]; + Warning("Document %s truncated", earliest_key.string(tmpstring)); + return calluser(VC_EVENT_ERROR); +Ldone: + return calluser(VC_EVENT_EOS); +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); +LreadMain: + fragment++; + doc_pos = doc->prefix_len(); + next_CacheKey(&key, &key); + SET_HANDLER(&CacheVC::openReadMain); + return openReadMain(event, e); +} + +int +CacheVC::openReadMain(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + Doc *doc = (Doc *) buf->data(); + int64_t ntodo = vio.ntodo(); + int64_t bytes = doc->len - doc_pos; + IOBufferBlock *b = NULL; + if (seek_to) { // handle do_io_pread + if (seek_to >= (int)doc_len) { + vio.ndone = doc_len; + return calluser(VC_EVENT_EOS); + } + Doc *first_doc = (Doc*)first_buf->data(); + Frag *first_frag = first_doc->frags(); + if (!f.single_fragment) { + // find the target fragment + int i = 0; + for (; i < (int)first_doc->nfrags(); i++) + if (seek_to < (int64_t)first_frag[i].offset) break; + if (i >= (int)first_doc->nfrags()) { + Warning("bad fragment header"); + return calluser(VC_EVENT_ERROR); + } + // fragment is the current fragment + // key is the next key (fragment + 1) + if (i != fragment) { + i--; // read will increment the key and fragment + while (i > fragment) { + next_CacheKey(&key, &key); + fragment++; + } + while (i < fragment) { + prev_CacheKey(&key, &key); + fragment--; + } + goto Lread; + } + } + if (fragment) + doc_pos = doc->prefix_len() + seek_to - (int64_t)first_frag[fragment-1].offset; + else + doc_pos = doc->prefix_len() + seek_to; + vio.ndone = 0; + seek_to = 0; + ntodo = vio.ntodo(); + } + if (ntodo <= 0) + return EVENT_CONT; + if (vio.buffer.mbuf->max_read_avail() > vio.buffer.writer()->water_mark && vio.ndone) // initiate read of first block + return EVENT_CONT; + if ((bytes <= 0) && vio.ntodo() >= 0) + goto Lread; + if (bytes > vio.ntodo()) + bytes = vio.ntodo(); + b = new_IOBufferBlock(buf, bytes, doc_pos); + b->_buf_end = b->_end; + vio.buffer.mbuf->append_block(b); + vio.ndone += bytes; + doc_pos += bytes; + if (vio.ntodo() <= 0) + return calluser(VC_EVENT_READ_COMPLETE); + else { + if (calluser(VC_EVENT_READ_READY) == EVENT_DONE) + return EVENT_DONE; + // we have to keep reading until we give the user all the + // bytes it wanted or we hit the watermark. + if (vio.ntodo() > 0 && !vio.buffer.writer()->high_water()) + goto Lread; + return EVENT_CONT; + } +Lread: { + if ((uint32_t)vio.ndone >= doc_len) + // reached the end of the document and the user still wants more + return calluser(VC_EVENT_EOS); + last_collision = 0; + writer_lock_retry = 0; + // if the state machine calls reenable on the callback from the cache, + // we set up a schedule_imm event. The openReadReadDone discards + // EVENT_IMMEDIATE events. So, we have to cancel that trigger and set + // a new EVENT_INTERVAL event. + cancel_trigger(); + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) { + SET_HANDLER(&CacheVC::openReadMain); + VC_SCHED_LOCK_RETRY(); + } + if (dir_probe(&key, vol, &dir, &last_collision)) { + SET_HANDLER(&CacheVC::openReadReadDone); + int ret = do_read_call(&key); + if (ret == EVENT_RETURN) + goto Lcallreturn; + return EVENT_CONT; + } else if (write_vc) { + if (writer_done()) { + last_collision = NULL; + while (dir_probe(&earliest_key, vol, &dir, &last_collision)) { + if (dir_offset(&dir) == dir_offset(&earliest_dir)) { + DDebug("cache_read_agg", "%x: key: %X ReadMain complete: %d", + this, first_key.word(1), (int)vio.ndone); + doc_len = vio.ndone; + goto Leos; + } + } + DDebug("cache_read_agg", "%X: key: %X ReadMain writer aborted: %d", + this, first_key.word(1), (int)vio.ndone); + goto Lerror; + } + DDebug("cache_read_agg", "%X: key: %X ReadMain retrying: %d", this, first_key.word(1), (int)vio.ndone); + SET_HANDLER(&CacheVC::openReadMain); + VC_SCHED_WRITER_RETRY(); + } + if (is_action_tag_set("cache")) + ink_release_assert(false); + Warning("Document %X truncated at %d of %d, missing fragment %X", first_key.word(1), (int)vio.ndone, (int)doc_len, key.word(1)); + // remove the directory entry + dir_delete(&earliest_key, vol, &earliest_dir); + } +Lerror: + return calluser(VC_EVENT_ERROR); +Leos: + return calluser(VC_EVENT_EOS); +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); +} + +/* + This code follows CacheVC::openReadStartHead closely, + if you change this you might have to change that. +*/ +int +CacheVC::openReadStartEarliest(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + int ret = 0; + Doc *doc = NULL; + cancel_trigger(); + set_io_not_in_progress(); + if (_action.cancelled) + return free_CacheVC(this); + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); + if (!buf) + goto Lread; + if (!io.ok()) + goto Ldone; + // an object needs to be outside the aggregation window in order to be + // be evacuated as it is read + if (!dir_agg_valid(vol, &dir)) { + // a directory entry which is nolonger valid may have been overwritten + if (!dir_valid(vol, &dir)) + last_collision = NULL; + goto Lread; + } + doc = (Doc *) buf->data(); + if (doc->magic != DOC_MAGIC) { + char tmpstring[100]; + if (is_action_tag_set("cache")) { + ink_release_assert(false); + } + if (doc->magic == DOC_CORRUPT) + Warning("Earliest: Doc checksum does not match for %s", key.string(tmpstring)); + else + Warning("Earliest : Doc magic does not match for %s", key.string(tmpstring)); + // remove the dir entry + dir_delete(&key, vol, &dir); + // try going through the directory entries again + // in case the dir entry we deleted doesnt correspond + // to the key we are looking for. This is possible + // because of directory collisions + last_collision = NULL; + goto Lread; + } + if (!(doc->key == key)) // collisiion + goto Lread; + // success + earliest_key = key; + doc_pos = doc->prefix_len(); + next_CacheKey(&key, &doc->key); + vol->begin_read(this); +#ifdef HIT_EVACUATE + if (vol->within_hit_evacuate_window(&earliest_dir) && + (!cache_config_hit_evacuate_size_limit || doc_len <= cache_config_hit_evacuate_size_limit)) { + DDebug("cache_hit_evac", "dir: %d, write: %d, phase: %d", + dir_offset(&earliest_dir), offset_to_vol_offset(vol, vol->header->write_pos), vol->header->phase); + f.hit_evacuate = 1; + } +#endif + goto Lsuccess; +Lread: + if (dir_probe(&key, vol, &earliest_dir, &last_collision) || + dir_lookaside_probe(&key, vol, &earliest_dir, NULL)) + { + dir = earliest_dir; + if ((ret = do_read_call(&key)) == EVENT_RETURN) + goto Lcallreturn; + return ret; + } + // read has detected that alternate does not exist in the cache. + // rewrite the vector. +#ifdef HTTP_CACHE + if (!f.read_from_writer_called && frag_type == CACHE_FRAG_TYPE_HTTP) { + // don't want any writers while we are evacuating the vector + if (!vol->open_write(this, false, 1)) { + Doc *doc1 = (Doc *) first_buf->data(); + uint32_t len = write_vector->get_handles(doc1->hdr(), doc1->hlen); + ink_assert(len == doc1->hlen && write_vector->count() > 0); + write_vector->remove(alternate_index, true); + // if the vector had one alternate, delete it's directory entry + if (len != doc1->hlen || !write_vector->count()) { + // sometimes the delete fails when there is a race and another read + // finds that the directory entry has been overwritten + // (cannot assert on the return value) + dir_delete(&first_key, vol, &first_dir); + } else { + buf = NULL; + last_collision = NULL; + write_len = 0; + header_len = write_vector->marshal_length(); + f.evac_vector = 1; + f.use_first_key = 1; + key = first_key; + // always use od->first_dir to overwrite a directory. + // If an evacuation happens while a vector is being updated + // the evacuator changes the od->first_dir to the new directory + // that it inserted + od->first_dir = first_dir; + od->writing_vec = 1; + earliest_key = zero_key; + + // set up this VC as a alternate delete write_vc + vio.op = VIO::WRITE; + total_len = 0; + f.update = 1; + alternate_index = CACHE_ALT_REMOVED; + ///////////////////////////////////////////////////////////////// + // change to create a directory entry for a resident alternate // + // when another alternate does not exist. // + ///////////////////////////////////////////////////////////////// + if (doc1->total_len > 0) { + od->move_resident_alt = 1; + od->single_doc_key = doc1->key; + dir_assign(&od->single_doc_dir, &dir); + dir_set_tag(&od->single_doc_dir, od->single_doc_key.word(2)); + } + SET_HANDLER(&CacheVC::openReadVecWrite); + if ((ret = do_write_call()) == EVENT_RETURN) + goto Lcallreturn; + return ret; + } + } + } +#endif + // open write failure - another writer, so don't modify the vector + Ldone: + if (od) + vol->close_write(this); + } + CACHE_INCREMENT_DYN_STAT(cache_read_failure_stat); + _action.continuation->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_NO_DOC); + return free_CacheVC(this); +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); // hopefully a tail call +Lsuccess: + if (write_vc) + CACHE_INCREMENT_DYN_STAT(cache_read_busy_success_stat); + SET_HANDLER(&CacheVC::openReadMain); + return callcont(CACHE_EVENT_OPEN_READ); +} + +// create the directory entry after the vector has been evacuated +// the volume lock has been taken when this function is called +#ifdef HTTP_CACHE +int +CacheVC::openReadVecWrite(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + set_io_not_in_progress(); + ink_assert(od); + od->writing_vec = 0; + if (_action.cancelled) + return openWriteCloseDir(EVENT_IMMEDIATE, 0); + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); + if (io.ok()) { + ink_assert(f.evac_vector); + ink_assert(frag_type == CACHE_FRAG_TYPE_HTTP); + ink_assert(!buf.m_ptr); + f.evac_vector = false; + last_collision = NULL; + f.update = 0; + alternate_index = CACHE_ALT_INDEX_DEFAULT; + f.use_first_key = 0; + vio.op = VIO::READ; + dir_overwrite(&first_key, vol, &dir, &od->first_dir); + if (od->move_resident_alt) + dir_insert(&od->single_doc_key, vol, &od->single_doc_dir); +#ifdef FIXME_NONMODULAR + int alt_ndx = HttpTransactCache::SelectFromAlternates(write_vector, &request, params); +#else + int alt_ndx = 0; +#endif + vol->close_write(this); + if (alt_ndx >= 0) { + vector.clear(); + // we don't need to start all over again, since we already + // have the vector in memory. But this is simpler and this + // case is rare. + goto Lrestart; + } + } else + vol->close_write(this); + } + + CACHE_INCREMENT_DYN_STAT(cache_read_failure_stat); + _action.continuation->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -ECACHE_ALT_MISS); + return free_CacheVC(this); +Lrestart: + SET_HANDLER(&CacheVC::openReadStartHead); + return openReadStartHead(EVENT_IMMEDIATE, 0); +} +#endif + +/* + This code follows CacheVC::openReadStartEarliest closely, + if you change this you might have to change that. +*/ +int +CacheVC::openReadStartHead(int event, Event * e) +{ + intptr_t err = ECACHE_NO_DOC; + Doc *doc = NULL; + cancel_trigger(); + set_io_not_in_progress(); + if (_action.cancelled) + return free_CacheVC(this); + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_SCHED_LOCK_RETRY(); + if (!buf) + goto Lread; + if (!io.ok()) + goto Ldone; + // an object needs to be outside the aggregation window in order to be + // be evacuated as it is read + if (!dir_agg_valid(vol, &dir)) { + // a directory entry which is nolonger valid may have been overwritten + if (!dir_valid(vol, &dir)) + last_collision = NULL; + goto Lread; + } + doc = (Doc *) buf->data(); + if (doc->magic != DOC_MAGIC) { + char tmpstring[100]; + if (is_action_tag_set("cache")) { + ink_release_assert(false); + } + if (doc->magic == DOC_CORRUPT) + Warning("Head: Doc checksum does not match for %s", key.string(tmpstring)); + else + Warning("Head : Doc magic does not match for %s", key.string(tmpstring)); + // remove the dir entry + dir_delete(&key, vol, &dir); + // try going through the directory entries again + // in case the dir entry we deleted doesnt correspond + // to the key we are looking for. This is possible + // because of directory collisions + last_collision = NULL; + goto Lread; + } + if (!(doc->first_key == key)) + goto Lread; + if (f.lookup) + goto Lookup; + earliest_dir = dir; +#ifdef HTTP_CACHE + CacheHTTPInfo *alternate_tmp; + if (frag_type == CACHE_FRAG_TYPE_HTTP) { + ink_assert(doc->hlen); + if (!doc->hlen) + goto Ldone; + if (vector.get_handles(doc->hdr(), doc->hlen) != doc->hlen) { + if (buf) { + Note("OpenReadHead failed for cachekey %X : vector inconsistency with %d", key.word(0), doc->hlen); + dir_delete(&key, vol, &dir); + } + err = ECACHE_BAD_META_DATA; + goto Ldone; + } + if (cache_config_select_alternate) { +#ifdef FIXME_NONMODULAR + alternate_index = HttpTransactCache::SelectFromAlternates(&vector, &request, params); +#else + alternate_index = 0; +#endif + if (alternate_index < 0) { + err = ECACHE_ALT_MISS; + goto Ldone; + } + } else + alternate_index = 0; + alternate_tmp = vector.get(alternate_index); + if (!alternate_tmp->valid()) { + if (buf) { + Note("OpenReadHead failed for cachekey %X : alternate inconsistency", key.word(0)); + dir_delete(&key, vol, &dir); + } + goto Ldone; + } + + alternate.copy_shallow(alternate_tmp); + alternate.object_key_get(&key); + doc_len = alternate.object_size_get(); + if (key == doc->key) { // is this my data? + f.single_fragment = doc->single_fragment(); + ink_assert(f.single_fragment); // otherwise need to read earliest + ink_assert(doc->hlen); + doc_pos = doc->prefix_len(); + next_CacheKey(&key, &doc->key); + } else { + f.single_fragment = false; + } + } else +#endif + { + next_CacheKey(&key, &doc->key); + f.single_fragment = doc->single_fragment(); + doc_pos = doc->prefix_len(); + doc_len = doc->total_len; + } + // the first fragment might have been gc'ed. Make sure the first + // fragment is there before returning CACHE_EVENT_OPEN_READ + if (!f.single_fragment) + goto Learliest; + +#ifdef HIT_EVACUATE + if (vol->within_hit_evacuate_window(&dir) && + (!cache_config_hit_evacuate_size_limit || doc_len <= cache_config_hit_evacuate_size_limit)) { + DDebug("cache_hit_evac", "dir: %d, write: %d, phase: %d", + dir_offset(&dir), offset_to_vol_offset(vol, vol->header->write_pos), vol->header->phase); + f.hit_evacuate = 1; + } +#endif + + first_buf = buf; + vol->begin_read(this); + + goto Lsuccess; + + Lread: + // check for collision + // INKqa07684 - Cache::lookup returns CACHE_EVENT_OPEN_READ_FAILED. + // don't want to go through this BS of reading from a writer if + // its a lookup. In this case lookup will fail while the document is + // being written to the cache. + OpenDirEntry *cod = vol->open_read(&key); + if (cod && !f.read_from_writer_called) { + if (f.lookup) { + err = ECACHE_DOC_BUSY; + goto Ldone; + } + od = cod; + MUTEX_RELEASE(lock); + SET_HANDLER(&CacheVC::openReadFromWriter); + return handleEvent(EVENT_IMMEDIATE, 0); + } + if (dir_probe(&key, vol, &dir, &last_collision)) { + first_dir = dir; + int ret = do_read_call(&key); + if (ret == EVENT_RETURN) + goto Lcallreturn; + return ret; + } + } +Ldone: + if (!f.lookup) { + CACHE_INCREMENT_DYN_STAT(cache_read_failure_stat); + _action.continuation->handleEvent(CACHE_EVENT_OPEN_READ_FAILED, (void *) -err); + } else { + CACHE_INCREMENT_DYN_STAT(cache_lookup_failure_stat); + _action.continuation->handleEvent(CACHE_EVENT_LOOKUP_FAILED, (void *) -err); + } + return free_CacheVC(this); +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); // hopefully a tail call +Lsuccess: + SET_HANDLER(&CacheVC::openReadMain); + return callcont(CACHE_EVENT_OPEN_READ); +Lookup: + CACHE_INCREMENT_DYN_STAT(cache_lookup_success_stat); + _action.continuation->handleEvent(CACHE_EVENT_LOOKUP, 0); + return free_CacheVC(this); +Learliest: + first_buf = buf; + buf = NULL; + earliest_key = key; + last_collision = NULL; + SET_HANDLER(&CacheVC::openReadStartEarliest); + return openReadStartEarliest(event, e); +} diff --git a/iocore/cache/CacheTest.cc b/iocore/cache/CacheTest.cc new file mode 100644 index 00000000..2e1bda3b --- /dev/null +++ b/iocore/cache/CacheTest.cc @@ -0,0 +1,418 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#include "P_Cache.h" +#include "P_CacheTest.h" +#include "api/ts/ts.h" + +CacheTestSM::CacheTestSM(RegressionTest *t) : + RegressionSM(t), + timeout(0), + cache_action(0), + start_time(0), + cache_vc(0), + cvio(0), + buffer(0), + buffer_reader(0), + nbytes(-1), + repeat_count(0), + expect_event(EVENT_NONE), + expect_initial_event(EVENT_NONE), + initial_event(EVENT_NONE), + content_salt(0) +{ + SET_HANDLER(&CacheTestSM::event_handler); +} + +CacheTestSM::~CacheTestSM() { + ink_assert(!cache_action); + ink_assert(!cache_vc); + if (buffer_reader) + buffer->dealloc_reader(buffer_reader); + if (buffer) + free_MIOBuffer(buffer); +} + +int CacheTestSM::open_read_callout() { + cvio = cache_vc->do_io_read(this, nbytes, buffer); + return 1; +} + +int CacheTestSM::open_write_callout() { + cvio = cache_vc->do_io_write(this, nbytes, buffer_reader); + return 1; +} + +int CacheTestSM::event_handler(int event, void *data) { + + switch (event) { + + case EVENT_INTERVAL: + case EVENT_IMMEDIATE: + cancel_timeout(); + if (cache_action) { + cache_action->cancel(); + cache_action = 0; + } + if (cache_vc) { + cache_vc->do_io_close(); + cache_vc = 0; + } + cvio = 0; + make_request(); + return EVENT_DONE; + + case CACHE_EVENT_LOOKUP_FAILED: + case CACHE_EVENT_LOOKUP: + goto Lcancel_next; + + case CACHE_EVENT_OPEN_READ: + initial_event = event; + cancel_timeout(); + cache_action = 0; + cache_vc = (CacheVConnection*)data; + buffer = new_empty_MIOBuffer(); + buffer_reader = buffer->alloc_reader(); + if (open_read_callout() < 0) + goto Lclose_error_next; + else + return EVENT_DONE; + + case CACHE_EVENT_OPEN_READ_FAILED: + goto Lcancel_next; + + case VC_EVENT_READ_READY: + if (!check_buffer()) + goto Lclose_error_next; + buffer_reader->consume(buffer_reader->read_avail()); + ((VIO*)data)->reenable(); + return EVENT_CONT; + + case VC_EVENT_READ_COMPLETE: + if (!check_buffer()) + goto Lclose_error_next; + goto Lclose_next; + + case VC_EVENT_ERROR: + case VC_EVENT_EOS: + goto Lclose_error_next; + + case CACHE_EVENT_OPEN_WRITE: + initial_event = event; + cancel_timeout(); + cache_action = 0; + cache_vc = (CacheVConnection*)data; + buffer = new_empty_MIOBuffer(); + buffer_reader = buffer->alloc_reader(); + if (open_write_callout() < 0) + goto Lclose_error_next; + else + return EVENT_DONE; + + case CACHE_EVENT_OPEN_WRITE_FAILED: + goto Lcancel_next; + + case VC_EVENT_WRITE_READY: + fill_buffer(); + cvio->reenable(); + return EVENT_CONT; + + case VC_EVENT_WRITE_COMPLETE: + if (nbytes != cvio->ndone) + goto Lclose_error_next; + goto Lclose_next; + + case CACHE_EVENT_REMOVE: + case CACHE_EVENT_REMOVE_FAILED: + goto Lcancel_next; + + case CACHE_EVENT_SCAN: + initial_event = event; + cache_vc = (CacheVConnection*)data; + return EVENT_CONT; + + case CACHE_EVENT_SCAN_OBJECT: + return CACHE_SCAN_RESULT_CONTINUE; + + case CACHE_EVENT_SCAN_OPERATION_FAILED: + return CACHE_SCAN_RESULT_CONTINUE; + + case CACHE_EVENT_SCAN_OPERATION_BLOCKED: + return CACHE_SCAN_RESULT_CONTINUE; + + case CACHE_EVENT_SCAN_DONE: + return EVENT_CONT; + + case CACHE_EVENT_SCAN_FAILED: + return EVENT_CONT; + + case AIO_EVENT_DONE: + goto Lnext; + + default: + ink_assert(!"case"); + break; + } + return EVENT_DONE; + +Lcancel_next: + cancel_timeout(); + cache_action = 0; + goto Lnext; +Lclose_error_next: + cache_vc->do_io_close(1); + goto Lclose_next_internal; +Lclose_next: + cache_vc->do_io_close(); +Lclose_next_internal: + cache_vc = 0; + if (buffer_reader) { + buffer->dealloc_reader(buffer_reader); + buffer_reader = 0; + } + if (buffer) { + free_MIOBuffer(buffer); + buffer = 0; + } +Lnext: + if (check_result(event) && repeat_count) { + repeat_count--; + timeout = eventProcessor.schedule_imm(this); + return EVENT_DONE; + } else + return complete(event); +} + +void CacheTestSM::fill_buffer() { + int64_t avail = buffer->write_avail(); + CacheKey k = key; + k.b[1] += content_salt; + int64_t sk = (int64_t)sizeof(key); + while (avail > 0) { + int64_t l = avail; + if (l > sk) + l = sk; + + int64_t pos = cvio->ndone + buffer_reader->read_avail(); + int64_t o = pos % sk; + + if (l > sk - o) + l = sk - o; + k.b[0] = pos / sk; + char *x = ((char*)&k) + o; + buffer->write(x, l); + buffer->fill(l); + avail -= l; + } +} + +int CacheTestSM::check_buffer() { + int64_t avail = buffer_reader->read_avail(); + CacheKey k = key; + k.b[1] += content_salt; + char b[sizeof(key)]; + int64_t sk = (int64_t)sizeof(key); + int64_t pos = cvio->ndone - buffer_reader->read_avail(); + while (avail > 0) { + int64_t l = avail; + if (l > sk) + l = sk; + int64_t o = pos % sk; + if (l > sk - o) + l = sk - o; + k.b[0] = pos / sk; + char *x = ((char*)&k) + o; + buffer_reader->read(&b[0], l); + if (::memcmp(b, x, l)) + return 0; + buffer_reader->consume(l); + pos += l; + avail -= l; + } + return 1; +} + +int CacheTestSM::check_result(int event) { + return + initial_event == expect_initial_event && + event == expect_event; +} + +int CacheTestSM::complete(int event) { + if (!check_result(event)) + done(REGRESSION_TEST_FAILED); + else + done(REGRESSION_TEST_PASSED); + delete this; + return EVENT_DONE; +} + +CacheTestSM::CacheTestSM(const CacheTestSM &ao) : RegressionSM(ao) { + int o = (int)(((char*)&start_memcpy_on_clone) - ((char*)this)); + int s = (int)(((char*)&end_memcpy_on_clone) - ((char*)&start_memcpy_on_clone)); + memcpy(((char*)this)+o, ((char*)&ao)+o, s); + SET_HANDLER(&CacheTestSM::event_handler); +} + +EXCLUSIVE_REGRESSION_TEST(cache)(RegressionTest *t, int atype, int *pstatus) { + NOWARN_UNUSED(atype); + if (cacheProcessor.IsCacheEnabled() != CACHE_INITIALIZED) { + rprintf(t, "cache not initialized"); + *pstatus = REGRESSION_TEST_FAILED; + return; + } + + EThread *thread = this_ethread(); + + CACHE_SM(t, write_test, { cacheProcessor.open_write( + this, &key, CACHE_FRAG_TYPE_NONE, 100, + CACHE_WRITE_OPT_SYNC); } ); + write_test.expect_initial_event = CACHE_EVENT_OPEN_WRITE; + write_test.expect_event = VC_EVENT_WRITE_COMPLETE; + write_test.nbytes = 100; + rand_CacheKey(&write_test.key, thread->mutex); + + CACHE_SM(t, lookup_test, { cacheProcessor.lookup(this, &key); } ); + lookup_test.expect_event = CACHE_EVENT_LOOKUP; + lookup_test.key = write_test.key; + + CACHE_SM(t, read_test, { cacheProcessor.open_read(this, &key); } ); + read_test.expect_initial_event = CACHE_EVENT_OPEN_READ; + read_test.expect_event = VC_EVENT_READ_COMPLETE; + read_test.nbytes = 100; + read_test.key = write_test.key; + + CACHE_SM(t, remove_test, { cacheProcessor.remove(this, &key); } ); + remove_test.expect_event = CACHE_EVENT_REMOVE; + remove_test.key = write_test.key; + + CACHE_SM(t, lookup_fail_test, { cacheProcessor.lookup(this, &key); } ); + lookup_fail_test.expect_event = CACHE_EVENT_LOOKUP_FAILED; + lookup_fail_test.key = write_test.key; + + CACHE_SM(t, read_fail_test, { cacheProcessor.open_read(this, &key); } ); + read_fail_test.expect_event = CACHE_EVENT_OPEN_READ_FAILED; + read_fail_test.key = write_test.key; + + CACHE_SM(t, remove_fail_test, { cacheProcessor.remove(this, &key); } ); + remove_fail_test.expect_event = CACHE_EVENT_REMOVE_FAILED; + rand_CacheKey(&remove_fail_test.key, thread->mutex); + + CACHE_SM(t, replace_write_test, { + cacheProcessor.open_write(this, &key, CACHE_FRAG_TYPE_NONE, 100, + CACHE_WRITE_OPT_SYNC); + } + int open_write_callout() { + header.serial = 10; + cache_vc->set_header(&header, sizeof(header)); + cvio = cache_vc->do_io_write(this, nbytes, buffer_reader); + return 1; + }); + replace_write_test.expect_initial_event = CACHE_EVENT_OPEN_WRITE; + replace_write_test.expect_event = VC_EVENT_WRITE_COMPLETE; + replace_write_test.nbytes = 100; + rand_CacheKey(&replace_write_test.key, thread->mutex); + + CACHE_SM(t, replace_test, { + cacheProcessor.open_write(this, &key, CACHE_FRAG_TYPE_NONE, 100, + CACHE_WRITE_OPT_OVERWRITE_SYNC); + } + int open_write_callout() { + CacheTestHeader *h = 0; + int hlen = 0; + if (cache_vc->get_header((void**)&h, &hlen) < 0) + return -1; + if (h->serial != 10) + return -1; + header.serial = 11; + cache_vc->set_header(&header, sizeof(header)); + cvio = cache_vc->do_io_write(this, nbytes, buffer_reader); + return 1; + }); + replace_test.expect_initial_event = CACHE_EVENT_OPEN_WRITE; + replace_test.expect_event = VC_EVENT_WRITE_COMPLETE; + replace_test.nbytes = 100; + replace_test.key = replace_write_test.key; + replace_test.content_salt = 1; + + CACHE_SM(t, replace_read_test, { + cacheProcessor.open_read(this, &key); + } + int open_read_callout() { + CacheTestHeader *h = 0; + int hlen = 0; + if (cache_vc->get_header((void**)&h, &hlen) < 0) + return -1; + if (h->serial != 11) + return -1; + cvio = cache_vc->do_io_read(this, nbytes, buffer); + return 1; + }); + replace_read_test.expect_initial_event = CACHE_EVENT_OPEN_READ; + replace_read_test.expect_event = VC_EVENT_READ_COMPLETE; + replace_read_test.nbytes = 100; + replace_read_test.key = replace_test.key; + replace_read_test.content_salt = 1; + + CACHE_SM(t, large_write_test, { cacheProcessor.open_write( + this, &key, CACHE_FRAG_TYPE_NONE, 100, + CACHE_WRITE_OPT_SYNC); } ); + large_write_test.expect_initial_event = CACHE_EVENT_OPEN_WRITE; + large_write_test.expect_event = VC_EVENT_WRITE_COMPLETE; + large_write_test.nbytes = 10000000; + rand_CacheKey(&large_write_test.key, thread->mutex); + + CACHE_SM(t, pread_test, { + cacheProcessor.open_read(this, &key); + } + int open_read_callout() { + cvio = cache_vc->do_io_pread(this, nbytes, buffer, 7000000); + return 1; + }); + pread_test.expect_initial_event = CACHE_EVENT_OPEN_READ; + pread_test.expect_event = VC_EVENT_READ_COMPLETE; + pread_test.nbytes = 100; + pread_test.key = large_write_test.key; + + r_sequential( + t, + write_test.clone(), + lookup_test.clone(), + r_sequential(t, 10, read_test.clone()), + remove_test.clone(), + lookup_fail_test.clone(), + read_fail_test.clone(), + remove_fail_test.clone(), + replace_write_test.clone(), + replace_test.clone(), + replace_read_test.clone(), + large_write_test.clone(), + pread_test.clone(), + NULL_PTR + )->run(pstatus); + return; +} + +void force_link_CacheTest() { +} diff --git a/iocore/cache/CacheVol.cc b/iocore/cache/CacheVol.cc new file mode 100644 index 00000000..13855fb5 --- /dev/null +++ b/iocore/cache/CacheVol.cc @@ -0,0 +1,509 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +#include "P_Cache.h" + +#define SCAN_BUF_SIZE RECOVERY_SIZE +#define SCAN_WRITER_LOCK_MAX_RETRY 5 + +Action * +Cache::scan(Continuation * cont, char *hostname, int host_len, int KB_per_second) +{ + Debug("cache_scan_truss", "inside scan"); + if (!CACHE_READY(CACHE_FRAG_TYPE_HTTP)) { + cont->handleEvent(CACHE_EVENT_SCAN_FAILED, 0); + return ACTION_RESULT_DONE; + } + + CacheVC *c = new_CacheVC(cont); + c->vol = NULL; + /* do we need to make a copy */ + c->hostname = hostname; + c->host_len = host_len; + c->base_stat = cache_scan_active_stat; + c->buf = new_IOBufferData(BUFFER_SIZE_FOR_XMALLOC(SCAN_BUF_SIZE), MEMALIGNED); + c->scan_msec_delay = (SCAN_BUF_SIZE / KB_per_second); + c->offset = 0; + SET_CONTINUATION_HANDLER(c, &CacheVC::scanVol); + eventProcessor.schedule_in(c, HRTIME_MSECONDS(c->scan_msec_delay)); + cont->handleEvent(CACHE_EVENT_SCAN, c); + return &c->_action; +} + +int +CacheVC::scanVol(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + Debug("cache_scan_truss", "inside %p:scanVol", this); + if (_action.cancelled) + return free_CacheVC(this); + CacheHostRecord *rec = &theCache->hosttable->gen_host_rec; + if (host_len) { + CacheHostResult res; + theCache->hosttable->Match(hostname, host_len, &res); + if (res.record) + rec = res.record; + } + if (!vol) { + if (!rec->num_vols) + goto Ldone; + vol = rec->vols[0]; + } else { + for (int i = 0; i < rec->num_vols - 1; i++) + if (vol == rec->vols[i]) { + vol = rec->vols[i + 1]; + goto Lcont; + } + goto Ldone; + } +Lcont: + fragment = 0; + SET_HANDLER(&CacheVC::scanObject); + eventProcessor.schedule_in(this, HRTIME_MSECONDS(scan_msec_delay)); + return EVENT_CONT; +Ldone: + _action.continuation->handleEvent(CACHE_EVENT_SCAN_DONE, NULL); + return free_CacheVC(this); +} + +/* Next block with some data in it in this partition. Returns end of partition if no more + * locations. + * + * d - Vol + * vol_map - precalculated map + * offset - offset to start looking at (and data at this location has not been read yet). */ +static off_t next_in_map(Vol *d, char *vol_map, off_t offset) +{ + off_t start_offset = vol_offset_to_offset(d, 0); + off_t new_off = (offset - start_offset); + off_t vol_len = vol_relative_length(d, start_offset); + + while (new_off < vol_len && !vol_map[new_off / SCAN_BUF_SIZE]) new_off += SCAN_BUF_SIZE; + if (new_off >= vol_len) return vol_len + start_offset; + return new_off + start_offset; +} + +// Function in CacheDir.cc that we need for make_vol_map(). +int +dir_bucket_loop_fix(Dir *start_dir, int s, Vol *d); + +// TODO: If we used a bit vector, we could make a smaller map structure. +// TODO: If we saved a high water mark we could have a smaller buf, and avoid searching it +// when we are asked about the highest interesting offset. +/* Make map of what blocks in partition are used. + * + * d - Vol to make a map of. */ +static char *make_vol_map(Vol *d) +{ + // Map will be one byte for each SCAN_BUF_SIZE bytes. + off_t start_offset = vol_offset_to_offset(d, 0); + off_t vol_len = vol_relative_length(d, start_offset); + size_t map_len = (vol_len + (SCAN_BUF_SIZE - 1)) / SCAN_BUF_SIZE; + char *vol_map = (char *)xmalloc(map_len); + if (!vol_map) return NULL; + memset(vol_map, 0, map_len); + + // Scan directories. + // Copied from dir_entries_used() and modified to fill in the map instead. + for (int s = 0; s < d->segments; s++) { + Dir *seg = dir_segment(s, d); + for (int b = 0; b < d->buckets; b++) { + Dir *e = dir_bucket(b, seg); + if (dir_bucket_loop_fix(e, s, d)) { + break; + } + while (e) { + if (dir_offset(e)) { + off_t offset = vol_offset(d, e) - start_offset; + if (offset <= vol_len) vol_map[offset / SCAN_BUF_SIZE] = 1; + } + e = next_dir(e, seg); + if (!e) + break; + } + } + } + return vol_map; +} + +int +CacheVC::scanObject(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + Debug("cache_scan_truss", "inside %p:scanObject", this); + + Doc *doc = NULL; + void *result = NULL; +#ifdef HTTP_CACHE + int hlen = 0; + char hname[500]; + bool hostinfo_copied = false; +#endif + off_t next_object_len = 0; + bool might_need_overlap_read = false; + + cancel_trigger(); + set_io_not_in_progress(); + if (_action.cancelled) + return free_CacheVC(this); + + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) { + Debug("cache_scan_truss", "delay %p:scanObject", this); + mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay)); + return EVENT_CONT; + } + + if (!fragment) { // initialize for first read + fragment = 1; + scan_vol_map = make_vol_map(vol); + io.aiocb.aio_offset = next_in_map(vol, scan_vol_map, vol_offset_to_offset(vol, 0)); + if (io.aiocb.aio_offset >= (off_t)(vol->skip + vol->len)) + goto Ldone; + io.aiocb.aio_nbytes = SCAN_BUF_SIZE; + io.aiocb.aio_buf = buf->data(); + io.action = this; + io.thread = AIO_CALLBACK_THREAD_ANY; + Debug("cache_scan_truss", "read %p:scanObject", this); + goto Lread; + } + + if ((size_t)io.aio_result != (size_t) io.aiocb.aio_nbytes) { + result = (void *) -ECACHE_READ_FAIL; + goto Ldone; + } + + doc = (Doc *) (buf->data() + offset); + // If there is data in the buffer before the start that is from a partial object read previously + // Fix things as if we read it this time. + if (scan_fix_buffer_offset) { + io.aio_result += scan_fix_buffer_offset; + io.aiocb.aio_nbytes += scan_fix_buffer_offset; + io.aiocb.aio_offset -= scan_fix_buffer_offset; + io.aiocb.aio_buf = (char *)io.aiocb.aio_buf - scan_fix_buffer_offset; + scan_fix_buffer_offset = 0; + } + while ((off_t)((char *) doc - buf->data()) + next_object_len < (off_t)io.aiocb.aio_nbytes) { + might_need_overlap_read = false; + doc = (Doc *) ((char *) doc + next_object_len); + next_object_len = vol->round_to_approx_size(doc->len); +#ifdef HTTP_CACHE + int i; + bool changed; + + if (doc->magic != DOC_MAGIC) { + next_object_len = CACHE_BLOCK_SIZE; + Debug("cache_scan_truss", "blockskip %p:scanObject", this); + continue; + } + + if (doc->ftype != CACHE_FRAG_TYPE_HTTP || !doc->hlen) + goto Lskip; + + last_collision = NULL; + while (1) { + if (!dir_probe(&doc->first_key, vol, &dir, &last_collision)) + goto Lskip; + if (!dir_agg_valid(vol, &dir) || !dir_head(&dir) || + (vol_offset(vol, &dir) != io.aiocb.aio_offset + ((char *) doc - buf->data()))) + continue; + break; + } + if (doc->data() - buf->data() > (int) io.aiocb.aio_nbytes) { + might_need_overlap_read = true; + goto Lskip; + } + { + char *tmp = doc->hdr(); + int len = doc->hlen; + while (len > 0) { + int r = HTTPInfo::unmarshal(tmp, len, buf._ptr()); + if (r < 0) { + ink_assert(!"CacheVC::scanObject unmarshal failed"); + goto Lskip; + } + len -= r; + tmp += r; + } + } + if (vector.get_handles(doc->hdr(), doc->hlen) != doc->hlen) + goto Lskip; + changed = false; + hostinfo_copied = 0; + for (i = 0; i < vector.count(); i++) { + if (!vector.get(i)->valid()) + goto Lskip; + if (!hostinfo_copied) { + memccpy(hname, vector.get(i)->request_get()->url_get()->host_get(&hlen), 0, 500); + hname[hlen] = 0; + Debug("cache_scan", "hostname = '%s', hostlen = %d", hname, hlen); + hostinfo_copied = 1; + } + vector.get(i)->object_key_get(&key); + alternate_index = i; + // verify that the earliest block exists, reducing 'false hit' callbacks + if (!(key == doc->key)) { + last_collision = NULL; + if (!dir_probe(&key, vol, &earliest_dir, &last_collision)) + continue; + } + earliest_key = key; + int result1 = _action.continuation->handleEvent(CACHE_EVENT_SCAN_OBJECT, vector.get(i)); + switch (result1) { + case CACHE_SCAN_RESULT_CONTINUE: + continue; + case CACHE_SCAN_RESULT_DELETE: + changed = true; + vector.remove(i, true); + i--; + continue; + case CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES: + changed = true; + vector.clear(); + i = 0; + break; + case CACHE_SCAN_RESULT_UPDATE: + ink_debug_assert(alternate_index >= 0); + vector.insert(&alternate, alternate_index); + if (!vector.get(alternate_index)->valid()) + continue; + changed = true; + continue; + case EVENT_DONE: + goto Lcancel; + default: + ink_assert(!"unexpected CACHE_SCAN_RESULT"); + continue; + } + } + if (changed) { + if (!vector.count()) { + ink_debug_assert(hostinfo_copied); + SET_HANDLER(&CacheVC::scanRemoveDone); + // force remove even if there is a writer + cacheProcessor.remove(this, &doc->first_key, CACHE_FRAG_TYPE_HTTP, true, false, (char *) hname, hlen); + return EVENT_CONT; + } else { + offset = (char *) doc - buf->data(); + write_len = 0; + frag_type = CACHE_FRAG_TYPE_HTTP; + f.use_first_key = 1; + f.evac_vector = 1; + first_key = key = doc->first_key; + alternate_index = CACHE_ALT_REMOVED; + earliest_key = zero_key; + writer_lock_retry = 0; + SET_HANDLER(&CacheVC::scanOpenWrite); + return scanOpenWrite(EVENT_NONE, 0); + } + } + continue; + Lskip:; +#endif + } +#ifdef HTTP_CACHE + vector.clear(); +#endif + // If we had an object that went past the end of the buffer, and it is small enough to fix, + // fix it. + if (might_need_overlap_read && + ((off_t)((char *) doc - buf->data()) + next_object_len > (off_t)io.aiocb.aio_nbytes) && + next_object_len > 0) { + off_t partial_object_len = io.aiocb.aio_nbytes - ((char *)doc - buf->data()); + // Copy partial object to beginning of the buffer. + memmove(buf->data(), (char *)doc, partial_object_len); + io.aiocb.aio_offset += io.aiocb.aio_nbytes; + io.aiocb.aio_nbytes = SCAN_BUF_SIZE - partial_object_len; + io.aiocb.aio_buf = buf->data() + partial_object_len; + scan_fix_buffer_offset = partial_object_len; + } else { // Normal case, where we ended on a object boundary. + io.aiocb.aio_offset += ((char *)doc - buf->data()) + next_object_len; + Debug("cache_scan_truss", "next %p:scanObject %lld", this, io.aiocb.aio_offset); + io.aiocb.aio_offset = next_in_map(vol, scan_vol_map, io.aiocb.aio_offset); + Debug("cache_scan_truss", "next_in_map %p:scanObject %lld", this, io.aiocb.aio_offset); + io.aiocb.aio_nbytes = SCAN_BUF_SIZE; + io.aiocb.aio_buf = buf->data(); + scan_fix_buffer_offset = 0; + } + + if (io.aiocb.aio_offset >= vol->skip + vol->len) { + SET_HANDLER(&CacheVC::scanVol); + eventProcessor.schedule_in(this, HRTIME_MSECONDS(scan_msec_delay)); + return EVENT_CONT; + } + +Lread: + io.aiocb.aio_fildes = vol->fd; + if ((off_t)(io.aiocb.aio_offset + io.aiocb.aio_nbytes) > (off_t)(vol->skip + vol->len)) + io.aiocb.aio_nbytes = vol->skip + vol->len - io.aiocb.aio_offset; + offset = 0; + ink_assert(ink_aio_read(&io) >= 0); + Debug("cache_scan_truss", "read %p:scanObject %lld %lld", this, + (off_t)io.aiocb.aio_offset, (off_t)io.aiocb.aio_nbytes); + return EVENT_CONT; + +Ldone: + Debug("cache_scan_truss", "done %p:scanObject", this); + _action.continuation->handleEvent(CACHE_EVENT_SCAN_DONE, result); +#ifdef HTTP_CACHE +Lcancel: +#endif + return free_CacheVC(this); +} + +int +CacheVC::scanRemoveDone(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + Debug("cache_scan_truss", "inside %p:scanRemoveDone", this); + Debug("cache_scan", "remove done."); +#ifdef HTTP_CACHE + alternate.destroy(); +#endif + SET_HANDLER(&CacheVC::scanObject); + return handleEvent(EVENT_IMMEDIATE, 0); +} + +int +CacheVC::scanOpenWrite(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + Debug("cache_scan_truss", "inside %p:scanOpenWrite", this); + cancel_trigger(); + // get volume lock + if (writer_lock_retry > SCAN_WRITER_LOCK_MAX_RETRY) { + int r = _action.continuation->handleEvent(CACHE_EVENT_SCAN_OPERATION_BLOCKED, 0); + Debug("cache_scan", "still havent got the writer lock, asking user.."); + switch (r) { + case CACHE_SCAN_RESULT_RETRY: + writer_lock_retry = 0; + break; + case CACHE_SCAN_RESULT_CONTINUE: + SET_HANDLER(&CacheVC::scanObject); + return scanObject(EVENT_IMMEDIATE, 0); + } + } + int ret = 0; + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) { + Debug("cache_scan", "vol->mutex %p:scanOpenWrite", this); + VC_SCHED_LOCK_RETRY(); + } + + Debug("cache_scan", "trying for writer lock"); + if (vol->open_write(this, false, 1)) { + writer_lock_retry++; + SET_HANDLER(&CacheVC::scanOpenWrite); + mutex->thread_holding->schedule_in_local(this, scan_msec_delay); + return EVENT_CONT; + } + + ink_debug_assert(this->od); + // put all the alternates in the open directory vector + int alt_count = vector.count(); + for (int i = 0; i < alt_count; i++) { + write_vector->insert(vector.get(i)); + } + od->writing_vec = 1; + vector.clear(false); + // check that the directory entry was not overwritten + // if so return failure + Debug("cache_scan", "got writer lock"); + Dir *l = NULL; + Dir d; + Doc *doc = (Doc *) (buf->data() + offset); + offset = (char *) doc - buf->data() + vol->round_to_approx_size(doc->len); + // if the doc contains some data, then we need to create + // a new directory entry for this fragment. Remember the + // offset and the key in earliest_key + dir_assign(&od->first_dir, &dir); + if (doc->total_len) { + dir_assign(&od->single_doc_dir, &dir); + dir_set_tag(&od->single_doc_dir, doc->key.word(2)); + od->single_doc_key = doc->key; + od->move_resident_alt = 1; + } + + while (1) { + if (!dir_probe(&first_key, vol, &d, &l)) { + vol->close_write(this); + _action.continuation->handleEvent(CACHE_EVENT_SCAN_OPERATION_FAILED, 0); + SET_HANDLER(&CacheVC::scanObject); + return handleEvent(EVENT_IMMEDIATE, 0); + } + if (memcmp(&dir, &d, SIZEOF_DIR)) { + Debug("cache_scan", "dir entry has changed"); + continue; + } + break; + } + + // the document was not modified + // we are safe from now on as we hold the + // writer lock on the doc + if (f.evac_vector) + header_len = write_vector->marshal_length(); + SET_HANDLER(&CacheVC::scanUpdateDone); + ret = do_write_call(); + } + if (ret == EVENT_RETURN) + return handleEvent(AIO_EVENT_DONE, 0); + return ret; +} + +int +CacheVC::scanUpdateDone(int event, Event * e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + Debug("cache_scan_truss", "inside %p:scanUpdateDone", this); + cancel_trigger(); + // get volume lock + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (lock) { + // insert a directory entry for the previous fragment + dir_overwrite(&first_key, vol, &dir, &od->first_dir, false); + if (od->move_resident_alt) { + dir_insert(&od->single_doc_key, vol, &od->single_doc_dir); + } + ink_debug_assert(vol->open_read(&first_key)); + ink_debug_assert(this->od); + vol->close_write(this); + SET_HANDLER(&CacheVC::scanObject); + return handleEvent(EVENT_IMMEDIATE, 0); + } else { + mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay)); + return EVENT_CONT; + } +} + diff --git a/iocore/cache/CacheWrite.cc b/iocore/cache/CacheWrite.cc new file mode 100644 index 00000000..975c8991 --- /dev/null +++ b/iocore/cache/CacheWrite.cc @@ -0,0 +1,1825 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "P_Cache.h" + +#define IS_POWER_2(_x) (!((_x)&((_x)-1))) +#define UINT_WRAP_LTE(_x, _y) (((_y)-(_x)) < INT_MAX) // exploit overflow +#define UINT_WRAP_GTE(_x, _y) (((_x)-(_y)) < INT_MAX) // exploit overflow +#define UINT_WRAP_LT(_x, _y) (((_x)-(_y)) >= INT_MAX) // exploit overflow + +// Given a key, finds the index of the alternate which matches +// used to get the alternate which is actually present in the document +#ifdef HTTP_CACHE +int +get_alternate_index(CacheHTTPInfoVector *cache_vector, CacheKey key) +{ + int alt_count = cache_vector->count(); + CacheHTTPInfo *obj; + if (!alt_count) + return -1; + for (int i = 0; i < alt_count; i++) { + obj = cache_vector->get(i); + if (obj->compare_object_key(&key)) { + // Debug("cache_key", "Resident alternate key %X", key.word(0)); + return i; + } + } + return -1; +} + +// Adds/Deletes alternate to the od->vector (write_vector). If the vector +// is empty, deletes the directory entry pointing to the vector. Each +// CacheVC must write the vector down to disk after making changes. If we +// wait till the last writer, that writer will have the responsibility of +// of writing the vector even if the http state machine aborts. This +// makes it easier to handle situations where writers abort. +int +CacheVC::updateVector(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + if (od->reading_vec || od->writing_vec) + VC_SCHED_LOCK_RETRY(); + int ret = 0; + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock || od->writing_vec) + VC_SCHED_LOCK_RETRY(); + + int vec = alternate.valid(); + if (f.update) { + // all Update cases. Need to get the alternate index. + alternate_index = get_alternate_index(write_vector, update_key); + Debug("cache_update", "updating alternate index %d", alternate_index); + // if its an alternate delete + if (!vec) { + ink_assert(!total_len); + if (alternate_index >= 0) { + write_vector->remove(alternate_index, true); + alternate_index = CACHE_ALT_REMOVED; + if (!write_vector->count()) + dir_delete(&first_key, vol, &od->first_dir); + } + // the alternate is not there any more. somebody might have + // deleted it. Just close this writer + if (alternate_index != CACHE_ALT_REMOVED || !write_vector->count()) { + SET_HANDLER(&CacheVC::openWriteCloseDir); + return openWriteCloseDir(EVENT_IMMEDIATE, 0); + } + } + if (update_key == od->single_doc_key && (total_len || !vec)) + od->move_resident_alt = 0; + } + if (cache_config_http_max_alts > 1 && write_vector->count() >= cache_config_http_max_alts && alternate_index < 0) { + if (od->move_resident_alt && get_alternate_index(write_vector, od->single_doc_key) == 0) + od->move_resident_alt = 0; + write_vector->remove(0, true); + } + if (vec) + alternate_index = write_vector->insert(&alternate, alternate_index); + + if (od->move_resident_alt && first_buf._ptr() && !od->has_multiple_writers()) { + Doc *doc = (Doc *) first_buf->data(); + int small_doc = (int64_t)doc->data_len() < (int64_t)cache_config_alt_rewrite_max_size; + int have_res_alt = doc->key == od->single_doc_key; + // if the new alternate is not written with the vector + // then move the old one with the vector + // if its a header only update move the resident alternate + // with the vector. + // We are sure that the body of the resident alternate that we are + // rewriting has not changed and the alternate is not being deleted, + // since we set od->move_resident_alt to 0 in that case + // (in updateVector) + if (small_doc && have_res_alt && (fragment || (f.update && !total_len))) { + // for multiple fragment document, we must have done + // CacheVC:openWriteCloseDataDone + ink_assert(!fragment || f.data_done); + od->move_resident_alt = 0; + f.rewrite_resident_alt = 1; + write_len = doc->data_len(); + Debug("cache_update_alt", + "rewriting resident alt size: %d key: %X, first_key: %X", write_len, doc->key.word(0), first_key.word(0)); + } + } + header_len = write_vector->marshal_length(); + od->writing_vec = 1; + f.use_first_key = 1; + SET_HANDLER(&CacheVC::openWriteCloseHeadDone); + ret = do_write_call(); + } + if (ret == EVENT_RETURN) + return handleEvent(AIO_EVENT_DONE, 0); + return ret; +} +#endif +/* + The following fields of the CacheVC are used when writing down a fragment. + Make sure that each of the fields is set to a valid value before calling + this function + - frag_type. Checked to see if a vector needs to be marshalled. + - f.use_first_key. To decide if the vector should be marshalled and to set + the doc->key to the appropriate key (first_key or earliest_key) + - f.evac_vector. If set, the writer is pushed in the beginning of the + agg queue. And if !f.evac_vector && !f.update the alternate->object_size + is set to vc->total_len + - f.readers. If set, assumes that this is an evacuation, so the write + is not aborted even if vol->agg_todo_size > agg_write_backlog + - f.evacuator. If this is an evacuation. + - f.rewrite_resident_alt. The resident alternate is rewritten. + - f.update. Used only if the write_vector needs to be written to disk. + Used to set the length of the alternate to total_len. + - write_vector. Used only if frag_type == CACHE_FRAG_TYPE_HTTP && + (f.use_fist_key || f.evac_vector) is set. Write_vector is written to disk + - alternate_index. Used only if write_vector needs to be written to disk. + Used to find out the VC's alternate in the write_vector and set its + length to tatal_len. + - write_len. The number of bytes for this fragment. + - total_len. The total number of bytes for the document so far. + Doc->total_len and alternate's total len is set to this value. + - first_key. Doc's first_key is set to this value. + - pin_in_cache. Doc's pinned value is set to this + ink_get_hrtime(). + - earliest_key. If f.use_first_key, Doc's key is set to this value. + - key. If !f.use_first_key, Doc's key is set to this value. + - blocks. Used only if write_len is set. Data to be written + - offset. Used only if write_len is set. offset into the block to copy + the data from. + - buf. Used only if f.evacuator is set. Should point to the old document. + The functions sets the length, offset, pinned, head and phase of vc->dir. + */ + +int +CacheVC::handleWrite(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + // plain write case + ink_assert(!trigger); + if (f.use_first_key && fragment) { + frag_len = (fragment-1) * sizeof(Frag); + } else + frag_len = 0; + set_agg_write_in_progress(); + POP_HANDLER; + agg_len = vol->round_to_approx_size(write_len + header_len + frag_len + sizeofDoc); + vol->agg_todo_size += agg_len; + bool agg_error = + (agg_len > AGG_SIZE || header_len + sizeofDoc > MAX_FRAG_SIZE || + (!f.readers && (vol->agg_todo_size > cache_config_agg_write_backlog + AGG_SIZE) && write_len)); +#ifdef CACHE_AGG_FAIL_RATE + agg_error = agg_error || ((uint32_t) mutex->thread_holding->generator.random() < + (uint32_t) (UINT_MAX * CACHE_AGG_FAIL_RATE)); +#endif + bool max_doc_error = (cache_config_max_doc_size && + (cache_config_max_doc_size < vio.ndone || + (vio.nbytes != INT64_MAX && (cache_config_max_doc_size < vio.nbytes)))); + + if (agg_error || max_doc_error) { + CACHE_INCREMENT_DYN_STAT(cache_write_backlog_failure_stat); + CACHE_INCREMENT_DYN_STAT(base_stat + CACHE_STAT_FAILURE); + vol->agg_todo_size -= agg_len; + io.aio_result = AIO_SOFT_FAILURE; + if (event == EVENT_CALL) + return EVENT_RETURN; + return handleEvent(AIO_EVENT_DONE, 0); + } + ink_assert(agg_len <= AGG_SIZE); + if (f.evac_vector) + vol->agg.push(this); + else + vol->agg.enqueue(this); + if (!vol->is_io_in_progress()) + return vol->aggWrite(event, this); + return EVENT_CONT; +} + +static char * +iobufferblock_memcpy(char *p, int len, IOBufferBlock *ab, int offset) +{ + IOBufferBlock *b = ab; + while (b && len >= 0) { + char *start = b->_start; + char *end = b->_end; + int max_bytes = end - start; + max_bytes -= offset; + if (max_bytes <= 0) { + offset = -max_bytes; + b = b->next; + continue; + } + int bytes = len; + if (bytes >= max_bytes) + bytes = max_bytes; + ::memcpy(p, start + offset, bytes); + p += bytes; + len -= bytes; + b = b->next; + offset = 0; + } + return p; +} + +EvacuationBlock * +Vol::force_evacuate_head(Dir *evac_dir, int pinned) +{ + // build an evacuation block for the object + EvacuationBlock *b = evacuation_block_exists(evac_dir, this); + // if we have already started evacuating this document, its too late + // to evacuate the head...bad luck + if (b && b->f.done) + return b; + + if (!b) { + b = new_EvacuationBlock(mutex->thread_holding); + b->dir = *evac_dir; + DDebug("cache_evac", "force: %d, %d", (int) dir_offset(evac_dir), (int) dir_phase(evac_dir)); + evacuate[dir_evac_bucket(evac_dir)].push(b); + } + b->f.pinned = pinned; + b->f.evacuate_head = 1; + b->evac_frags.key.set(0, 0); // ensure that the block gets + // evacuated no matter what + b->readers = 0; // ensure that the block does not disappear + return b; +} + +void +Vol::scan_for_pinned_documents() +{ + if (cache_config_permit_pinning) { + // we can't evacuate anything between header->write_pos and + // header->write_pos + AGG_SIZE. + int ps = offset_to_vol_offset(this, header->write_pos + AGG_SIZE); + int pe = offset_to_vol_offset(this, header->write_pos + 2 * EVACUATION_SIZE + (len / PIN_SCAN_EVERY)); + int vol_end_offset = offset_to_vol_offset(this, len + skip); + int before_end_of_vol = pe < vol_end_offset; + DDebug("cache_evac", "scan %d %d", ps, pe); + for (int i = 0; i < vol_direntries(this); i++) { + // is it a valid pinned object? + if (!dir_is_empty(&dir[i]) && dir_pinned(&dir[i]) && dir_head(&dir[i])) { + // select objects only within this PIN_SCAN region + int o = dir_offset(&dir[i]); + if (dir_phase(&dir[i]) == header->phase) { + if (before_end_of_vol || o >= (pe - vol_end_offset)) + continue; + } else { + if (o= pe) + continue; + } + force_evacuate_head(&dir[i], 1); + // DDebug("cache_evac", "scan pinned at offset %d %d %d %d %d %d", + // (int)dir_offset(&b->dir), ps, o , pe, i, (int)b->f.done); + } + } + } +} + +/* NOTE:: This state can be called by an AIO thread, so DON'T DON'T + DON'T schedule any events on this thread using VC_SCHED_XXX or + mutex->thread_holding->schedule_xxx_local(). ALWAYS use + eventProcessor.schedule_xxx(). + */ +int +Vol::aggWriteDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + + // ensure we have the cacheDirSync lock if we intend to call it later + // retaking the current mutex recursively is a NOOP + CACHE_TRY_LOCK(lock, dir_sync_waiting ? cacheDirSync->mutex : mutex, mutex->thread_holding); + if (!lock) { + eventProcessor.schedule_in(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay)); + return EVENT_CONT; + } + if (io.ok()) { + header->last_write_pos = header->write_pos; + header->write_pos += io.aiocb.aio_nbytes; + ink_assert(header->write_pos >= start); + DDebug("cache_agg", "Dir %s, Write: %" PRIu64 ", last Write: %" PRIu64 "\n", + hash_id, header->write_pos, header->last_write_pos); + ink_assert(header->write_pos == header->agg_pos); + if (header->write_pos + EVACUATION_SIZE > scan_pos) + periodic_scan(); + agg_buf_pos = 0; + header->write_serial++; + } else { + // delete all the directory entries that we inserted + // for fragments is this aggregation buffer + Debug("cache_disk_error", "Write error on disk %s\n \ + write range : [%" PRIu64 " - %" PRIu64 " bytes] [%" PRIu64 " - %" PRIu64 " blocks] \n", + hash_id, io.aiocb.aio_offset, io.aiocb.aio_offset + io.aiocb.aio_nbytes, + io.aiocb.aio_offset / CACHE_BLOCK_SIZE, + (io.aiocb.aio_offset + io.aiocb.aio_nbytes) / CACHE_BLOCK_SIZE); + Dir del_dir; + dir_clear(&del_dir); + for (int done = 0; done < agg_buf_pos;) { + Doc *doc = (Doc *) (agg_buffer + done); + dir_set_offset(&del_dir, header->write_pos + done); + dir_delete(&doc->key, this, &del_dir); + done += round_to_approx_size(doc->len); + } + agg_buf_pos = 0; + } + set_io_not_in_progress(); + // callback ready sync CacheVCs + CacheVC *c = 0; + while ((c = sync.dequeue())) { + if (UINT_WRAP_LTE(c->write_serial + 2, header->write_serial)) + c->initial_thread->schedule_imm_signal(c, AIO_EVENT_DONE); + else { + sync.push(c); // put it back on the front + break; + } + } + if (dir_sync_waiting) { + dir_sync_waiting = 0; + cacheDirSync->handleEvent(EVENT_IMMEDIATE, 0); + } + if (agg.head || sync.head) + return aggWrite(event, e); + return EVENT_CONT; +} + +CacheVC * +new_DocEvacuator(int nbytes, Vol *vol) +{ + CacheVC *c = new_CacheVC(vol); + ProxyMutex *mutex = vol->mutex; + c->base_stat = cache_evacuate_active_stat; + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE); + c->buf = new_IOBufferData(iobuffer_size_to_index(nbytes, MAX_BUFFER_SIZE_INDEX), MEMALIGNED); + c->vol = vol; + c->f.evacuator = 1; + c->earliest_key = zero_key; + SET_CONTINUATION_HANDLER(c, &CacheVC::evacuateDocDone); + return c; +} + +int +CacheVC::evacuateReadHead(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + // The evacuator vc shares the lock with the volition mutex + ink_debug_assert(vol->mutex->thread_holding == this_ethread()); + cancel_trigger(); + Doc *doc = (Doc *) buf->data(); +#ifdef HTTP_CACHE + CacheHTTPInfo *alternate_tmp = 0; +#endif + if (!io.ok()) + goto Ldone; + // a directory entry which is nolonger valid may have been overwritten + if (!dir_valid(vol, &dir)) { + last_collision = NULL; + goto Lcollision; + } + if (doc->magic != DOC_MAGIC || !(doc->first_key == first_key)) + goto Lcollision; +#ifdef HTTP_CACHE + alternate_tmp = 0; + if (doc->ftype == CACHE_FRAG_TYPE_HTTP && doc->hlen) { + // its an http document + if (vector.get_handles(doc->hdr(), doc->hlen) != doc->hlen) { + Note("bad vector detected during evacuation"); + goto Ldone; + } + alternate_index = get_alternate_index(&vector, earliest_key); + if (alternate_index < 0) + goto Ldone; + alternate_tmp = vector.get(alternate_index); + doc_len = alternate_tmp->object_size_get(); + Debug("cache_evac", "evacuateReadHead http earliest %X first: %X len: %d", + first_key.word(0), earliest_key.word(0), doc_len); + } else +#endif + { + // non-http document + CacheKey next_key; + next_CacheKey(&next_key, &doc->key); + if (!(next_key == earliest_key)) + goto Ldone; + doc_len = doc->total_len; + DDebug("cache_evac", + "evacuateReadHead non-http earliest %X first: %X len: %d", first_key.word(0), earliest_key.word(0), doc_len); + } + if (doc_len == total_len) { + // the whole document has been evacuated. Insert the directory + // entry in the directory. + dir_lookaside_fixup(&earliest_key, vol); + return free_CacheVC(this); + } + return EVENT_CONT; +Lcollision: + if (dir_probe(&first_key, vol, &dir, &last_collision)) { + int ret = do_read_call(&first_key); + if (ret == EVENT_RETURN) + return handleEvent(AIO_EVENT_DONE, 0); + return ret; + } +Ldone: + dir_lookaside_remove(&earliest_key, vol); + return free_CacheVC(this); +} + +int +CacheVC::evacuateDocDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + ink_debug_assert(vol->mutex->thread_holding == this_ethread()); + Doc *doc = (Doc *) buf->data(); + DDebug("cache_evac", "evacuateDocDone %X o %d p %d new_o %d new_p %d", + (int) key.word(0), (int) dir_offset(&overwrite_dir), + (int) dir_phase(&overwrite_dir), (int) dir_offset(&dir), (int) dir_phase(&dir)); + int i = dir_evac_bucket(&overwrite_dir); + // nasty beeping race condition, need to have the EvacuationBlock here + EvacuationBlock *b = vol->evacuate[i].head; + for (; b; b = b->link.next) { + if (dir_offset(&b->dir) == dir_offset(&overwrite_dir)) { + + // If the document is single fragment (although not tied to the vector), + // then we don't have to put the directory entry in the lookaside + // buffer. But, we have no way of finding out if the document is + // single fragment. doc->single_fragment() can be true for a multiple + // fragment document since total_len and doc->len could be equal at + // the time we write the fragment down. To be on the safe side, we + // only overwrite the entry in the directory if its not a head. + if (!dir_head(&overwrite_dir)) { + // find the earliest key + EvacuationKey *evac = &b->evac_frags; + for (; evac && !(evac->key == doc->key); evac = evac->link.next); + ink_assert(evac); + if (!evac) + break; + if (evac->earliest_key.fold()) { + DDebug("cache_evac", "evacdocdone: evacuating key %X earliest %X", + evac->key.word(0), evac->earliest_key.word(0)); + EvacuationBlock *eblock = 0; + Dir dir_tmp; + dir_lookaside_probe(&evac->earliest_key, vol, &dir_tmp, &eblock); + if (eblock) { + CacheVC *earliest_evac = eblock->earliest_evacuator; + earliest_evac->total_len += doc->data_len(); + if (earliest_evac->total_len == earliest_evac->doc_len) { + dir_lookaside_fixup(&evac->earliest_key, vol); + free_CacheVC(earliest_evac); + } + } + } + dir_overwrite(&doc->key, vol, &dir, &overwrite_dir); + } + // if the tag in the overwrite_dir matches the first_key in the + // document, then it has to be the vector. We gaurantee that + // the first_key and the earliest_key will never collide (see + // Cache::open_write). Once we know its the vector, we can + // safely overwrite the first_key in the directory. + if (dir_head(&overwrite_dir) && b->f.evacuate_head) { + DDebug("cache_evac", + "evacuateDocDone evacuate_head %X %X hlen %d offset %d", + (int) key.word(0), (int) doc->key.word(0), doc->hlen, (int) dir_offset(&overwrite_dir)); + + if (dir_compare_tag(&overwrite_dir, &doc->first_key)) { + OpenDirEntry *cod; + DDebug("cache_evac", "evacuating vector: %X %d", + (int) doc->first_key.word(0), (int) dir_offset(&overwrite_dir)); + if ((cod = vol->open_read(&doc->first_key))) { + // writer exists + DDebug("cache_evac", "overwriting the open directory %X %d %d", + (int) doc->first_key.word(0), (int) dir_offset(&cod->first_dir), (int) dir_offset(&dir)); + ink_assert(dir_pinned(&dir)); + cod->first_dir = dir; + + } + if (dir_overwrite(&doc->first_key, vol, &dir, &overwrite_dir)) { + vol->ram_cache->fixup(&doc->first_key, 0, dir_offset(&overwrite_dir), 0, dir_offset(&dir)); + } + } else { + DDebug("cache_evac", "evacuating earliest: %X %d", (int) doc->key.word(0), (int) dir_offset(&overwrite_dir)); + ink_debug_assert(dir_compare_tag(&overwrite_dir, &doc->key)); + ink_assert(b->earliest_evacuator == this); + total_len += doc->data_len(); + first_key = doc->first_key; + earliest_dir = dir; + if (dir_probe(&first_key, vol, &dir, &last_collision) > 0) { + dir_lookaside_insert(b, vol, &earliest_dir); + // read the vector + SET_HANDLER(&CacheVC::evacuateReadHead); + int ret = do_read_call(&first_key); + if (ret == EVENT_RETURN) + return handleEvent(AIO_EVENT_DONE, 0); + return ret; + } + } + } + break; + } + } + return free_CacheVC(this); +} + +static int +evacuate_fragments(CacheKey *key, CacheKey *earliest_key, int force, Vol *vol) +{ + Dir dir, *last_collision = 0; + int i = 0; + while (dir_probe(key, vol, &dir, &last_collision)) { + // next fragment cannot be a head...if it is, it must have been a + // directory collision. + if (dir_head(&dir)) + continue; + EvacuationBlock *b = evacuation_block_exists(&dir, vol); + if (!b) { + b = new_EvacuationBlock(vol->mutex->thread_holding); + b->dir = dir; + b->evac_frags.key = *key; + b->evac_frags.earliest_key = *earliest_key; + vol->evacuate[dir_evac_bucket(&dir)].push(b); + i++; + } else { + ink_assert(dir_offset(&dir) == dir_offset(&b->dir)); + ink_assert(dir_phase(&dir) == dir_phase(&b->dir)); + EvacuationKey *evac_frag = evacuationKeyAllocator.alloc(); + evac_frag->key = *key; + evac_frag->earliest_key = *earliest_key; + evac_frag->link.next = b->evac_frags.link.next; + b->evac_frags.link.next = evac_frag; + } + if (force) + b->readers = 0; + DDebug("cache_evac", + "next fragment %X Earliest: %X offset %d phase %d force %d", + (int) key->word(0), (int) earliest_key->word(0), (int) dir_offset(&dir), (int) dir_phase(&dir), force); + } + return i; +} + +int +Vol::evacuateWrite(CacheVC *evacuator, int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + // push to front of aggregation write list, so it is written first + + evacuator->agg_len = round_to_approx_size(((Doc *)evacuator->buf->data())->len); + agg_todo_size += evacuator->agg_len; + /* insert the evacuator after all the other evacuators */ + CacheVC *cur = (CacheVC *) agg.head; + CacheVC *after = NULL; + for (; cur && cur->f.evacuator; cur = (CacheVC *) cur->link.next) + after = cur; + ink_assert(evacuator->agg_len <= AGG_SIZE); + agg.insert(evacuator, after); + return aggWrite(event, e); +} + +int +Vol::evacuateDocReadDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + + cancel_trigger(); + if (event != AIO_EVENT_DONE) + return EVENT_DONE; + ink_assert(is_io_in_progress()); + set_io_not_in_progress(); + ink_debug_assert(mutex->thread_holding == this_ethread()); + Doc *doc = (Doc *) doc_evacuator->buf->data(); + CacheKey next_key; + EvacuationBlock *b = NULL; + if (doc->magic != DOC_MAGIC) { + Debug("cache_evac", "DOC magic: %X %d", + (int) dir_tag(&doc_evacuator->overwrite_dir), (int) dir_offset(&doc_evacuator->overwrite_dir)); + ink_assert(doc->magic == DOC_MAGIC); + goto Ldone; + } + DDebug("cache_evac", "evacuateDocReadDone %X offset %d", + (int) doc->key.word(0), (int) dir_offset(&doc_evacuator->overwrite_dir)); + + b = evacuate[dir_evac_bucket(&doc_evacuator->overwrite_dir)].head; + while (b) { + if (dir_offset(&b->dir) == dir_offset(&doc_evacuator->overwrite_dir)) + break; + b = b->link.next; + } + if (!b) + goto Ldone; + if ((b->f.pinned && !b->readers) && doc->pinned < (uint32_t) (ink_get_based_hrtime() / HRTIME_SECOND)) + goto Ldone; + + if (dir_head(&b->dir) && b->f.evacuate_head) { + ink_assert(!b->evac_frags.key.fold()); + // if its a head (vector), evacuation is real simple...we just + // need to write this vector down and overwrite the directory entry. + if (dir_compare_tag(&b->dir, &doc->first_key)) { + doc_evacuator->key = doc->first_key; + b->evac_frags.key = doc->first_key; + DDebug("cache_evac", "evacuating vector %X offset %d", + (int) doc->first_key.word(0), (int) dir_offset(&doc_evacuator->overwrite_dir)); + b->f.unused = 57; + } else { + // if its an earliest fragment (alternate) evacuation, things get + // a little tricky. We have to propagate the earliest key to the next + // fragments for this alternate. The last fragment to be evacuated + // fixes up the lookaside buffer. + doc_evacuator->key = doc->key; + doc_evacuator->earliest_key = doc->key; + b->evac_frags.key = doc->key; + b->evac_frags.earliest_key = doc->key; + b->earliest_evacuator = doc_evacuator; + DDebug("cache_evac", "evacuating earliest %X %X evac: %X offset: %d", + (int) b->evac_frags.key.word(0), (int) doc->key.word(0), + doc_evacuator, (int) dir_offset(&doc_evacuator->overwrite_dir)); + b->f.unused = 67; + } + } else { + // find which key matches the document + EvacuationKey *ek = &b->evac_frags; + for (; ek && !(ek->key == doc->key); ek = ek->link.next); + if (!ek) { + b->f.unused = 77; + goto Ldone; + } + doc_evacuator->key = ek->key; + doc_evacuator->earliest_key = ek->earliest_key; + DDebug("cache_evac", "evacuateDocReadDone key: %X earliest: %X", + (int) ek->key.word(0), (int) ek->earliest_key.word(0)); + b->f.unused = 87; + } + // if the tag in the c->dir does match the first_key in the + // document, then it has to be the earliest fragment. We gaurantee that + // the first_key and the earliest_key will never collide (see + // Cache::open_write). + if (!dir_head(&b->dir) || !dir_compare_tag(&b->dir, &doc->first_key)) { + next_CacheKey(&next_key, &doc->key); + evacuate_fragments(&next_key, &doc_evacuator->earliest_key, !b->readers, this); + } + return evacuateWrite(doc_evacuator, event, e); +Ldone: + free_CacheVC(doc_evacuator); + doc_evacuator = 0; + return aggWrite(event, e); +} + +int +Vol::evac_range(off_t low, off_t high, int evac_phase) +{ + int s = offset_to_vol_offset(this, low); + int e = offset_to_vol_offset(this, high); + int si = dir_offset_evac_bucket(s); + int ei = dir_offset_evac_bucket(e); + + for (int i = si; i <= ei; i++) { + EvacuationBlock *b = evacuate[i].head; + EvacuationBlock *first = 0; + int first_offset = INT_MAX; + for (; b; b = b->link.next) { + int64_t offset = dir_offset(&b->dir); + int phase = dir_phase(&b->dir); + if (offset >= s && offset < e && !b->f.done && phase == evac_phase) + if (offset < first_offset) { + first = b; + first_offset = offset; + } + } + if (first) { + first->f.done = 1; + io.aiocb.aio_fildes = fd; + io.aiocb.aio_nbytes = dir_approx_size(&first->dir); + io.aiocb.aio_offset = vol_offset(this, &first->dir); + if ((off_t)(io.aiocb.aio_offset + io.aiocb.aio_nbytes) > (off_t)(skip + len)) + io.aiocb.aio_nbytes = skip + len - io.aiocb.aio_offset; + doc_evacuator = new_DocEvacuator(io.aiocb.aio_nbytes, this); + doc_evacuator->overwrite_dir = first->dir; + + io.aiocb.aio_buf = doc_evacuator->buf->data(); + io.action = this; + io.thread = AIO_CALLBACK_THREAD_ANY; + DDebug("cache_evac", "evac_range evacuating %X %d", (int)dir_tag(&first->dir), (int)dir_offset(&first->dir)); + SET_HANDLER(&Vol::evacuateDocReadDone); + ink_assert(ink_aio_read(&io) >= 0); + return -1; + } + } + return 0; +} + + +static int +agg_copy(char *p, CacheVC *vc) +{ + Vol *vol = vc->vol; + off_t o = vol->header->write_pos + vol->agg_buf_pos; + + if (!vc->f.evacuator) { + Doc *doc = (Doc *) p; + IOBufferBlock *res_alt_blk = 0; + + uint32_t len = vc->write_len + vc->header_len + vc->frag_len + sizeofDoc; + ink_assert(vc->frag_type != CACHE_FRAG_TYPE_HTTP || len != sizeofDoc); + ink_debug_assert(vol->round_to_approx_size(len) == vc->agg_len); + // update copy of directory entry for this document + dir_set_approx_size(&vc->dir, vc->agg_len); + dir_set_offset(&vc->dir, offset_to_vol_offset(vol, o)); + ink_assert(vol_offset(vol, &vc->dir) < (vol->skip + vol->len)); + dir_set_phase(&vc->dir, vol->header->phase); + + // fill in document header + doc->magic = DOC_MAGIC; + doc->len = len; + doc->hlen = vc->header_len; + doc->ftype = vc->frag_type; + doc->flen = vc->frag_len; + doc->total_len = vc->total_len; + doc->first_key = vc->first_key; + doc->sync_serial = vol->header->sync_serial; + vc->write_serial = doc->write_serial = vol->header->write_serial; + doc->checksum = DOC_NO_CHECKSUM; + if (vc->pin_in_cache) { + dir_set_pinned(&vc->dir, 1); + doc->pinned = (uint32_t) (ink_get_based_hrtime() / HRTIME_SECOND) + vc->pin_in_cache; + } else { + dir_set_pinned(&vc->dir, 0); + doc->pinned = 0; + } + + if (vc->f.use_first_key) { + if (doc->data_len()) + doc->key = vc->earliest_key; + else { + // the vector is being written by itself + prev_CacheKey(&doc->key, &vc->earliest_key); + } + dir_set_head(&vc->dir, true); + } else { + doc->key = vc->key; + dir_set_head(&vc->dir, !vc->fragment); + } + if (doc->flen) + memcpy(doc->frags(), &vc->frag[0], doc->flen); + +#ifdef HTTP_CACHE + if (vc->f.rewrite_resident_alt) { + ink_assert(vc->f.use_first_key); + Doc *res_doc = (Doc *) vc->first_buf->data(); + res_alt_blk = new_IOBufferBlock(vc->first_buf, res_doc->data_len(), sizeofDoc + res_doc->hlen); + doc->key = res_doc->key; + doc->total_len = res_doc->data_len(); + } +#endif + // update the new_info object_key, and total_len and dirinfo + if (vc->header_len) { + ink_debug_assert(vc->f.use_first_key); +#ifdef HTTP_CACHE + if (vc->frag_type == CACHE_FRAG_TYPE_HTTP) { + ink_debug_assert(vc->write_vector->count() > 0); + if (!vc->f.update && !vc->f.evac_vector) { + ink_debug_assert(!(vc->first_key == zero_key)); + CacheHTTPInfo *http_info = vc->write_vector->get(vc->alternate_index); + http_info->object_size_set(vc->total_len); + } + // update + data_written => Update case (b) + // need to change the old alternate's object length + if (vc->f.update && vc->total_len) { + CacheHTTPInfo *http_info = vc->write_vector->get(vc->alternate_index); + http_info->object_size_set(vc->total_len); + } + ink_assert(!(((uintptr_t) &doc->hdr()[0]) & HDR_PTR_ALIGNMENT_MASK)); + ink_assert(vc->header_len == vc->write_vector->marshal(doc->hdr(), vc->header_len)); + } else +#endif + memcpy(doc->hdr(), vc->header_to_write, vc->header_len); + // the single fragment flag is not used in the write call. + // putting it in for completeness. + vc->f.single_fragment = doc->single_fragment(); + } + // move data + if (vc->write_len) { + { + ProxyMutex RELEASE_UNUSED *mutex = vc->vol->mutex; + ink_debug_assert(mutex->thread_holding == this_ethread()); + CACHE_DEBUG_SUM_DYN_STAT(cache_write_bytes_stat, vc->write_len); + } +#ifdef HTTP_CACHE + if (vc->f.rewrite_resident_alt) + iobufferblock_memcpy(doc->data(), vc->write_len, res_alt_blk, 0); + else +#endif + iobufferblock_memcpy(doc->data(), vc->write_len, vc->blocks, vc->offset); +#ifdef VERIFY_JTEST_DATA + if (f.use_first_key && header_len) { + int ib = 0, xd = 0; + char xx[500]; + new_info.request_get().url_get().print(xx, 500, &ib, &xd); + char *x = xx; + for (int q = 0; q < 3; q++) + x = strchr(x + 1, '/'); + ink_assert(!memcmp(doc->hdr(), x, ib - (x - xx))); + } +#endif + + } + if (cache_config_enable_checksum) { + doc->checksum = 0; + for (char *b = doc->hdr(); b < (char *) doc + doc->len; b++) + doc->checksum += *b; + } + if (vc->frag_type == CACHE_FRAG_TYPE_HTTP && vc->f.single_fragment) + ink_assert(doc->hlen); + + if (res_alt_blk) + res_alt_blk->free(); + + return vc->agg_len; + } else { + // for evacuated documents, copy the data, and update directory + Doc *doc = (Doc *) vc->buf->data(); + int l = vc->vol->round_to_approx_size(doc->len); + { + ProxyMutex RELEASE_UNUSED *mutex = vc->vol->mutex; + ink_debug_assert(mutex->thread_holding == this_ethread()); + CACHE_DEBUG_INCREMENT_DYN_STAT(cache_gc_frags_evacuated_stat); + CACHE_DEBUG_SUM_DYN_STAT(cache_gc_bytes_evacuated_stat, l); + } + doc->sync_serial = vc->vol->header->sync_serial; + doc->write_serial = vc->vol->header->write_serial; + + memcpy(p, doc, doc->len); + + vc->dir = vc->overwrite_dir; + dir_set_offset(&vc->dir, offset_to_vol_offset(vc->vol, o)); + dir_set_phase(&vc->dir, vc->vol->header->phase); + + return l; + } +} + +inline void +Vol::evacuate_cleanup_blocks(int i) +{ + EvacuationBlock *b = evacuate[i].head; + while (b) { + if (b->f.done && + ((header->phase != dir_phase(&b->dir) && + header->write_pos > vol_offset(this, &b->dir)) || + (header->phase == dir_phase(&b->dir) && header->write_pos <= vol_offset(this, &b->dir)))) { + EvacuationBlock *x = b; + DDebug("cache_evac", "evacuate cleanup free %X offset %d", + (int) b->evac_frags.key.word(0), (int) dir_offset(&b->dir)); + b = b->link.next; + evacuate[i].remove(x); + free_EvacuationBlock(x, mutex->thread_holding); + continue; + } + b = b->link.next; + } +} + +void +Vol::evacuate_cleanup() +{ + int64_t eo = ((header->write_pos - start) / CACHE_BLOCK_SIZE) + 1; + int64_t e = dir_offset_evac_bucket(eo); + int64_t sx = e - (evacuate_size / PIN_SCAN_EVERY) - 1; + int64_t s = sx; + int i; + + if (e > evacuate_size) + e = evacuate_size; + if (sx < 0) + s = 0; + for (i = s; i < e; i++) + evacuate_cleanup_blocks(i); + + // if we have wrapped, handle the end bit + if (sx <= 0) { + s = evacuate_size + sx - 2; + if (s < 0) + s = 0; + for (i = s; i < evacuate_size; i++) + evacuate_cleanup_blocks(i); + } +} + +void +Vol::periodic_scan() +{ + evacuate_cleanup(); + scan_for_pinned_documents(); + if (header->write_pos == start) + scan_pos = start; + scan_pos += len / PIN_SCAN_EVERY; +} + +void +Vol::agg_wrap() +{ + header->write_pos = start; + header->phase = !header->phase; + + header->cycle++; + header->agg_pos = header->write_pos; + dir_lookaside_cleanup(this); + dir_clean_vol(this); + periodic_scan(); +} + +/* NOTE: This state can be called by an AIO thread, so DON'T DON'T + DON'T schedule any events on this thread using VC_SCHED_XXX or + mutex->thread_holding->schedule_xxx_local(). ALWAYS use + eventProcessor.schedule_xxx(). + Also, make sure that any functions called by this also use + the eventProcessor to schedule events +*/ +int +Vol::aggWrite(int event, void *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + ink_assert(!is_io_in_progress()); + + Que(CacheVC, link) tocall; + CacheVC *c; + + cancel_trigger(); + +Lagain: + // calculate length of aggregated write + for (c = (CacheVC *) agg.head; c;) { + int writelen = c->agg_len; + ink_assert(writelen < AGG_SIZE); + if (agg_buf_pos + writelen > AGG_SIZE || + header->write_pos + agg_buf_pos + writelen > (skip + len)) + break; + DDebug("agg_read", "copying: %d, %" PRIu64 ", key: %d", + agg_buf_pos, header->write_pos + agg_buf_pos, c->first_key.word(0)); + int wrotelen = agg_copy(agg_buffer + agg_buf_pos, c); + ink_assert(writelen == wrotelen); + agg_todo_size -= writelen; + agg_buf_pos += writelen; + CacheVC *n = (CacheVC *)c->link.next; + agg.dequeue(); + if (c->f.sync && c->f.use_first_key) { + CacheVC *last = sync.tail; + while (last && UINT_WRAP_LT(c->write_serial, last->write_serial)) + last = (CacheVC*)last->link.prev; + sync.insert(c, last); + } else if (c->f.evacuator) + c->handleEvent(AIO_EVENT_DONE, 0); + else + tocall.enqueue(c); + c = n; + } + + // if we got nothing... + if (!agg_buf_pos) { + if (!agg.head && !sync.head) // nothing to get + return EVENT_CONT; + if (header->write_pos == start) { + // write aggregation too long, bad bad, punt on everything. + Note("write aggregation exceeds vol size"); + ink_assert(!tocall.head); + ink_assert(false); + while ((c = agg.dequeue())) { + agg_todo_size -= c->agg_len; + c->initial_thread->schedule_imm_signal(c, AIO_EVENT_DONE); + } + return EVENT_CONT; + } + // start back + if (agg.head) { + agg_wrap(); + goto Lagain; + } + } + + // evacuate space + off_t end = header->write_pos + agg_buf_pos + EVACUATION_SIZE; + if (evac_range(header->write_pos, end, !header->phase) < 0) + goto Lwait; + if (end > skip + len) + if (evac_range(start, start + (end - (skip + len)), header->phase)) + goto Lwait; + + // if agg.head, then we are near the end of the disk, so + // write down the aggregation in whatever size it is. + if (agg_buf_pos < AGG_HIGH_WATER && !agg.head && !sync.head && !dir_sync_waiting) + goto Lwait; + + // write sync marker + if (!agg_buf_pos) { + ink_assert(sync.head); + int l = round_to_approx_size(sizeof(Doc)); + agg_buf_pos = l; + Doc *d = (Doc*)agg_buffer; + memset(d, 0, sizeof(Doc)); + d->magic = DOC_MAGIC; + d->len = l; + d->sync_serial = header->sync_serial; + d->write_serial = header->write_serial; + } + + // set write limit + header->agg_pos = header->write_pos + agg_buf_pos; + + io.aiocb.aio_fildes = fd; + io.aiocb.aio_offset = header->write_pos; + io.aiocb.aio_buf = agg_buffer; + io.aiocb.aio_nbytes = agg_buf_pos; + io.action = this; + /* + Callback on AIO thread so that we can issue a new write ASAP + as all writes are serialized in the volume. This is not necessary + for reads proceed independently. + */ + io.thread = AIO_CALLBACK_THREAD_AIO; + SET_HANDLER(&Vol::aggWriteDone); + ink_aio_write(&io); + +Lwait: + int ret = EVENT_CONT; + while ((c = tocall.dequeue())) { + if (event == EVENT_CALL && c->mutex->thread_holding == mutex->thread_holding) + ret = EVENT_RETURN; + else + c->initial_thread->schedule_imm_signal(c, AIO_EVENT_DONE); + } + return ret; +} + +int +CacheVC::openWriteCloseDir(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + cancel_trigger(); + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) { + SET_HANDLER(&CacheVC::openWriteCloseDir); + ink_debug_assert(!is_io_in_progress()); + VC_SCHED_LOCK_RETRY(); + } + vol->close_write(this); + if (closed < 0 && fragment) + dir_delete(&earliest_key, vol, &earliest_dir); + } + if (is_debug_tag_set("cache_update")) { + if (f.update && closed > 0) { + if (!total_len && alternate_index != CACHE_ALT_REMOVED) { + Debug("cache_update", "header only %d (%" PRIu64 ", %" PRIu64 ")\n", + DIR_MASK_TAG(first_key.word(2)), update_key.b[0], update_key.b[1]); + + } else if (total_len && alternate_index != CACHE_ALT_REMOVED) { + Debug("cache_update", "header body, %d, (%" PRIu64 ", %" PRIu64 "), (%" PRIu64 ", %" PRIu64 ")\n", + DIR_MASK_TAG(first_key.word(2)), update_key.b[0], update_key.b[1], earliest_key.b[0], earliest_key.b[1]); + } else if (!total_len && alternate_index == CACHE_ALT_REMOVED) { + Debug("cache_update", "alt delete, %d, (%" PRIu64 ", %" PRIu64 ")\n", + DIR_MASK_TAG(first_key.word(2)), update_key.b[0], update_key.b[1]); + } + } + } + // update the appropriate stat variable + // These variables may not give the current no of documents with + // one, two and three or more fragments. This is because for + // updates we dont decrement the variable corresponding the old + // size of the document + if ((closed == 1) && (total_len > 0)) { + DDebug("cache_stats", "Fragment = %d", fragment); + switch (fragment) { + case 0: CACHE_INCREMENT_DYN_STAT(cache_single_fragment_document_count_stat); break; + case 1: CACHE_INCREMENT_DYN_STAT(cache_two_fragment_document_count_stat); break; + default: CACHE_INCREMENT_DYN_STAT(cache_three_plus_plus_fragment_document_count_stat); break; + } + } + if (f.close_complete) { + recursive++; + ink_debug_assert(!vol || this_ethread() != vol->mutex->thread_holding); + vio._cont->handleEvent(VC_EVENT_WRITE_COMPLETE, (void *) &vio); + recursive--; + } + return free_CacheVC(this); +} + +int +CacheVC::openWriteCloseHeadDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + if (event == AIO_EVENT_DONE) + set_io_not_in_progress(); + else if (is_io_in_progress()) + return EVENT_CONT; + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_LOCK_RETRY_EVENT(); + od->writing_vec = 0; + if (!io.ok()) + goto Lclose; + ink_assert(f.use_first_key); + if (!od->dont_update_directory) { + if (dir_is_empty(&od->first_dir)) { + dir_insert(&first_key, vol, &dir); + } else { + // multiple fragment vector write + dir_overwrite(&first_key, vol, &dir, &od->first_dir, false); + // insert moved resident alternate + if (od->move_resident_alt) { + if (dir_valid(vol, &od->single_doc_dir)) + dir_insert(&od->single_doc_key, vol, &od->single_doc_dir); + od->move_resident_alt = 0; + } + } + od->first_dir = dir; + if (frag_type == CACHE_FRAG_TYPE_HTTP && f.single_fragment) { + // fragment is tied to the vector + od->move_resident_alt = 1; + if (!f.rewrite_resident_alt) { + od->single_doc_key = earliest_key; + } + dir_assign(&od->single_doc_dir, &dir); + dir_set_tag(&od->single_doc_dir, od->single_doc_key.word(2)); + } + } + } +Lclose: + return openWriteCloseDir(event, e); +} + +int +CacheVC::openWriteCloseHead(int event, Event *e) +{ + NOWARN_UNUSED(e); + + cancel_trigger(); + f.use_first_key = 1; + if (io.ok()) + ink_assert(fragment || (length == (int64_t)total_len)); + else + return openWriteCloseDir(event, e); + if (f.data_done) + write_len = 0; + else + write_len = length; +#ifdef HTTP_CACHE + if (frag_type == CACHE_FRAG_TYPE_HTTP) { + SET_HANDLER(&CacheVC::updateVector); + return updateVector(EVENT_IMMEDIATE, 0); + } else { +#endif + header_len = header_to_write_len; + SET_HANDLER(&CacheVC::openWriteCloseHeadDone); + return do_write_lock(); +#ifdef HTTP_CACHE + } +#endif +} + +int +CacheVC::openWriteCloseDataDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + int ret = 0; + + if (event == AIO_EVENT_DONE) + set_io_not_in_progress(); + else if (is_io_in_progress()) + return EVENT_CONT; + if (!io.ok()) + return openWriteCloseDir(event, e); + { + CACHE_TRY_LOCK(lock, vol->mutex, this_ethread()); + if (!lock) + VC_LOCK_RETRY_EVENT(); + if (!fragment) { + ink_assert(key == earliest_key); + earliest_dir = dir; + } else { + if (!frag) + frag = &integral_frags[0]; + else { + if (fragment-1 >= INTEGRAL_FRAGS && IS_POWER_2((uint32)(fragment-1))) { + Frag *t = frag; + frag = (Frag*)xmalloc(sizeof(Frag) * (fragment-1)*2); + memcpy(frag, t, sizeof(Frag) * (fragment-1)); + if (t != integral_frags) + xfree(t); + } + } + frag[fragment-1].offset = write_pos; + } + fragment++; + write_pos += write_len; + dir_insert(&key, vol, &dir); + blocks = iobufferblock_skip(blocks, &offset, &length, write_len); + next_CacheKey(&key, &key); + if (length) { + write_len = length; + if (write_len > MAX_FRAG_SIZE) + write_len = MAX_FRAG_SIZE; + if ((ret = do_write_call()) == EVENT_RETURN) + goto Lcallreturn; + return ret; + } + f.data_done = 1; + return openWriteCloseHead(event, e); // must be called under vol lock from here + } +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); +} + +int +CacheVC::openWriteClose(int event, Event *e) +{ + NOWARN_UNUSED(e); + cancel_trigger(); + if (is_io_in_progress()) { + if (event != AIO_EVENT_DONE) + return EVENT_CONT; + set_io_not_in_progress(); + if (!io.ok()) + return openWriteCloseDir(event, e); + } + if (closed > 0) { + if (total_len == 0) { +#ifdef HTTP_CACHE + if (f.update) { + return updateVector(event, e); + } else { + // If we've been CLOSE'd but nothing has been written then + // this close is transformed into an abort. + closed = -1; + return openWriteCloseDir(event, e); + } +#else + return openWriteCloseDir(event, e); +#endif + } + if (length && (fragment || length > MAX_FRAG_SIZE)) { + SET_HANDLER(&CacheVC::openWriteCloseDataDone); + write_len = length; + if (write_len > MAX_FRAG_SIZE) + write_len = MAX_FRAG_SIZE; + return do_write_lock_call(); + } else + return openWriteCloseHead(event, e); + } else + return openWriteCloseDir(event, e); +} + +int +CacheVC::openWriteWriteDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + + cancel_trigger(); + if (event == AIO_EVENT_DONE) + set_io_not_in_progress(); + else + if (is_io_in_progress()) + return EVENT_CONT; + // In the event of VC_EVENT_ERROR, the cont must do an io_close + if (!io.ok()) { + if (closed) { + closed = -1; + return die(); + } + SET_HANDLER(&CacheVC::openWriteMain); + return calluser(VC_EVENT_ERROR); + } + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_LOCK_RETRY_EVENT(); + // store the earliest directory. Need to remove the earliest dir + // in case the writer aborts. + if (!fragment) { + ink_assert(key == earliest_key); + earliest_dir = dir; + } else { + if (!frag) + frag = &integral_frags[0]; + else { + if (fragment-1 >= INTEGRAL_FRAGS && IS_POWER_2((uint32_t)(fragment-1))) { + Frag *t = frag; + frag = (Frag*)xmalloc(sizeof(Frag) * (fragment-1)*2); + memcpy(frag, t, sizeof(Frag) * (fragment-1)); + if (t != integral_frags) + xfree(t); + } + } + frag[fragment-1].offset = write_pos; + } + fragment++; + write_pos += write_len; + dir_insert(&key, vol, &dir); + DDebug("cache_insert", "WriteDone: %X, %X, %d", key.word(0), first_key.word(0), write_len); + blocks = iobufferblock_skip(blocks, &offset, &length, write_len); + next_CacheKey(&key, &key); + } + if (closed) + return die(); + SET_HANDLER(&CacheVC::openWriteMain); + return openWriteMain(event, e); +} + +static inline int target_fragment_size() { + return cache_config_target_fragment_size - sizeofDoc; +} + +int +CacheVC::openWriteMain(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + cancel_trigger(); + int called_user = 0; + ink_debug_assert(!is_io_in_progress()); +Lagain: + if (!vio.buffer.writer()) { + if (calluser(VC_EVENT_WRITE_READY) == EVENT_DONE) + return EVENT_DONE; + if (!vio.buffer.writer()) + return EVENT_CONT; + } + if (vio.ntodo() <= 0) { + called_user = 1; + if (calluser(VC_EVENT_WRITE_COMPLETE) == EVENT_DONE) + return EVENT_DONE; + ink_assert(!f.close_complete || !"close expected after write COMPLETE"); + if (vio.ntodo() <= 0) + return EVENT_CONT; + } + int64_t ntodo = (int64_t)(vio.ntodo() + length); + int64_t total_avail = vio.buffer.reader()->read_avail(); + int64_t avail = total_avail; + int64_t towrite = avail + length; + if (towrite > ntodo) { + avail -= (towrite - ntodo); + towrite = ntodo; + } + if (towrite > MAX_FRAG_SIZE) { + avail -= (towrite - MAX_FRAG_SIZE); + towrite = MAX_FRAG_SIZE; + } + if (!blocks && towrite) { + blocks = vio.buffer.reader()->block; + offset = vio.buffer.reader()->start_offset; + } + if (avail > 0) { + vio.buffer.reader()->consume(avail); + vio.ndone += avail; + total_len += avail; + } + length = (uint64_t)towrite; + if (length > target_fragment_size() && + (length < target_fragment_size() + target_fragment_size() / 4)) + write_len = target_fragment_size(); + else + write_len = length; + bool not_writing = towrite != ntodo && towrite < target_fragment_size(); + if (!called_user) { + if (not_writing) { + called_user = 1; + if (calluser(VC_EVENT_WRITE_READY) == EVENT_DONE) + return EVENT_DONE; + goto Lagain; + } else if (vio.ntodo() <= 0) + goto Lagain; + } + if (not_writing) + return EVENT_CONT; + if (towrite == ntodo && f.close_complete) { + closed = 1; + SET_HANDLER(&CacheVC::openWriteClose); + return openWriteClose(EVENT_NONE, NULL); + } + SET_HANDLER(&CacheVC::openWriteWriteDone); + return do_write_lock_call(); +} + +// begin overwrite +int +CacheVC::openWriteOverwrite(int event, Event *e) +{ + NOWARN_UNUSED(e); + + cancel_trigger(); + if (event != AIO_EVENT_DONE) { + if (event == EVENT_IMMEDIATE) + last_collision = 0; + } else { + Doc *doc = NULL; + set_io_not_in_progress(); + if (_action.cancelled) + return openWriteCloseDir(event, e); + if (!io.ok()) + goto Ldone; + doc = (Doc *) buf->data(); + if (!(doc->first_key == first_key)) + goto Lcollision; + od->first_dir = dir; + first_buf = buf; + goto Ldone; + } +Lcollision: + { + CACHE_TRY_LOCK(lock, vol->mutex, this_ethread()); + if (!lock) + VC_LOCK_RETRY_EVENT(); + int res = dir_probe(&first_key, vol, &dir, &last_collision); + if (res > 0) { + if ((res = do_read_call(&first_key)) == EVENT_RETURN) + goto Lcallreturn; + return res; + } + } +Ldone: + SET_HANDLER(&CacheVC::openWriteMain); + return callcont(CACHE_EVENT_OPEN_WRITE); +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); // hopefully a tail call +} + +#ifdef HTTP_CACHE +// openWriteStartDone handles vector read (addition of alternates) +// and lock misses +int +CacheVC::openWriteStartDone(int event, Event *e) +{ + NOWARN_UNUSED(e); + + intptr_t err = ECACHE_NO_DOC; + cancel_trigger(); + if (is_io_in_progress()) { + if (event != AIO_EVENT_DONE) + return EVENT_CONT; + set_io_not_in_progress(); + } + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) + VC_LOCK_RETRY_EVENT(); + + if (_action.cancelled && (!od || !od->has_multiple_writers())) + goto Lcancel; + + if (event == AIO_EVENT_DONE) { // vector read done + Doc *doc = (Doc *) buf->data(); + if (!io.ok()) { + err = ECACHE_READ_FAIL; + goto Lfailure; + } + /* INKqa07123. + A directory entry which is nolonger valid may have been overwritten. + We need to start afresh from the beginning by setting last_collision + to NULL. + */ + if (!dir_valid(vol, &dir)) { + DDebug("cache_write", + "OpenReadStartDone: Dir not valid: Write Head: %lld, Dir: %"PRId64, + (long long)offset_to_vol_offset(vol, vol->header->write_pos), dir_offset(&dir)); + last_collision = NULL; + goto Lcollision; + } + if (!(doc->first_key == first_key)) + goto Lcollision; + if (doc->magic != DOC_MAGIC) { + err = ECACHE_BAD_META_DATA; + goto Lfailure; + } + if (!doc->hlen) { + err = ECACHE_BAD_META_DATA; + goto Lfailure; + } + ink_assert((((uintptr_t) &doc->hdr()[0]) & HDR_PTR_ALIGNMENT_MASK) == 0); + + if (write_vector->get_handles(doc->hdr(), doc->hlen, buf) != doc->hlen) { + err = ECACHE_BAD_META_DATA; + goto Lfailure; + } + ink_debug_assert(write_vector->count() > 0); + od->first_dir = dir; + first_dir = dir; + if (doc->single_fragment()) { + // fragment is tied to the vector + od->move_resident_alt = 1; + od->single_doc_key = doc->key; + dir_assign(&od->single_doc_dir, &dir); + dir_set_tag(&od->single_doc_dir, od->single_doc_key.word(2)); + } + } + first_buf = buf; + goto Lsuccess; + + +Lcollision: + + int if_writers = ((uintptr_t) info == CACHE_ALLOW_MULTIPLE_WRITES); + if (!od) { + if ((err = vol->open_write( + this, if_writers, cache_config_http_max_alts > 1 ? cache_config_http_max_alts : 0)) > 0) + goto Lfailure; + if (od->has_multiple_writers()) { + MUTEX_RELEASE(lock); + SET_HANDLER(&CacheVC::openWriteMain); + return callcont(CACHE_EVENT_OPEN_WRITE); + } + } + // check for collision + if (dir_probe(&first_key, vol, &dir, &last_collision)) { + od->reading_vec = 1; + int ret = do_read_call(&first_key); + if (ret == EVENT_RETURN) + goto Lcallreturn; + return ret; + } + if (f.update) { + // fail update because vector has been GC'd + goto Lfailure; + } + } +Lsuccess: + od->reading_vec = 0; + if (_action.cancelled) + goto Lcancel; + SET_HANDLER(&CacheVC::openWriteMain); + return callcont(CACHE_EVENT_OPEN_WRITE); + +Lfailure: + CACHE_INCREMENT_DYN_STAT(base_stat + CACHE_STAT_FAILURE); + _action.continuation->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -err); +Lcancel: + if (od) { + od->reading_vec = 0; + return openWriteCloseDir(event, e); + } else + return free_CacheVC(this); +Lcallreturn: + return handleEvent(AIO_EVENT_DONE, 0); // hopefully a tail call +} +#endif + +// handle lock failures from main Cache::open_write entry points below +int +CacheVC::openWriteStartBegin(int event, Event *e) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + + intptr_t err; + cancel_trigger(); + if (_action.cancelled) + return free_CacheVC(this); + if (((err = vol->open_write_lock(this, false, 1)) > 0)) { + CACHE_INCREMENT_DYN_STAT(base_stat + CACHE_STAT_FAILURE); + free_CacheVC(this); + _action.continuation->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -err); + return EVENT_DONE; + } + if (err < 0) + VC_SCHED_LOCK_RETRY(); + if (f.overwrite) { + SET_HANDLER(&CacheVC::openWriteOverwrite); + return openWriteOverwrite(EVENT_IMMEDIATE, 0); + } else { + // write by key + SET_HANDLER(&CacheVC::openWriteMain); + return callcont(CACHE_EVENT_OPEN_WRITE); + } +} + +// main entry point for writing of of non-http documents +Action * +Cache::open_write(Continuation *cont, CacheKey *key, CacheFragType frag_type, + int options, time_t apin_in_cache, char *hostname, int host_len) +{ + + if (!CACHE_READY(frag_type)) { + cont->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -ECACHE_NOT_READY); + return ACTION_RESULT_DONE; + } + + ink_assert(caches[frag_type] == this); + + intptr_t res = 0; + CacheVC *c = new_CacheVC(cont); + ProxyMutex *mutex = cont->mutex; + MUTEX_LOCK(lock, c->mutex, this_ethread()); + c->vio.op = VIO::WRITE; + c->base_stat = cache_write_active_stat; + c->vol = key_to_vol(key, hostname, host_len); + Vol *vol = c->vol; + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE); + c->first_key = c->key = *key; + c->frag_type = frag_type; + /* + The transition from single fragment document to a multi-fragment document + would cause a problem if the key and the first_key collide. In case of + a collision, old vector data could be served to HTTP. Need to avoid that. + Also, when evacuating a fragment, we have to decide if its the first_key + or the earliest_key based on the dir_tag. + */ + do { + rand_CacheKey(&c->key, cont->mutex); + } while (DIR_MASK_TAG(c->key.word(2)) == DIR_MASK_TAG(c->first_key.word(2))); + c->earliest_key = c->key; +#ifdef HTTP_CACHE + c->info = 0; +#endif + c->f.overwrite = (options & CACHE_WRITE_OPT_OVERWRITE) != 0; + c->f.close_complete = (options & CACHE_WRITE_OPT_CLOSE_COMPLETE) != 0; + c->f.sync = (options & CACHE_WRITE_OPT_SYNC) == CACHE_WRITE_OPT_SYNC; + c->pin_in_cache = (uint32_t) apin_in_cache; + + if ((res = c->vol->open_write_lock(c, false, 1)) > 0) { + // document currently being written, abort + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_FAILURE); + cont->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -res); + free_CacheVC(c); + return ACTION_RESULT_DONE; + } + if (res < 0) { + SET_CONTINUATION_HANDLER(c, &CacheVC::openWriteStartBegin); + c->trigger = CONT_SCHED_LOCK_RETRY(c); + return &c->_action; + } + if (!c->f.overwrite) { + SET_CONTINUATION_HANDLER(c, &CacheVC::openWriteMain); + c->callcont(CACHE_EVENT_OPEN_WRITE); + return ACTION_RESULT_DONE; + } else { + SET_CONTINUATION_HANDLER(c, &CacheVC::openWriteOverwrite); + if (c->openWriteOverwrite(EVENT_IMMEDIATE, 0) == EVENT_DONE) + return ACTION_RESULT_DONE; + else + return &c->_action; + } +} + +#ifdef HTTP_CACHE +// main entry point for writing of http documents +Action * +Cache::open_write(Continuation *cont, CacheKey *key, CacheHTTPInfo *info, time_t apin_in_cache, + CacheKey *key1, CacheFragType type, char *hostname, int host_len) +{ + NOWARN_UNUSED(key1); + + if (!CACHE_READY(type)) { + cont->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -ECACHE_NOT_READY); + return ACTION_RESULT_DONE; + } + + ink_assert(caches[type] == this); + intptr_t err = 0; + int if_writers = (uintptr_t) info == CACHE_ALLOW_MULTIPLE_WRITES; + CacheVC *c = new_CacheVC(cont); + ProxyMutex *mutex = cont->mutex; + c->vio.op = VIO::WRITE; + c->first_key = *key; + /* + The transition from single fragment document to a multi-fragment document + would cause a problem if the key and the first_key collide. In case of + a collision, old vector data could be served to HTTP. Need to avoid that. + Also, when evacuating a fragment, we have to decide if its the first_key + or the earliest_key based on the dir_tag. + */ + do { + rand_CacheKey(&c->key, cont->mutex); + } + while (DIR_MASK_TAG(c->key.word(2)) == DIR_MASK_TAG(c->first_key.word(2))); + c->earliest_key = c->key; + c->frag_type = CACHE_FRAG_TYPE_HTTP; + c->vol = key_to_vol(key, hostname, host_len); + Vol *vol = c->vol; + c->info = info; + if (c->info && (uintptr_t) info != CACHE_ALLOW_MULTIPLE_WRITES) { + /* + Update has the following code paths : + a) Update alternate header only : + In this case the vector has to be rewritten. The content + length(update_len) and the key for the document are set in the + new_info in the set_http_info call. + HTTP OPERATIONS + open_write with info set + set_http_info new_info + (total_len == 0) + close + b) Update alternate and data + In this case both the vector and the data needs to be rewritten. + This case is similar to the standard write of a document case except + that the new_info is inserted into the vector at the alternate_index + (overwriting the old alternate) rather than the end of the vector. + HTTP OPERATIONS + open_write with info set + set_http_info new_info + do_io_write => (total_len > 0) + close + c) Delete an alternate + The vector may need to be deleted (if there was only one alternate) or + rewritten (if there were more than one alternate). The deletion of the + vector is done in openWriteRemoveVector. + HTTP OPERATIONS + open_write with info set + close + */ + c->f.update = 1; + c->base_stat = cache_update_active_stat; + DDebug("cache_update", "Update called"); + info->object_key_get(&c->update_key); + ink_debug_assert(!(c->update_key == zero_key)); + c->update_len = info->object_size_get(); + } else + c->base_stat = cache_write_active_stat; + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_ACTIVE); + c->pin_in_cache = (uint32_t) apin_in_cache; + + { + CACHE_TRY_LOCK(lock, c->vol->mutex, cont->mutex->thread_holding); + if (lock) { + if ((err = c->vol->open_write(c, if_writers, + cache_config_http_max_alts > 1 ? cache_config_http_max_alts : 0)) > 0) + goto Lfailure; + // If there are multiple writers, then this one cannot be an update. + // Only the first writer can do an update. If that's the case, we can + // return success to the state machine now.; + if (c->od->has_multiple_writers()) + goto Lmiss; + if (!dir_probe(key, c->vol, &c->dir, &c->last_collision)) { + if (c->f.update) { + // fail update because vector has been GC'd + // This situation can also arise in openWriteStartDone + err = ECACHE_NO_DOC; + goto Lfailure; + } + // document doesn't exist, begin write + goto Lmiss; + } else { + c->od->reading_vec = 1; + // document exists, read vector + SET_CONTINUATION_HANDLER(c, &CacheVC::openWriteStartDone); + switch (c->do_read_call(&c->first_key)) { + case EVENT_DONE: return ACTION_RESULT_DONE; + case EVENT_RETURN: goto Lcallreturn; + default: return &c->_action; + } + } + } + // missed lock + SET_CONTINUATION_HANDLER(c, &CacheVC::openWriteStartDone); + CONT_SCHED_LOCK_RETRY(c); + return &c->_action; + } + +Lmiss: + SET_CONTINUATION_HANDLER(c, &CacheVC::openWriteMain); + c->callcont(CACHE_EVENT_OPEN_WRITE); + return ACTION_RESULT_DONE; + +Lfailure: + CACHE_INCREMENT_DYN_STAT(c->base_stat + CACHE_STAT_FAILURE); + cont->handleEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (void *) -err); + if (c->od) { + c->openWriteCloseDir(EVENT_IMMEDIATE, 0); + return ACTION_RESULT_DONE; + } + free_CacheVC(c); + return ACTION_RESULT_DONE; + +Lcallreturn: + if (c->handleEvent(AIO_EVENT_DONE, 0) == EVENT_DONE) + return ACTION_RESULT_DONE; + return &c->_action; +} +#endif diff --git a/iocore/cache/I_Cache.h b/iocore/cache/I_Cache.h new file mode 100644 index 00000000..dc50ae0a --- /dev/null +++ b/iocore/cache/I_Cache.h @@ -0,0 +1,187 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_CACHE_H__ +#define _I_CACHE_H__ + +#ifndef TS_INLINE +#define TS_INLINE +#endif + +#include "libts.h" +#include "I_EventSystem.h" +#include "I_AIO.h" +#include "I_CacheDefs.h" +#include "I_Store.h" + +#define CACHE_MODULE_MAJOR_VERSION 1 +#define CACHE_MODULE_MINOR_VERSION 0 +#define CACHE_MODULE_VERSION makeModuleVersion(CACHE_MODULE_MAJOR_VERSION,\ + CACHE_MODULE_MINOR_VERSION,\ + PUBLIC_MODULE_HEADER) + +#define CACHE_WRITE_OPT_OVERWRITE 0x0001 +#define CACHE_WRITE_OPT_CLOSE_COMPLETE 0x0002 +#define CACHE_WRITE_OPT_SYNC (CACHE_WRITE_OPT_CLOSE_COMPLETE | 0x0004) +#define CACHE_WRITE_OPT_OVERWRITE_SYNC (CACHE_WRITE_OPT_SYNC | CACHE_WRITE_OPT_OVERWRITE) + +#define SCAN_KB_PER_SECOND 8192 // 1TB/8MB = 131072 = 36 HOURS to scan a TB + +#define RAM_CACHE_ALGORITHM_CLFUS 0 +#define RAM_CACHE_ALGORITHM_LRU 1 + +#define CACHE_COMPRESSION_NONE 0 +#define CACHE_COMPRESSION_FASTLZ 1 +#define CACHE_COMPRESSION_LIBZ 2 +#define CACHE_COMPRESSION_LIBLZMA 3 + +struct CacheVC; +#ifdef HTTP_CACHE +class CacheLookupHttpConfig; +class URL; +class HTTPHdr; +class HTTPInfo; + +typedef HTTPHdr CacheHTTPHdr; +typedef URL CacheURL; +typedef HTTPInfo CacheHTTPInfo; +#endif + +struct CacheProcessor:public Processor +{ + virtual int start(int n_cache_threads = 0 /* cache uses event threads */ ); + virtual int start_internal(int flags = 0); + void stop(); + + int dir_check(bool fix); + int db_check(bool fix); + + inkcoreapi Action *lookup(Continuation *cont, CacheKey *key, + bool local_only = false, + CacheFragType frag_type = CACHE_FRAG_TYPE_NONE, char *hostname = 0, int host_len = 0); + inkcoreapi Action *open_read(Continuation *cont, CacheKey *key, + CacheFragType frag_type = CACHE_FRAG_TYPE_NONE, char *hostname = 0, int host_len = 0); + Action *open_read_buffer(Continuation *cont, MIOBuffer *buf, CacheKey *key, + CacheFragType frag_type = CACHE_FRAG_TYPE_NONE, char *hostname = 0, int host_len = 0); + + inkcoreapi Action *open_write(Continuation *cont, + CacheKey *key, + CacheFragType frag_type = CACHE_FRAG_TYPE_NONE, + int expected_size = CACHE_EXPECTED_SIZE, + int options = 0, + time_t pin_in_cache = (time_t) 0, + char *hostname = 0, int host_len = 0); + Action *open_write_buffer(Continuation *cont, MIOBuffer *buf, + CacheKey *key, + CacheFragType frag_type = CACHE_FRAG_TYPE_NONE, + int options = 0, + time_t pin_in_cache = (time_t) 0, + char *hostname = 0, int host_len = 0); + inkcoreapi Action *remove(Continuation *cont, CacheKey *key, + CacheFragType frag_type = CACHE_FRAG_TYPE_NONE, + bool rm_user_agents = true, bool rm_link = false, + char *hostname = 0, int host_len = 0); + Action *scan(Continuation *cont, char *hostname = 0, int host_len = 0, int KB_per_second = SCAN_KB_PER_SECOND); +#ifdef HTTP_CACHE + Action *lookup(Continuation *cont, URL *url, bool local_only = false, + CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP); + inkcoreapi Action *open_read(Continuation *cont, URL *url, + CacheHTTPHdr *request, + CacheLookupHttpConfig *params, + time_t pin_in_cache = (time_t) 0, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP); + Action *open_read_buffer(Continuation *cont, MIOBuffer *buf, URL *url, + CacheHTTPHdr *request, + CacheLookupHttpConfig *params, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP); + Action *open_write(Continuation *cont, int expected_size, URL *url, + CacheHTTPHdr *request, CacheHTTPInfo *old_info, + time_t pin_in_cache = (time_t) 0, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP); + Action *open_write_buffer(Continuation *cont, MIOBuffer *buf, URL *url, + CacheHTTPHdr *request, CacheHTTPHdr *response, + CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP); + Action *remove(Continuation *cont, URL *url, CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP); + + Action *open_read_internal(int, Continuation *, MIOBuffer *, CacheURL *, + CacheHTTPHdr *, CacheLookupHttpConfig *, + CacheKey *, time_t, CacheFragType type, char *hostname, int host_len); +#endif + Action *link(Continuation *cont, CacheKey *from, CacheKey *to, + CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP, char *hostname = 0, int host_len = 0); + + Action *deref(Continuation *cont, CacheKey *key, + CacheFragType frag_type = CACHE_FRAG_TYPE_HTTP, char *hostname = 0, int host_len = 0); + static int IsCacheEnabled(); + + static unsigned int IsCacheReady(CacheFragType type); + + // private members + void diskInitialized(); + + void cacheInitialized(); + + static volatile uint32_t cache_ready; + static volatile int initialized; + static volatile int start_done; + static int clear; + static int fix; + static int start_internal_flags; + static int auto_clear_flag; +}; + +struct CacheVConnection:public VConnection +{ + VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) = 0; + virtual VIO *do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *buf, int64_t offset) = 0; + VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) = 0; + void do_io_close(int lerrno = -1) = 0; + void reenable(VIO *avio) = 0; + void reenable_re(VIO *avio) = 0; + void do_io_shutdown(ShutdownHowTo_t howto) + { + (void) howto; + ink_assert(!"CacheVConnection::do_io_shutdown unsupported"); + } + + virtual int get_header(void **ptr, int *len) = 0; + virtual int set_header(void *ptr, int len) = 0; + virtual int get_single_data(void **ptr, int *len) = 0; + +#ifdef HTTP_CACHE + virtual void set_http_info(CacheHTTPInfo *info) = 0; + virtual void get_http_info(CacheHTTPInfo **info) = 0; +#endif + + virtual bool is_ram_cache_hit() = 0; + virtual bool set_disk_io_priority(int priority) = 0; + virtual int get_disk_io_priority() = 0; + virtual bool set_pin_in_cache(time_t t) = 0; + virtual time_t get_pin_in_cache() = 0; + virtual int64_t get_object_size() = 0; + + CacheVConnection(); +}; + +void ink_cache_init(ModuleVersion version); +extern inkcoreapi CacheProcessor cacheProcessor; +extern Continuation *cacheRegexDeleteCont; + +#endif /* _I_CACHE_H__ */ diff --git a/iocore/cache/I_CacheDefs.h b/iocore/cache/I_CacheDefs.h new file mode 100644 index 00000000..5910d4bc --- /dev/null +++ b/iocore/cache/I_CacheDefs.h @@ -0,0 +1,131 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +#ifndef _I_CACHE_DEFS_H__ +#define _I_CACHE_DEFS_H__ + +#define CACHE_INIT_FAILED -1 +#define CACHE_INITIALIZING 0 +#define CACHE_INITIALIZED 1 + +#define CACHE_ALT_INDEX_DEFAULT -1 +#define CACHE_ALT_REMOVED -2 + +#define CACHE_DB_MAJOR_VERSION 21 +#define CACHE_DB_MINOR_VERSION 0 + +#define CACHE_DIR_MAJOR_VERSION 18 +#define CACHE_DIR_MINOR_VERSION 0 + +#define CACHE_DB_FDS 128 + +// opcodes +#define CACHE_OPEN_READ 1 +#define CACHE_OPEN_READ_BUFFER 2 +#define CACHE_OPEN_READ_LONG 3 +#define CACHE_OPEN_READ_BUFFER_LONG 4 +#define CACHE_OPEN_WRITE 5 +#define CACHE_OPEN_WRITE_BUFFER 6 +#define CACHE_OPEN_WRITE_LONG 7 +#define CACHE_OPEN_WRITE_BUFFER_LONG 8 +#define CACHE_UPDATE 9 +#define CACHE_REMOVE 10 +#define CACHE_LINK 11 +#define CACHE_DEREF 12 +#define CACHE_LOOKUP_OP 13 + +#define CACHE_NONE_TYPE 0 // for empty disk fragments +#define CACHE_HTTP_TYPE 1 +#define CACHE_RTSP_TYPE 2 +// NOTE: All the failures are ODD, and one greater than the success +// Some of these must match those in (tested in verify_cache_api()) +enum CacheEventType +{ + CACHE_EVENT_LOOKUP = CACHE_EVENT_EVENTS_START + 0, + CACHE_EVENT_LOOKUP_FAILED = CACHE_EVENT_EVENTS_START + 1, + CACHE_EVENT_OPEN_READ = CACHE_EVENT_EVENTS_START + 2, + CACHE_EVENT_OPEN_READ_FAILED = CACHE_EVENT_EVENTS_START + 3, + // 4-7 unused + CACHE_EVENT_OPEN_WRITE = CACHE_EVENT_EVENTS_START + 8, + CACHE_EVENT_OPEN_WRITE_FAILED = CACHE_EVENT_EVENTS_START + 9, + CACHE_EVENT_REMOVE = CACHE_EVENT_EVENTS_START + 12, + CACHE_EVENT_REMOVE_FAILED = CACHE_EVENT_EVENTS_START + 13, + CACHE_EVENT_UPDATE, + CACHE_EVENT_UPDATE_FAILED, + CACHE_EVENT_LINK, + CACHE_EVENT_LINK_FAILED, + CACHE_EVENT_DEREF, + CACHE_EVENT_DEREF_FAILED, + CACHE_EVENT_SCAN = CACHE_EVENT_EVENTS_START + 20, + CACHE_EVENT_SCAN_FAILED = CACHE_EVENT_EVENTS_START + 21, + CACHE_EVENT_SCAN_OBJECT = CACHE_EVENT_EVENTS_START + 22, + CACHE_EVENT_SCAN_OPERATION_BLOCKED = CACHE_EVENT_EVENTS_START + 23, + CACHE_EVENT_SCAN_OPERATION_FAILED = CACHE_EVENT_EVENTS_START + 24, + CACHE_EVENT_SCAN_DONE = CACHE_EVENT_EVENTS_START + 25, + ////////////////////////// + // Internal error codes // + ////////////////////////// + CACHE_EVENT_RESPONSE = CACHE_EVENT_EVENTS_START + 50, + CACHE_EVENT_RESPONSE_MSG, + CACHE_EVENT_RESPONSE_RETRY +}; + +enum CacheScanResult +{ + CACHE_SCAN_RESULT_CONTINUE = EVENT_CONT, + CACHE_SCAN_RESULT_DONE = EVENT_DONE, + CACHE_SCAN_RESULT_DELETE = 10, + CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES, + CACHE_SCAN_RESULT_UPDATE, + CACHE_SCAN_RESULT_RETRY +}; + +enum CacheDataType +{ + CACHE_DATA_SIZE = VCONNECTION_CACHE_DATA_BASE, + CACHE_DATA_HTTP_INFO, + CACHE_DATA_KEY, + CACHE_DATA_RAM_CACHE_HIT_FLAG +}; + +enum CacheFragType +{ + CACHE_FRAG_TYPE_NONE, + CACHE_FRAG_TYPE_HTTP, + CACHE_FRAG_TYPE_RTSP, + NUM_CACHE_FRAG_TYPES +}; + +#define CacheKey INK_MD5 +#define CACHE_ALLOW_MULTIPLE_WRITES 1 +#define CACHE_EXPECTED_SIZE 32768 + +/* uses of the CacheKey + word(0) - cache partition segment + word(1) - cache partition bucket + word(2) - tag (lower bits), hosttable hash (upper bits) + word(3) - ram cache hash, lookaside cache + */ +#endif // __CACHE_DEFS_H__ diff --git a/iocore/cache/I_Store.h b/iocore/cache/I_Store.h new file mode 100644 index 00000000..0229283d --- /dev/null +++ b/iocore/cache/I_Store.h @@ -0,0 +1,189 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Store.h + + + ****************************************************************************/ + +#ifndef _Store_h_ +#define _Store_h_ + +#include "libts.h" + +#define STORE_BLOCK_SIZE 8192 +#define STORE_BLOCK_SHIFT 13 +#define DEFAULT_HW_SECTOR_SIZE 512 + +// +// A Store is a place to store data. +// Those on the same disk should be in a linked list. +// +struct Span +{ + char *pathname; + int64_t blocks; + int64_t hw_sector_size; + bool file_pathname; // the pathname is a file + bool isRaw; + int64_t offset; // used only if (file == true) + int alignment; + int disk_id; + LINK(Span, link); + +private: + bool is_mmapable_internal; +public: + bool is_mmapable() { return is_mmapable_internal; } + void set_mmapable(bool s) { is_mmapable_internal = s; } + int64_t size() { return blocks * STORE_BLOCK_SIZE; } + + int64_t total_blocks() { + if (link.next) { + return blocks + link.next->total_blocks(); + } else { + return blocks; + } + } + + Span *nth(int i) { + Span *x = this; + while (x && i--) + x = x->link.next; + return x; + } + + int paths() { + int i = 0; + for (Span * x = this; x; i++, x = x->link.next); + return i; + } + int write(int fd); + int read(int fd); + + Span *dup(); + int64_t end() { return offset + blocks; } + + const char *init(char *n, int64_t size); + + // 0 on success -1 on failure + int path(char *filename, // for non-file, the filename in the director + int64_t * offset, // for file, start offset (unsupported) + char *buf, int buflen); // where to store the path + +Span():pathname(NULL), blocks(0), hw_sector_size(DEFAULT_HW_SECTOR_SIZE), file_pathname(false), + isRaw(true), offset(0), alignment(0), disk_id(0), is_mmapable_internal(false) { + } + ~Span(); +}; + +struct Store +{ + // + // Public Interface + // Thread-safe operations + // + + // spread evenly on all disks + void spread_alloc(Store & s, unsigned int blocks, bool mmapable = true); + void alloc(Store & s, unsigned int blocks, bool only_one = false, bool mmapable = true); + + Span *alloc_one(unsigned int blocks, bool mmapable) { + Store s; + alloc(s, blocks, true, mmapable); + if (s.n_disks) + { + Span *t = s.disk[0]; + s.disk[0] = NULL; + return t; + } else + return NULL; + } + // try to allocate, return (s == gotten, diff == not gotten) + void try_realloc(Store & s, Store & diff); + + // free back the contents of a store. + // must have been JUST allocated (no intervening allocs/frees) + void free(Store & s); + void add(Span * s); + void add(Store & s); + void dup(Store & s); + void sort(); + void extend(int i) + { + if (i > n_disks) { + disk = (Span **) xrealloc(disk, i * sizeof(Span *)); + for (int j = n_disks; j < i; j++) + disk[j] = NULL; + n_disks = i; + } + } + + // Non Thread-safe operations + unsigned int total_blocks(int after = 0) { + int64_t t = 0; + for (int i = after; i < n_disks; i++) + if (disk[i]) + t += disk[i]->total_blocks(); + return (unsigned int) t; + } + // 0 on success -1 on failure + // these operations are NOT thread-safe + // + int write(int fd, char *name); + int read(int fd, char *name); + int clear(char *filename, bool clear_dirs = true); + void normalize(); + void delete_all(); + int remove(char *pathname); + Store(); + ~Store(); + + int n_disks; + Span **disk; + + // + // returns NULL on success + // if fd >= 0 then on failure it returns an error string + // otherwise on failure it returns (char *)-1 + // + const char *read_config(int fd = -1); + int write_config_data(int fd); +}; + +extern Store theStore; + +// store either free or in the cache, can be stolen for reconfiguration +void stealStore(Store & s, int blocks); +int initialize_store(); + +struct storageConfigFile { + const char *parseFile(int fd) { + Store tStore; + return tStore.read_config(fd); + } +}; + +#endif diff --git a/iocore/cache/Inline.cc b/iocore/cache/Inline.cc new file mode 100644 index 00000000..9a9d3752 --- /dev/null +++ b/iocore/cache/Inline.cc @@ -0,0 +1,33 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Inline Functions as globals for users using the public interface + * + */ +#define TS_INLINE +#define INLINE_CC + +#include "P_Cache.h" + + diff --git a/iocore/cache/Makefile.am b/iocore/cache/Makefile.am new file mode 100644 index 00000000..10c9a78a --- /dev/null +++ b/iocore/cache/Makefile.am @@ -0,0 +1,75 @@ +# Makefile.am for the traffic/iocore/cache hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if STANDALONE_IOCORE +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records + +ADD_SRC = +else +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/proxy/http \ + -I$(top_srcdir)/proxy/http/remap \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/utils + +ADD_SRC = +if BUILD_TESTS + ADD_SRC += CacheTest.cc P_CacheTest.h +endif + +endif + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +noinst_LIBRARIES = libinkcache.a + +libinkcache_a_SOURCES = \ + Cache.cc \ + CacheDir.cc \ + CacheDisk.cc \ + CacheHosting.cc \ + CacheHttp.cc \ + CacheLink.cc \ + CachePages.cc \ + CachePagesInternal.cc \ + CacheVol.cc \ + CacheRead.cc \ + CacheWrite.cc \ + I_Cache.h \ + I_CacheDefs.h \ + I_Store.h \ + P_Cache.h \ + P_CacheArray.h \ + P_CacheDir.h \ + P_CacheDisk.h \ + P_CacheHosting.h \ + P_CacheHttp.h \ + P_CacheInternal.h \ + P_CacheVol.h \ + P_RamCache.h \ + RamCacheLRU.cc \ + RamCacheCLFUS.cc \ + Store.cc \ + Inline.cc $(ADD_SRC) diff --git a/iocore/cache/Makefile.in b/iocore/cache/Makefile.in new file mode 100644 index 00000000..a6035229 --- /dev/null +++ b/iocore/cache/Makefile.in @@ -0,0 +1,768 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/cache hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_TESTS_TRUE@@STANDALONE_IOCORE_FALSE@am__append_1 = CacheTest.cc P_CacheTest.h +subdir = iocore/cache +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinkcache_a_AR = $(AR) $(ARFLAGS) +libinkcache_a_LIBADD = +am__libinkcache_a_SOURCES_DIST = Cache.cc CacheDir.cc CacheDisk.cc \ + CacheHosting.cc CacheHttp.cc CacheLink.cc CachePages.cc \ + CachePagesInternal.cc CacheVol.cc CacheRead.cc CacheWrite.cc \ + I_Cache.h I_CacheDefs.h I_Store.h P_Cache.h P_CacheArray.h \ + P_CacheDir.h P_CacheDisk.h P_CacheHosting.h P_CacheHttp.h \ + P_CacheInternal.h P_CacheVol.h P_RamCache.h RamCacheLRU.cc \ + RamCacheCLFUS.cc Store.cc Inline.cc CacheTest.cc P_CacheTest.h +@BUILD_TESTS_TRUE@@STANDALONE_IOCORE_FALSE@am__objects_1 = CacheTest.$(OBJEXT) +@STANDALONE_IOCORE_FALSE@am__objects_2 = $(am__objects_1) +@STANDALONE_IOCORE_TRUE@am__objects_2 = $(am__objects_1) +am_libinkcache_a_OBJECTS = Cache.$(OBJEXT) CacheDir.$(OBJEXT) \ + CacheDisk.$(OBJEXT) CacheHosting.$(OBJEXT) CacheHttp.$(OBJEXT) \ + CacheLink.$(OBJEXT) CachePages.$(OBJEXT) \ + CachePagesInternal.$(OBJEXT) CacheVol.$(OBJEXT) \ + CacheRead.$(OBJEXT) CacheWrite.$(OBJEXT) RamCacheLRU.$(OBJEXT) \ + RamCacheCLFUS.$(OBJEXT) Store.$(OBJEXT) Inline.$(OBJEXT) \ + $(am__objects_2) +libinkcache_a_OBJECTS = $(am_libinkcache_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinkcache_a_SOURCES) +DIST_SOURCES = $(am__libinkcache_a_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +@STANDALONE_IOCORE_FALSE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_FALSE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/lib/records \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/hdrs \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/http \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/http/remap \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/preparse \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/utils + +@STANDALONE_IOCORE_TRUE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_TRUE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_TRUE@ -I$(top_srcdir)/lib/records + +@STANDALONE_IOCORE_FALSE@ADD_SRC = $(am__append_1) +@STANDALONE_IOCORE_TRUE@ADD_SRC = $(am__append_1) +noinst_LIBRARIES = libinkcache.a +libinkcache_a_SOURCES = \ + Cache.cc \ + CacheDir.cc \ + CacheDisk.cc \ + CacheHosting.cc \ + CacheHttp.cc \ + CacheLink.cc \ + CachePages.cc \ + CachePagesInternal.cc \ + CacheVol.cc \ + CacheRead.cc \ + CacheWrite.cc \ + I_Cache.h \ + I_CacheDefs.h \ + I_Store.h \ + P_Cache.h \ + P_CacheArray.h \ + P_CacheDir.h \ + P_CacheDisk.h \ + P_CacheHosting.h \ + P_CacheHttp.h \ + P_CacheInternal.h \ + P_CacheVol.h \ + P_RamCache.h \ + RamCacheLRU.cc \ + RamCacheCLFUS.cc \ + Store.cc \ + Inline.cc $(ADD_SRC) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/cache/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/cache/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinkcache.a: $(libinkcache_a_OBJECTS) $(libinkcache_a_DEPENDENCIES) + -rm -f libinkcache.a + $(libinkcache_a_AR) libinkcache.a $(libinkcache_a_OBJECTS) $(libinkcache_a_LIBADD) + $(RANLIB) libinkcache.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheDir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheDisk.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheHosting.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheHttp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheLink.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CachePages.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CachePagesInternal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheRead.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheVol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CacheWrite.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RamCacheCLFUS.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RamCacheLRU.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Store.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/cache/Notes b/iocore/cache/Notes new file mode 100644 index 00000000..f26843ac --- /dev/null +++ b/iocore/cache/Notes @@ -0,0 +1,17 @@ +proxy/cluster/Cluster.h is now iocore/cluster/P_ClusterCache.h +Clustering compiles but only works if this module is compiled with the entire +TS because there are a lot of stuff required for clustering in proxy/http. + + +cache ifdefs +FIXME_NONMODULAR -> this flaf needs to be turned on when compiling along +with the entire TS. Turning this flag on should automatically turn the +HTTP cache flag on. +FIXME_HOSTDB -> Store ifdef to be turned off when HostDB stops using Store +FIXME_MGMT -> Interface for warnings on the manager +FIXME_CLUSTER_ARGUMENTS -> runtime arguments for clustering etc. Needs +to be added by Eric + +cluster ifdefs +FIXME_WIRELESS_API -> RPC API's for wireless which is probably not going to +be used in the future diff --git a/iocore/cache/P_Cache.h b/iocore/cache/P_Cache.h new file mode 100644 index 00000000..1d930551 --- /dev/null +++ b/iocore/cache/P_Cache.h @@ -0,0 +1,53 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_CACHE_H__ +#define _P_CACHE_H__ + +#ifndef INLINE_CC +#undef TS_INLINE +#define TS_INLINE inline +#endif + +#define PATH_NAME_MAX 511 +#include "libts.h" +#include "P_EventSystem.h" +#include "P_AIO.h" +#include "I_RecProcess.h" + +#ifdef HTTP_CACHE +#include "HTTP.h" +#include "MIME.h" +#include "MimeTable.h" +#include "HttpTransactCache.h" +#endif + +#include "I_Cache.h" +#include "P_CacheDisk.h" +#include "P_CacheDir.h" +#include "P_RamCache.h" +#include "P_CacheVol.h" +#include "P_CacheInternal.h" +#include "P_CacheHosting.h" +#include "P_CacheHttp.h" +#endif /* _P_CACHE_H */ diff --git a/iocore/cache/P_CacheArray.h b/iocore/cache/P_CacheArray.h new file mode 100644 index 00000000..fb4adced --- /dev/null +++ b/iocore/cache/P_CacheArray.h @@ -0,0 +1,186 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __CACHE_ARRAY_H__ +#define __CACHE_ARRAY_H__ + + +#include "Resource.h" + + +#define FAST_DATA_SIZE 4 + + +template struct CacheArray +{ + CacheArray(const T * val, int initial_size = 0); + ~CacheArray(); + + operator const T *() const; + operator T *(); + T & operator[] (int idx); + T & operator() (int idx); + T *detach(); + int length(); + void clear(); + void set_length(int i) + { + pos = i - 1; + } + + void resize(int new_size); + + T *data; + T fast_data[FAST_DATA_SIZE]; + const T *default_val; + int size; + int pos; +}; + + +template TS_INLINE CacheArray::CacheArray(const T * val, int initial_size) + : +data(NULL), +default_val(val), +size(0), +pos(-1) +{ + if (initial_size > 0) { + int i = 1; + + while (i < initial_size) + i <<= 1; + + resize(i); + } +} + +template TS_INLINE CacheArray::~CacheArray() +{ + if (data) { + if (data != fast_data) { + delete[]data; + } + } +} + +template TS_INLINE CacheArray::operator const T *() +const +{ + return + data; +} + +template TS_INLINE CacheArray ::operator T *() +{ + return data; +} + +template TS_INLINE T & CacheArray::operator [](int idx) { + return data[idx]; +} + +template TS_INLINE T & CacheArray::operator ()(int idx) { + if (idx >= size) { + int new_size; + + if (size == 0) { + new_size = FAST_DATA_SIZE; + } else { + new_size = size * 2; + } + + if (idx >= new_size) { + new_size = idx + 1; + } + + resize(new_size); + } + + if (idx > pos) { + pos = idx; + } + + return data[idx]; +} + +template TS_INLINE T * CacheArray::detach() +{ + T *d; + + d = data; + data = NULL; + + return d; +} + +template TS_INLINE int CacheArray::length() +{ + return pos + 1; +} + +template TS_INLINE void CacheArray::clear() +{ + if (data) { + if (data != fast_data) { + delete[]data; + } + data = NULL; + } + + size = 0; + pos = -1; +} + +template TS_INLINE void CacheArray::resize(int new_size) +{ + if (new_size > size) { + T *new_data; + int i; + + if (new_size > FAST_DATA_SIZE) { + new_data = NEW(new T[new_size]); + } else { + new_data = fast_data; + } + + for (i = 0; i < size; i++) { + new_data[i] = data[i]; + } + + for (; i < new_size; i++) { + new_data[i] = *default_val; + } + + if (data) { + if (data != fast_data) { + delete[]data; + } + } + data = new_data; + size = new_size; + } +} + + +#endif /* __CACHE_ARRAY_H__ */ diff --git a/iocore/cache/P_CacheDir.h b/iocore/cache/P_CacheDir.h new file mode 100644 index 00000000..2d00e3b1 --- /dev/null +++ b/iocore/cache/P_CacheDir.h @@ -0,0 +1,359 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef _P_CACHE_DIR_H__ +#define _P_CACHE_DIR_H__ + +#include "P_CacheHttp.h" + +struct Vol; +struct CacheVC; + +/* + Directory layout +*/ + +// Constants + +#define DIR_TAG_WIDTH 12 +#define DIR_MASK_TAG(_t) ((_t) & ((1 << DIR_TAG_WIDTH) - 1)) +#define SIZEOF_DIR 10 +#define ESTIMATED_OBJECT_SIZE 8000 + +#define MAX_DIR_SEGMENTS (32 * (1<<16)) +#define DIR_DEPTH 4 +#define DIR_SIZE_WIDTH 6 +#define DIR_BLOCK_SIZES 4 +#define DIR_BLOCK_SHIFT(_i) (3*(_i)) +#define DIR_BLOCK_SIZE(_i) (CACHE_BLOCK_SIZE << DIR_BLOCK_SHIFT(_i)) +#define DIR_SIZE_WITH_BLOCK(_i) ((1<dir + (SIZEOF_DIR * (_i)))) +#define dir_assign(_e,_x) do { \ + (_e)->w[0] = (_x)->w[0]; \ + (_e)->w[1] = (_x)->w[1]; \ + (_e)->w[2] = (_x)->w[2]; \ + (_e)->w[3] = (_x)->w[3]; \ + (_e)->w[4] = (_x)->w[4]; \ +} while (0) +#define dir_assign_data(_e,_x) do { \ + unsigned short next = dir_next(_e); \ + dir_assign(_e, _x); \ + dir_set_next(_e, next); \ +} while(0) +// entry is valid +#define dir_valid(_d, _e) \ + (_d->header->phase == dir_phase(_e) ? vol_in_phase_valid(_d, _e) : \ + vol_out_of_phase_valid(_d, _e)) +// entry is valid and outside of write aggregation region +#define dir_agg_valid(_d, _e) \ + (_d->header->phase == dir_phase(_e) ? vol_in_phase_valid(_d, _e) : \ + vol_out_of_phase_agg_valid(_d, _e)) +// entry may be valid or overwritten in the last aggregated write +#define dir_write_valid(_d, _e) \ + (_d->header->phase == dir_phase(_e) ? vol_in_phase_valid(_d, _e) : \ + vol_out_of_phase_write_valid(_d, _e)) +#define dir_agg_buf_valid(_d, _e) \ + (_d->header->phase == dir_phase(_e) && vol_in_phase_agg_buf_valid(_d, _e)) +#define dir_is_empty(_e) (!dir_offset(_e)) +#define dir_clear(_e) do { \ + (_e)->w[0] = 0; \ + (_e)->w[1] = 0; \ + (_e)->w[2] = 0; \ + (_e)->w[3] = 0; \ + (_e)->w[4] = 0; \ +} while (0) +#define dir_clean(_e) dir_set_offset(_e,0) +#define dir_segment(_s, _d) vol_dir_segment(_d, _s) + +// OpenDir + +#define OPEN_DIR_BUCKETS 256 + +struct EvacuationBlock; +typedef uint32_t DirInfo; + +// Cache Directory + +// INTERNAL: do not access these members directly, use the +// accessors below (e.g. dir_offset, dir_set_offset). +// These structures are stored in memory 2 byte aligned. +// The accessors prevent unaligned memory access which +// is often either less efficient or unsupported depending +// on the processor. +struct Dir +{ +#if DO_NOT_REMOVE_THIS + // THE BIT-FIELD INTERPRETATION OF THIS STRUCT WHICH HAS TO + // USE MACROS TO PREVENT UNALIGNED LOADS + // bits are numbered from lowest in u16 to highest + // always index as u16 to avoid byte order issues + unsigned int offset:24; // (0,1:0-7) 16M * 512 = 8GB + unsigned int big:2; // (1:8-9) 512 << (3 * big) + unsigned int size:6; // (1:10-15) 6**2 = 64, 64*512 = 32768 .. 64*256=16MB + unsigned int tag:12; // (2:0-11) 2048 / 8 entries/bucket = .4% + unsigned int phase:1; // (2:12) + unsigned int head:1; // (2:13) first segment in a document + unsigned int pinned:1; // (2:14) + unsigned int token:1; // (2:15) + unsigned int next:16; // (3) + inku16 offset_high; // 8GB * 65k = 0.5PB (4) +#else + uint16_t w[5]; + Dir() { dir_clear(this); } +#endif +}; + +// INTERNAL: do not access these members directly, use the +// accessors below (e.g. dir_offset, dir_set_offset) +struct FreeDir +{ +#if DO_NOT_REMOVE_THIS + // THE BIT-FIELD INTERPRETATION OF THIS STRUCT WHICH HAS TO + // USE MACROS TO PREVENT UNALIGNED LOADS + unsigned int offset:24; // 0: empty + unsigned int reserved:8; + unsigned int prev:16; // (2) + unsigned int next:16; // (3) + inku16 offset_high; // 0: empty +#else + uint16_t w[5]; + FreeDir() { dir_clear(this); } +#endif +}; + +#define dir_bit(_e, _w, _b) ((uint32_t)(((_e)->w[_w] >> (_b)) & 1)) +#define dir_set_bit(_e, _w, _b, _v) (_e)->w[_w] = (uint16_t)(((_e)->w[_w] & ~(1<<(_b))) | (((_v)?1:0)<<(_b))) +#define dir_offset(_e) ((int64_t) \ + (((uint64_t)(_e)->w[0]) | \ + (((uint64_t)((_e)->w[1] & 0xFF)) << 16) | \ + (((uint64_t)(_e)->w[4]) << 24))) +#define dir_set_offset(_e,_o) do { \ + (_e)->w[0] = (uint16_t)_o; \ + (_e)->w[1] = (uint16_t)((((_o) >> 16) & 0xFF) | ((_e)->w[1] & 0xFF00)); \ + (_e)->w[4] = (uint16_t)((_o) >> 24); \ +} while (0) +#define dir_big(_e) ((uint32_t)((((_e)->w[1]) >> 8)&0x3)) +#define dir_set_big(_e, _v) (_e)->w[1] = (uint16_t)(((_e)->w[1] & 0xFCFF) | (((uint16_t)(_v))&0x3)<<8) +#define dir_size(_e) ((uint32_t)(((_e)->w[1]) >> 10)) +#define dir_set_size(_e, _v) (_e)->w[1] = (uint16_t)(((_e)->w[1] & ((1<<10)-1)) | ((_v)<<10)) +#define dir_set_approx_size(_e, _s) do { \ + if ((_s) <= DIR_SIZE_WITH_BLOCK(0)) { \ + dir_set_big(_e,0); \ + dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(0)); \ + } else if ((_s) <= DIR_SIZE_WITH_BLOCK(1)) { \ + dir_set_big(_e,1); \ + dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(1)); \ + } else if ((_s) <= DIR_SIZE_WITH_BLOCK(2)) { \ + dir_set_big(_e,2); \ + dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(2)); \ + } else { \ + dir_set_big(_e,3); \ + dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(3)); \ + } \ +} while (0) +#define dir_approx_size(_e) ((dir_size(_e) + 1) * DIR_BLOCK_SIZE(dir_big(_e))) +#define round_to_approx_dir_size(_s) (_s <= DIR_SIZE_WITH_BLOCK(0) ? ROUND_TO(_s, DIR_BLOCK_SIZE(0)) : \ + (_s <= DIR_SIZE_WITH_BLOCK(1) ? ROUND_TO(_s, DIR_BLOCK_SIZE(1)) : \ + (_s <= DIR_SIZE_WITH_BLOCK(2) ? ROUND_TO(_s, DIR_BLOCK_SIZE(2)) : \ + ROUND_TO(_s, DIR_BLOCK_SIZE(3))))) +#define dir_tag(_e) ((uint32_t)((_e)->w[2]&((1<w[2] = (uint16_t)(((_e)->w[2]&~((1<w[3] +#define dir_set_next(_e, _o) (_e)->w[3] = (uint16_t)(_o) +#define dir_prev(_e) (_e)->w[2] +#define dir_set_prev(_e,_o) (_e)->w[2] = (uint16_t)(_o) + +// INKqa11166 - Cache can not store 2 HTTP alternates simultaneously. +// To allow this, move the vector from the CacheVC to the OpenDirEntry. +// Each CacheVC now maintains a pointer to this vector. Adding/Deleting +// alternates from this vector is done under the Vol::lock. The alternate +// is deleted/inserted into the vector just before writing the vector disk +// (CacheVC::updateVector). +LINK_FORWARD_DECLARATION(CacheVC, opendir_link) // forward declaration +struct OpenDirEntry +{ + DLL writers; // list of all the current writers + DLL readers; // list of all the current readers - not used + CacheHTTPInfoVector vector; // Vector for the http document. Each writer + // maintains a pointer to this vector and + // writes it down to disk. + CacheKey single_doc_key; // Key for the resident alternate. + Dir single_doc_dir; // Directory for the resident alternate + Dir first_dir; // Dir for the vector. If empty, a new dir is + // inserted, otherwise this dir is overwritten + uint16_t num_writers; // num of current writers + uint16_t max_writers; // max number of simultaneous writers allowed + bool dont_update_directory; // if set, the first_dir is not updated. + bool move_resident_alt; // if set, single_doc_dir is inserted. + volatile bool reading_vec; // somebody is currently reading the vector + volatile bool writing_vec; // somebody is currently writing the vector + + LINK(OpenDirEntry, link); + + int wait(CacheVC *c, int msec); + + bool has_multiple_writers() + { + return num_writers > 1; + } +}; + +struct OpenDir: public Continuation +{ + Queue delayed_readers; + DLL bucket[OPEN_DIR_BUCKETS]; + + int open_write(CacheVC *c, int allow_if_writers, int max_writers); + int close_write(CacheVC *c); + OpenDirEntry *open_read(INK_MD5 *key); + int signal_readers(int event, Event *e); + + OpenDir(); +}; + +struct CacheSync: public Continuation +{ + int vol; + char *buf; + size_t buflen; + off_t writepos; + AIOCallbackInternal io; + Event *trigger; + int mainEvent(int event, Event *e); + void aio_write(int fd, char *b, int n, off_t o); + + CacheSync():Continuation(new_ProxyMutex()), vol(0), buf(0), buflen(0), writepos(0), trigger(0) + { + SET_HANDLER(&CacheSync::mainEvent); + } +}; + +// Global Functions + +void vol_init_dir(Vol *d); +int dir_token_probe(CacheKey *, Vol *, Dir *); +int dir_probe(CacheKey *, Vol *, Dir *, Dir **); +int dir_insert(CacheKey *key, Vol *d, Dir *to_part); +int dir_overwrite(CacheKey *key, Vol *d, Dir *to_part, Dir *overwrite, bool must_overwrite = true); +int dir_delete(CacheKey *key, Vol *d, Dir *del); +int dir_lookaside_probe(CacheKey *key, Vol *d, Dir *result, EvacuationBlock ** eblock); +int dir_lookaside_insert(EvacuationBlock *b, Vol *d, Dir *to); +int dir_lookaside_fixup(CacheKey *key, Vol *d); +void dir_lookaside_cleanup(Vol *d); +void dir_lookaside_remove(CacheKey *key, Vol *d); +void dir_free_entry(Dir *e, int s, Vol *d); +void dir_sync_init(); +int check_dir(Vol *d); +void dir_clean_vol(Vol *d); +void dir_clear_range(off_t start, off_t end, Vol *d); +int dir_segment_accounted(int s, Vol *d, int offby = 0, + int *free = 0, int *used = 0, + int *empty = 0, int *valid = 0, int *agg_valid = 0, int *avg_size = 0); +uint64_t dir_entries_used(Vol *d); +void sync_cache_dir_on_shutdown(); + +// Global Data + +extern Dir empty_dir; + +// Inline Funtions + +#define dir_in_seg(_s, _i) ((Dir*)(((char*)(_s)) + (SIZEOF_DIR *(_i)))) + +TS_INLINE bool +dir_compare_tag(Dir *e, CacheKey *key) +{ + return (dir_tag(e) == DIR_MASK_TAG(key->word(2))); +} + +TS_INLINE Dir * +dir_from_offset(int i, Dir *seg) +{ +#if DIR_DEPTH < 5 + if (!i) + return 0; + return dir_in_seg(seg, i); +#else + i = i + ((i - 1) / (DIR_DEPTH - 1)); + return dir_in_seg(seg, i); +#endif +} +TS_INLINE Dir * +next_dir(Dir *d, Dir *seg) +{ + int i = dir_next(d); + return dir_from_offset(i, seg); +} +TS_INLINE int +dir_to_offset(Dir *d, Dir *seg) +{ +#if DIR_DEPTH < 5 + return (((char*)d) - ((char*)seg))/SIZEOF_DIR; +#else + int i = (int)((((char*)d) - ((char*)seg))/SIZEOF_DIR); + i = i - (i / DIR_DEPTH); + return i; +#endif +} +TS_INLINE Dir * +dir_bucket(int b, Dir *seg) +{ + return dir_in_seg(seg, b * DIR_DEPTH); +} +TS_INLINE Dir * +dir_bucket_row(Dir *b, int i) +{ + return dir_in_seg(b, i); +} + +#endif /* _P_CACHE_DIR_H__ */ diff --git a/iocore/cache/P_CacheDisk.h b/iocore/cache/P_CacheDisk.h new file mode 100644 index 00000000..60379bee --- /dev/null +++ b/iocore/cache/P_CacheDisk.h @@ -0,0 +1,133 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_CACHE_DISK_H__ +#define _P_CACHE_DISK_H__ + +#include "I_Cache.h" + +extern int cache_config_max_disk_errors; + +#define DISK_BAD(_x) (_x->num_errors >= cache_config_max_disk_errors) +#define DISK_BAD_SIGNALLED(_x) (_x->num_errors > cache_config_max_disk_errors) +#define SET_DISK_BAD(_x) (_x->num_errors = cache_config_max_disk_errors) +#define SET_DISK_OKAY(_x) (_x->num_errors = 0) + +#define VOL_BLOCK_SIZE (1024 * 1024 * 128) +#define MIN_VOL_SIZE VOL_BLOCK_SIZE +#define ROUND_DOWN_TO_VOL_BLOCK(_x) (((_x) &~ (VOL_BLOCK_SIZE - 1))) +#define VOL_BLOCK_SHIFT 27 +#define ROUND_DOWN_TO_STORE_BLOCK(_x) (((_x) >> STORE_BLOCK_SHIFT) << STORE_BLOCK_SHIFT) + +#define STORE_BLOCKS_PER_VOL (VOL_BLOCK_SIZE / STORE_BLOCK_SIZE) +#define DISK_HEADER_MAGIC 0xABCD1237 + +/* each disk vol block has a corresponding Vol object */ +struct CacheDisk; + +struct DiskVolBlock +{ + uint64_t offset; // offset in bytes from the start of the disk + uint64_t len; // length in in store blocks + int number; + unsigned int type:3; + unsigned int free:1; +}; + +struct DiskVolBlockQueue +{ + DiskVolBlock *b; + int new_block; /* whether an existing vol or a new one */ + LINK(DiskVolBlockQueue, link); + + DiskVolBlockQueue() + : b(NULL), new_block(0) + { } +}; + +struct DiskVol +{ + int num_volblocks; /* number of disk volume blocks in this volume */ + int vol_number; /* the volume number of this volume */ + uint64_t size; /* size in store blocks */ + CacheDisk *disk; + Queue dpb_queue; +}; + +struct DiskHeader +{ + unsigned int magic; + unsigned int num_volumes; /* number of discrete volumes (DiskVol) */ + unsigned int num_free; /* number of disk volume blocks free */ + unsigned int num_used; /* number of disk volume blocks in use */ + unsigned int num_diskvol_blks; /* number of disk volume blocks */ + uint64_t num_blocks; + DiskVolBlock vol_info[1]; +}; + +struct CacheDisk: public Continuation +{ + DiskHeader *header; + char *path; + int header_len; + AIOCallbackInternal io; + off_t len; // in blocks (STORE_BLOCK) + off_t start; + off_t skip; + off_t num_usable_blocks; + int hw_sector_size; + int fd; + off_t free_space; + off_t wasted_space; + DiskVol **disk_vols; + DiskVol *free_blocks; + int num_errors; + int cleared; + + CacheDisk() + : Continuation(new_ProxyMutex()), header(NULL), + path(NULL), header_len(0), len(0), start(0), skip(0), + num_usable_blocks(0), fd(-1), free_space(0), wasted_space(0), + disk_vols(NULL), free_blocks(NULL), num_errors(0), cleared(0) + { } + + ~CacheDisk(); + + int open(bool clear); + int open(char *s, off_t blocks, off_t skip, int hw_sector_size, int fildes, bool clear); + int clearDisk(); + int clearDone(int event, void *data); + int openStart(int event, void *data); + int openDone(int event, void *data); + int sync(); + int syncDone(int event, void *data); + DiskVolBlock *create_volume(int number, off_t size, int scheme); + int delete_volume(int number); + int delete_all_volumes(); + void update_header(); + DiskVol *get_diskvol(int vol_number); + +}; + + +#endif diff --git a/iocore/cache/P_CacheHosting.h b/iocore/cache/P_CacheHosting.h new file mode 100644 index 00000000..97e6f240 --- /dev/null +++ b/iocore/cache/P_CacheHosting.h @@ -0,0 +1,197 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __P_CACHE_HOSTING_H__ +#define __P_CACHE_HOSTING_H__ +#include "P_Cache.h" + +#define CACHE_MEM_FREE_TIMEOUT HRTIME_SECONDS(1) + +struct Vol; +struct CacheVol; + +struct CacheHostResult; +struct Cache; + +struct CacheHostRecord +{ + int Init(int typ); + int Init(matcher_line *line_info, int typ); + void UpdateMatch(CacheHostResult *r, char *rd); + void Print(); + ~CacheHostRecord() + { + if (vols) + xfree(vols); + if (vol_hash_table) + xfree(vol_hash_table); + if (cp) + xfree(cp); + } + + int type; + Vol **vols; + volatile int good_num_vols; + volatile int num_vols; + int num_initialized; + unsigned short *vol_hash_table; + CacheVol **cp; + int num_cachevols; + + CacheHostRecord(): + type(0), vols(NULL), good_num_vols(0), num_vols(0), + num_initialized(0), vol_hash_table(0), cp(NULL), num_cachevols(0) + { } + +}; + +void build_vol_hash_table(CacheHostRecord *cp); + +struct CacheHostResult +{ + CacheHostRecord *record; + + CacheHostResult() + : record(NULL) + { } +}; + + +class CacheHostMatcher +{ +public: + CacheHostMatcher(const char *name, const char *filename, int typ); + ~CacheHostMatcher(); + + void Match(char *rdata, int rlen, CacheHostResult *result); + void AllocateSpace(int num_entries); + void NewEntry(matcher_line *line_info); + void Print(); + + int getNumElements() const { return num_el; } + CacheHostRecord *getDataArray() const { return data_array; } + HostLookup *getHLookup() const { return host_lookup; } + +private: + static void PrintFunc(void *opaque_data); + HostLookup *host_lookup; // Data structure to do the lookups + CacheHostRecord *data_array; // array of all data items + int array_len; // the length of the arrays + int num_el; // the numbe of itmems in the tree + const char *matcher_name; // Used for Debug/Warning/Error messages + const char *file_name; // Used for Debug/Warning/Error messages + int type; +}; + +class CacheHostTable +{ +public: + // Parameter name must not be deallocated before this + // object is + CacheHostTable(Cache *c, int typ); + ~CacheHostTable(); + int BuildTable(); + int BuildTableFromString(char *str); + void Match(char *rdata, int rlen, CacheHostResult *result); + void Print(); + + int getEntryCount() const { return m_numEntries; } + CacheHostMatcher *getHostMatcher() const { return hostMatch; } + + static int config_callback(const char *, RecDataT, RecData, void *); + + void register_config_callback(CacheHostTable ** p) + { + IOCORE_RegisterConfigUpdateFunc("proxy.config.cache.hosting_filename", CacheHostTable::config_callback, (void *) p); + } + + int type; + Cache *cache; + int m_numEntries; + CacheHostRecord gen_host_rec; + +private: + CacheHostMatcher *hostMatch; + const matcher_tags *config_tags; + char config_file_path[PATH_NAME_MAX]; + const char *matcher_name; // Used for Debug/Warning/Error messages +}; + +struct CacheHostTableConfig; +typedef int (CacheHostTableConfig::*CacheHostTabHandler) (int, void *); +struct CacheHostTableConfig: public Continuation +{ + CacheHostTable **ppt; + CacheHostTableConfig(CacheHostTable ** appt) + : Continuation(NULL), ppt(appt) + { + SET_HANDLER((CacheHostTabHandler) & CacheHostTableConfig::mainEvent); + } + + int mainEvent(int event, Event *e) + { + (void) e; + (void) event; + CacheHostTable *t = NEW(new CacheHostTable((*ppt)->cache, (*ppt)->type)); + CacheHostTable *old = (CacheHostTable *) ink_atomic_swap_ptr(&t, ppt); + new_Deleter(old, CACHE_MEM_FREE_TIMEOUT); + return EVENT_DONE; + } +}; + + +/* list of volumes in the volume.config file */ +struct ConfigVol +{ + int number; + int scheme; + int size; + bool in_percent; + int percent; + CacheVol *cachep; + LINK(ConfigVol, link); +}; + +struct ConfigVolumes +{ + int num_volumes; + int num_http_volumes; + int num_stream_volumes; + Queue cp_queue; + void read_config_file(); + void BuildListFromString(char *config_file_path, char *file_buf); + + void clear_all(void) + { + // remove all the volumes from the queue + for (int i = 0; i < num_volumes; i++) { + cp_queue.pop(); + } + // reset count variables + num_volumes = 0; + num_http_volumes = 0; + num_stream_volumes = 0; + } +}; + +#endif diff --git a/iocore/cache/P_CacheHttp.h b/iocore/cache/P_CacheHttp.h new file mode 100644 index 00000000..e64a2005 --- /dev/null +++ b/iocore/cache/P_CacheHttp.h @@ -0,0 +1,99 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __CACHE_HTTP_H__ +#define __CACHE_HTTP_H__ + +#include "P_CacheArray.h" +#ifdef HTTP_CACHE +#include "HTTP.h" +#include "URL.h" + + +typedef URL CacheURL; +typedef HTTPHdr CacheHTTPHdr; +typedef HTTPInfo CacheHTTPInfo; + + +#define OFFSET_BITS 24 +enum +{ + OWNER_NONE = 0, + OWNER_CACHE = 1, + OWNER_HTTP = 2 +}; + +#else +struct CacheHTTPInfo +{ +}; + +#endif //HTTP_CACHE + +struct vec_info +{ + CacheHTTPInfo alternate; +}; + +struct CacheHTTPInfoVector +{ + void *magic; + + CacheHTTPInfoVector(); + ~CacheHTTPInfoVector(); + + int count() + { + return xcount; + } + int insert(CacheHTTPInfo * info, int id = -1); + CacheHTTPInfo *get(int idx); + void detach(int idx, CacheHTTPInfo * r); + void remove(int idx, bool destroy); + void clear(bool destroy = true); + void reset() + { + xcount = 0; + data.clear(); + } + void print(char *buffer, size_t buf_size, bool temps = true); + + int marshal_length(); + int marshal(char *buf, int length); + uint32_t get_handles(const char *buf, int length, RefCountObj * block_ptr = NULL); + int unmarshal(const char *buf, int length, RefCountObj * block_ptr); + + CacheArray data; + int xcount; + Ptr vector_buf; +}; + +TS_INLINE CacheHTTPInfo * +CacheHTTPInfoVector::get(int idx) +{ + ink_assert(idx >= 0); + ink_assert(idx < xcount); + return &data[idx].alternate; +} + +#endif /* __CACHE_HTTP_H__ */ diff --git a/iocore/cache/P_CacheInternal.h b/iocore/cache/P_CacheInternal.h new file mode 100644 index 00000000..2b11408b --- /dev/null +++ b/iocore/cache/P_CacheInternal.h @@ -0,0 +1,1337 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef _P_CACHE_INTERNAL_H__ +#define _P_CACHE_INTERNAL_H__ + +#include "libts.h" + +#ifdef HTTP_CACHE +#include "HTTP.h" +#include "P_CacheHttp.h" +#endif + +struct EvacuationBlock; + +// Compilation Options + +//#define HIT_EVACUATE 1 +#define ALTERNATES 1 +// #define CACHE_LOCK_FAIL_RATE 0.001 +// #define CACHE_AGG_FAIL_RATE 0.005 +// #define CACHE_INSPECTOR_PAGES +#define MAX_CACHE_VCS_PER_THREAD 500 + +#define INTEGRAL_FRAGS 4 + +#ifdef CACHE_INSPECTOR_PAGES +#ifdef DEBUG +#define CACHE_STAT_PAGES +#endif +#endif + +#ifdef DEBUG +#define DDebug Debug +#else +#define DDebug if (0) dummy_debug +#endif + +#define AIO_SOFT_FAILURE -100000 +// retry read from writer delay +#define WRITER_RETRY_DELAY HRTIME_MSECONDS(50) + +#define CACHE_READY(_x) (CacheProcessor::cache_ready & (1 << (_x))) + +#ifndef CACHE_LOCK_FAIL_RATE +#define CACHE_TRY_LOCK(_l, _m, _t) MUTEX_TRY_LOCK(_l, _m, _t) +#else +#define CACHE_TRY_LOCK(_l, _m, _t) \ + MUTEX_TRY_LOCK(_l, _m, _t); \ + if ((uint32_t)_t->generator.random() < \ + (uint32_t)(UINT_MAX *CACHE_LOCK_FAIL_RATE)) \ + CACHE_MUTEX_RELEASE(_l) +#endif + + +#define VC_LOCK_RETRY_EVENT() \ + do { \ + trigger = mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay), event); \ + return EVENT_CONT; \ + } while (0) + +#define VC_SCHED_LOCK_RETRY() \ + do { \ + trigger = mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay)); \ + return EVENT_CONT; \ + } while (0) + +#define CONT_SCHED_LOCK_RETRY_RET(_c) \ + do { \ + _c->mutex->thread_holding->schedule_in_local(_c, HRTIME_MSECONDS(cache_config_mutex_retry_delay)); \ + return EVENT_CONT; \ + } while (0) + +#define CONT_SCHED_LOCK_RETRY(_c) \ + _c->mutex->thread_holding->schedule_in_local(_c, HRTIME_MSECONDS(cache_config_mutex_retry_delay)) + +#define VC_SCHED_WRITER_RETRY() \ + do { \ + ink_assert(!trigger); \ + writer_lock_retry++; \ + ink_hrtime _t = WRITER_RETRY_DELAY; \ + if (writer_lock_retry > 2) \ + _t = WRITER_RETRY_DELAY * 2; \ + else if (writer_lock_retry > 5) \ + _t = WRITER_RETRY_DELAY * 10; \ + else if (writer_lock_retry > 10) \ + _t = WRITER_RETRY_DELAY * 100; \ + trigger = mutex->thread_holding->schedule_in_local(this, _t); \ + return EVENT_CONT; \ + } while (0) + + + // cache stats definitions +enum +{ + cache_bytes_used_stat, + cache_bytes_total_stat, + cache_ram_cache_bytes_stat, + cache_ram_cache_bytes_total_stat, + cache_direntries_total_stat, + cache_direntries_used_stat, + cache_ram_cache_hits_stat, + cache_ram_cache_misses_stat, + cache_pread_count_stat, + cache_percent_full_stat, + cache_lookup_active_stat, + cache_lookup_success_stat, + cache_lookup_failure_stat, + cache_read_active_stat, + cache_read_success_stat, + cache_read_failure_stat, + cache_write_active_stat, + cache_write_success_stat, + cache_write_failure_stat, + cache_write_backlog_failure_stat, + cache_update_active_stat, + cache_update_success_stat, + cache_update_failure_stat, + cache_remove_active_stat, + cache_remove_success_stat, + cache_remove_failure_stat, + cache_evacuate_active_stat, + cache_evacuate_success_stat, + cache_evacuate_failure_stat, + cache_scan_active_stat, + cache_scan_success_stat, + cache_scan_failure_stat, + cache_directory_collision_count_stat, + cache_single_fragment_document_count_stat, + cache_two_fragment_document_count_stat, + cache_three_plus_plus_fragment_document_count_stat, + cache_read_busy_success_stat, + cache_read_busy_failure_stat, + cache_gc_bytes_evacuated_stat, + cache_gc_frags_evacuated_stat, + cache_write_bytes_stat, + cache_hdr_vector_marshal_stat, + cache_hdr_marshal_stat, + cache_hdr_marshal_bytes_stat, + cache_stat_count +}; + + +extern RecRawStatBlock *cache_rsb; + +#define GLOBAL_CACHE_SET_DYN_STAT(x,y) \ + RecSetGlobalRawStatSum(cache_rsb, (x), (y)) + +#define CACHE_SET_DYN_STAT(x,y) \ + RecSetGlobalRawStatSum(cache_rsb, (x), (y)) \ + RecSetGlobalRawStatSum(vol->cache_vol->vol_rsb, (x), (y)) + +#define CACHE_INCREMENT_DYN_STAT(x) \ + RecIncrRawStat(cache_rsb, mutex->thread_holding, (int) (x), 1); \ + RecIncrRawStat(vol->cache_vol->vol_rsb, mutex->thread_holding, (int) (x), 1); + +#define CACHE_DECREMENT_DYN_STAT(x) \ + RecIncrRawStat(cache_rsb, mutex->thread_holding, (int) (x), -1); \ + RecIncrRawStat(vol->cache_vol->vol_rsb, mutex->thread_holding, (int) (x), -1); + +#define CACHE_VOL_SUM_DYN_STAT(x,y) \ + RecIncrRawStat(vol->cache_vol->vol_rsb, mutex->thread_holding, (int) (x), (int) y); + +#define CACHE_SUM_DYN_STAT(x, y) \ + RecIncrRawStat(cache_rsb, mutex->thread_holding, (int) (x), (int) (y)); \ + RecIncrRawStat(vol->cache_vol->vol_rsb, mutex->thread_holding, (int) (x), (int) (y)); + +#define CACHE_SUM_DYN_STAT_THREAD(x, y) \ + RecIncrRawStat(cache_rsb, this_ethread(), (int) (x), (int) (y)); \ + RecIncrRawStat(vol->cache_vol->vol_rsb, this_ethread(), (int) (x), (int) (y)); + +#define GLOBAL_CACHE_SUM_GLOBAL_DYN_STAT(x, y) \ + RecIncrGlobalRawStatSum(cache_rsb,(x),(y)) + +#define CACHE_SUM_GLOBAL_DYN_STAT(x, y) \ + RecIncrGlobalRawStatSum(cache_rsb,(x),(y)) \ + RecIncrGlobalRawStatSum(vol->cache_vol->vol_rsb,(x),(y)) + +#define CACHE_CLEAR_DYN_STAT(x) \ +do { \ + RecSetRawStatSum(cache_rsb, (x), 0); \ + RecSetRawStatCount(cache_rsb, (x), 0); \ + RecSetRawStatSum(vol->cache_vol->vol_rsb, (x), 0); \ + RecSetRawStatCount(vol->cache_vol->vol_rsb, (x), 0); \ +} while (0); + +// Configuration +extern int cache_config_dir_sync_frequency; +extern int cache_config_http_max_alts; +extern int cache_config_permit_pinning; +extern int cache_config_select_alternate; +extern int cache_config_vary_on_user_agent; +extern int cache_config_max_doc_size; +extern int cache_config_min_average_object_size; +extern int cache_config_agg_write_backlog; +extern int cache_config_enable_checksum; +extern int cache_config_alt_rewrite_max_size; +extern int cache_config_read_while_writer; +extern char cache_system_config_directory[PATH_NAME_MAX + 1]; +extern int cache_clustering_enabled; +extern int cache_config_agg_write_backlog; +extern int cache_config_ram_cache_compress; +extern int cache_config_ram_cache_compress_percent; +#ifdef HIT_EVACUATE +extern int cache_config_hit_evacuate_percent; +extern int cache_config_hit_evacuate_size_limit; +#endif +extern int cache_config_force_sector_size; +extern int cache_config_target_fragment_size; +extern int cache_config_mutex_retry_delay; + +// CacheVC +struct CacheVC: public CacheVConnection +{ + CacheVC(); + + VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf); + VIO *do_io_pread(Continuation *c, int64_t nbytes, MIOBuffer *buf, int64_t offset); + VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false); + void do_io_close(int lerrno = -1); + void reenable(VIO *avio); + void reenable_re(VIO *avio); + bool get_data(int i, void *data); + bool set_data(int i, void *data); + + bool is_ram_cache_hit() + { + ink_assert(vio.op == VIO::READ); + return !f.not_from_ram_cache; + } + int get_header(void **ptr, int *len) + { + if (first_buf.m_ptr) { + Doc *doc = (Doc*)first_buf->data(); + *ptr = doc->hdr(); + *len = doc->hlen; + return 0; + } else + return -1; + } + int set_header(void *ptr, int len) + { + header_to_write = ptr; + header_to_write_len = len; + return 0; + } + int get_single_data(void **ptr, int *len) + { + if (first_buf.m_ptr) { + Doc *doc = (Doc*)first_buf->data(); + if (doc->data_len() == doc->total_len) { + *ptr = doc->data(); + *len = doc->data_len(); + return 0; + } + } + return -1; + } + + bool writer_done(); + int calluser(int event); + int callcont(int event); + int die(); + int dead(int event, Event *e); + + int handleReadDone(int event, Event *e); + int handleRead(int event, Event *e); + int do_read_call(CacheKey *akey); + int handleWrite(int event, Event *e); + int handleWriteLock(int event, Event *e); + int do_write_call(); + int do_write_lock(); + int do_write_lock_call(); + int do_sync(uint32_t target_write_serial); + + int openReadClose(int event, Event *e); + int openReadReadDone(int event, Event *e); + int openReadMain(int event, Event *e); + int openReadStartEarliest(int event, Event *e); +#ifdef HTTP_CACHE + int openReadVecWrite(int event, Event *e); +#endif + int openReadStartHead(int event, Event *e); + int openReadFromWriter(int event, Event *e); + int openReadFromWriterMain(int event, Event *e); + int openReadFromWriterFailure(int event, Event *); + int openReadChooseWriter(int event, Event *e); + + int openWriteCloseDir(int event, Event *e); + int openWriteCloseHeadDone(int event, Event *e); + int openWriteCloseHead(int event, Event *e); + int openWriteCloseDataDone(int event, Event *e); + int openWriteClose(int event, Event *e); + int openWriteRemoveVector(int event, Event *e); + int openWriteWriteDone(int event, Event *e); + int openWriteOverwrite(int event, Event *e); + int openWriteMain(int event, Event *e); + int openWriteStartDone(int event, Event *e); + int openWriteStartBegin(int event, Event *e); + + int updateVector(int event, Event *e); + int updateReadDone(int event, Event *e); + int updateVecWrite(int event, Event *e); + + int removeEvent(int event, Event *e); + + int linkWrite(int event, Event *e); + int derefRead(int event, Event *e); + + int scanVol(int event, Event *e); + int scanObject(int event, Event *e); + int scanUpdateDone(int event, Event *e); + int scanOpenWrite(int event, Event *e); + int scanRemoveDone(int event, Event *e); + + int is_io_in_progress() + { + return io.aiocb.aio_fildes != AIO_NOT_IN_PROGRESS; + } + void set_io_not_in_progress() + { + io.aiocb.aio_fildes = AIO_NOT_IN_PROGRESS; + } + void set_agg_write_in_progress() + { + io.aiocb.aio_fildes = AIO_AGG_WRITE_IN_PROGRESS; + } + int evacuateDocDone(int event, Event *e); + int evacuateReadHead(int event, Event *e); + + void cancel_trigger(); + virtual int64_t get_object_size(); +#ifdef HTTP_CACHE + virtual void set_http_info(CacheHTTPInfo *info); + virtual void get_http_info(CacheHTTPInfo ** info); +#endif + virtual bool set_pin_in_cache(time_t time_pin); + virtual time_t get_pin_in_cache(); + virtual bool set_disk_io_priority(int priority); + virtual int get_disk_io_priority(); + + // offsets from the base stat +#define CACHE_STAT_ACTIVE 0 +#define CACHE_STAT_SUCCESS 1 +#define CACHE_STAT_FAILURE 2 + + // number of bytes to memset to 0 in the CacheVC when we free + // it. All member variables starting from vio are memset to 0. + // This variable is initialized in CacheVC constructor. + static int size_to_init; + + // Start Region A + // This set of variables are not reset when the cacheVC is freed. + // A CacheVC must set these to the correct values whenever needed + // These are variables that are always set to the correct values + // before being used by the CacheVC + CacheKey key, first_key, earliest_key, update_key; + Dir dir, earliest_dir, overwrite_dir, first_dir; + // end Region A + + // Start Region B + // These variables are individually cleared or reset when the + // CacheVC is freed. All these variables must be reset/cleared + // in free_CacheVC. + Action _action; +#ifdef HTTP_CACHE + CacheHTTPHdr request; +#endif + CacheHTTPInfoVector vector; + CacheHTTPInfo alternate; + Ptr buf; + Ptr first_buf; + Ptr blocks; // data available to write + Ptr writer_buf; + + OpenDirEntry *od; + AIOCallbackInternal io; + int alternate_index; // preferred position in vector + LINK(CacheVC, opendir_link); +#ifdef CACHE_STAT_PAGES + LINK(CacheVC, stat_link); +#endif + // end Region B + + // Start Region C + // These variables are memset to 0 when the structure is freed. + // The size of this region is size_to_init which is initialized + // in the CacheVC constuctor. It assumes that vio is the start + // of this region. + // NOTE: NOTE: NOTE: If vio is NOT the start, then CHANGE the + // size_to_init initialization + VIO vio; + EThread *initial_thread; // initial thread open_XX was called on + CacheFragType frag_type; + CacheHTTPInfo *info; + CacheHTTPInfoVector *write_vector; +#ifdef HTTP_CACHE + CacheLookupHttpConfig *params; +#endif + int header_len; // for communicating with agg_copy + int frag_len; // for communicating with agg_copy + uint32_t write_len; // for communicating with agg_copy + uint32_t agg_len; // for communicating with aggWrite + uint32_t write_serial; // serial of the final write for SYNC + Frag *frag; // arraylist of fragment offset + Frag integral_frags[INTEGRAL_FRAGS]; + Vol *vol; + Dir *last_collision; + Event *trigger; + CacheKey *read_key; + ContinuationHandler save_handler; + uint32_t pin_in_cache; + ink_hrtime start_time; + int base_stat; + int recursive; + int closed; + int64_t seek_to; // pread offset + int64_t offset; // offset into 'blocks' of data to write + int64_t writer_offset; // offset of the writer for reading from a writer + int64_t length; // length of data available to write + int64_t doc_pos; // read position in 'buf' + uint64_t write_pos; // length written + uint64_t total_len; // total length written and available to write + uint64_t doc_len; // total_length (of the selected alternate for HTTP) + uint64_t update_len; + int fragment; + int scan_msec_delay; + CacheVC *write_vc; + char *hostname; + int host_len; + int header_to_write_len; + void *header_to_write; + short writer_lock_retry; + + union + { + uint32_t flags; + struct + { + unsigned int use_first_key:1; + unsigned int overwrite:1; // overwrite first_key Dir if it exists + unsigned int close_complete:1; // WRITE_COMPLETE is final + unsigned int sync:1; // write to be committed to durable storage before WRITE_COMPLETE + unsigned int evacuator:1; + unsigned int single_fragment:1; + unsigned int evac_vector:1; + unsigned int lookup:1; + unsigned int update:1; + unsigned int remove:1; + unsigned int remove_aborted_writers:1; + unsigned int open_read_timeout:1; // UNUSED + unsigned int data_done:1; + unsigned int read_from_writer_called:1; + unsigned int not_from_ram_cache:1; // entire object was from ram cache + unsigned int rewrite_resident_alt:1; + unsigned int readers:1; + unsigned int doc_from_ram_cache:1; +#ifdef HIT_EVACUATE + unsigned int hit_evacuate:1; +#endif + } f; + }; + // BTF optimization used to skip reading stuff in cache partition that doesn't contain any + // dir entries. + char *scan_vol_map; + // BTF fix to handle objects that overlapped over two different reads, + // this is how much we need to back up the buffer to get the start of the overlapping object. + off_t scan_fix_buffer_offset; + //end region C +}; + +#define PUSH_HANDLER(_x) do { \ + ink_assert(handler != (ContinuationHandler)(&CacheVC::dead)); \ + save_handler = handler; handler = (ContinuationHandler)(_x); \ +} while (0) + +#define POP_HANDLER do { \ + handler = save_handler; \ + ink_assert(handler != (ContinuationHandler)(&CacheVC::dead)); \ + } while (0) + +struct CacheRemoveCont: public Continuation +{ + int event_handler(int event, void *data); + + CacheRemoveCont() + : Continuation(NULL) + { } +}; + + +// Global Data + +extern ClassAllocator cacheVConnectionAllocator; +extern CacheKey zero_key; +extern CacheSync *cacheDirSync; +// Function Prototypes +#ifdef HTTP_CACHE +int cache_write(CacheVC *, CacheHTTPInfoVector *); +int get_alternate_index(CacheHTTPInfoVector *cache_vector, CacheKey key); +#endif +CacheVC *new_DocEvacuator(int nbytes, Vol *d); + +// inline Functions + +TS_INLINE CacheVC * +new_CacheVC(Continuation *cont) +{ + EThread *t = cont->mutex->thread_holding; + CacheVC *c = THREAD_ALLOC(cacheVConnectionAllocator, t); +#ifdef HTTP_CACHE + c->vector.data.data = &c->vector.data.fast_data[0]; +#endif + c->_action = cont; + c->initial_thread = t; + c->mutex = cont->mutex; + c->start_time = ink_get_hrtime(); + ink_assert(c->trigger == NULL); + Debug("cache_new", "new %p", c); +#ifdef CACHE_STAT_PAGES + ink_assert(!c->stat_link.next); + ink_assert(!c->stat_link.prev); +#endif + dir_clear(&c->dir); + return c; +} + +TS_INLINE int +free_CacheVC(CacheVC *cont) +{ + Debug("cache_free", "free %p", cont); + ProxyMutex *mutex = cont->mutex; + Vol *vol = cont->vol; + if (vol) { + CACHE_DECREMENT_DYN_STAT(cont->base_stat + CACHE_STAT_ACTIVE); + if (cont->closed > 0) { + CACHE_INCREMENT_DYN_STAT(cont->base_stat + CACHE_STAT_SUCCESS); + } // else abort,cancel + } + ink_debug_assert(mutex->thread_holding == this_ethread()); + if (cont->trigger) + cont->trigger->cancel(); + ink_assert(!cont->is_io_in_progress()); + ink_assert(!cont->od); + /* calling cont->io.action = NULL causes compile problem on 2.6 solaris + release build....wierd??? For now, null out continuation and mutex + of the action separately */ + cont->io.action.continuation = NULL; + cont->io.action.mutex = NULL; + cont->io.mutex.clear(); + cont->io.aio_result = 0; + cont->io.aiocb.aio_nbytes = 0; + cont->io.aiocb.aio_reqprio = AIO_DEFAULT_PRIORITY; +#ifdef HTTP_CACHE + cont->request.reset(); + cont->vector.clear(); +#endif + cont->vio.buffer.clear(); + cont->vio.mutex.clear(); +#ifdef HTTP_CACHE + if (cont->vio.op == VIO::WRITE && cont->alternate_index == CACHE_ALT_INDEX_DEFAULT) + cont->alternate.destroy(); + else + cont->alternate.clear(); +#endif + cont->_action.cancelled = 0; + cont->_action.mutex.clear(); + cont->mutex.clear(); + cont->buf.clear(); + cont->first_buf.clear(); + cont->blocks.clear(); + cont->writer_buf.clear(); + cont->alternate_index = CACHE_ALT_INDEX_DEFAULT; + if (cont->frag && cont->frag != cont->integral_frags) + xfree(cont->frag); + if (cont->scan_vol_map) + xfree(cont->scan_vol_map); + memset((char *) &cont->vio, 0, cont->size_to_init); +#ifdef CACHE_STAT_PAGES + ink_assert(!cont->stat_link.next && !cont->stat_link.prev); +#endif +#ifdef DEBUG + SET_CONTINUATION_HANDLER(cont, &CacheVC::dead); +#endif + THREAD_FREE_TO(cont, cacheVConnectionAllocator, this_ethread(), MAX_CACHE_VCS_PER_THREAD); + return EVENT_DONE; +} + +TS_INLINE int +CacheVC::calluser(int event) +{ + recursive++; + ink_debug_assert(!vol || this_ethread() != vol->mutex->thread_holding); + vio._cont->handleEvent(event, (void *) &vio); + recursive--; + if (closed) { + die(); + return EVENT_DONE; + } + return EVENT_CONT; +} + +TS_INLINE int +CacheVC::callcont(int event) +{ + recursive++; + ink_debug_assert(!vol || this_ethread() != vol->mutex->thread_holding); + _action.continuation->handleEvent(event, this); + recursive--; + if (closed) + die(); + else if (vio.vc_server) + handleEvent(EVENT_IMMEDIATE, 0); + return EVENT_DONE; +} + +TS_INLINE int +CacheVC::do_read_call(CacheKey *akey) +{ + doc_pos = 0; + read_key = akey; + io.aiocb.aio_nbytes = dir_approx_size(&dir); + PUSH_HANDLER(&CacheVC::handleRead); + return handleRead(EVENT_CALL, 0); +} + +TS_INLINE int +CacheVC::do_write_call() +{ + PUSH_HANDLER(&CacheVC::handleWrite); + return handleWrite(EVENT_CALL, 0); +} + +TS_INLINE void +CacheVC::cancel_trigger() +{ + if (trigger) { + trigger->cancel_action(); + trigger = NULL; + } +} + +TS_INLINE int +CacheVC::die() +{ + if (vio.op == VIO::WRITE) { +#ifdef HTTP_CACHE + if (f.update && total_len) { + alternate.object_key_set(earliest_key); + } +#endif + if (!is_io_in_progress()) { + SET_HANDLER(&CacheVC::openWriteClose); + if (!recursive) + openWriteClose(EVENT_NONE, NULL); + } // else catch it at the end of openWriteWriteDone + return EVENT_CONT; + } else { + if (is_io_in_progress()) + save_handler = (ContinuationHandler) & CacheVC::openReadClose; + else { + SET_HANDLER(&CacheVC::openReadClose); + if (!recursive) + openReadClose(EVENT_NONE, NULL); + } + return EVENT_CONT; + } +} + +TS_INLINE int +CacheVC::handleWriteLock(int event, Event *e) +{ + NOWARN_UNUSED(event); + cancel_trigger(); + int ret = 0; + { + CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding); + if (!lock) { + set_agg_write_in_progress(); + trigger = mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay)); + return EVENT_CONT; + } + ret = handleWrite(EVENT_CALL, e); + } + if (ret == EVENT_RETURN) + return handleEvent(AIO_EVENT_DONE, 0); + return EVENT_CONT; +} + +TS_INLINE int +CacheVC::do_write_lock() +{ + PUSH_HANDLER(&CacheVC::handleWriteLock); + return handleWriteLock(EVENT_NONE, 0); +} + +TS_INLINE int +CacheVC::do_write_lock_call() +{ + PUSH_HANDLER(&CacheVC::handleWriteLock); + return handleWriteLock(EVENT_CALL, 0); +} + +TS_INLINE bool +CacheVC::writer_done() +{ + OpenDirEntry *cod = od; + if (!cod) + cod = vol->open_read(&first_key); + CacheVC *w = (cod) ? cod->writers.head : NULL; + // If the write vc started after the reader, then its not the + // original writer, since we never choose a writer that started + // after the reader. The original writer was deallocated and then + // reallocated for the same first_key + for (; w && (w != write_vc || w->start_time > start_time); w = (CacheVC *) w->opendir_link.next); + if (!w) + return true; + return false; +} + +TS_INLINE int +Vol::close_write(CacheVC *cont) +{ + +#ifdef CACHE_STAT_PAGES + ink_assert(stat_cache_vcs.head); + stat_cache_vcs.remove(cont, cont->stat_link); + ink_assert(!cont->stat_link.next && !cont->stat_link.prev); +#endif + return open_dir.close_write(cont); +} + +// Returns 0 on success or a positive error code on failure +TS_INLINE int +Vol::open_write(CacheVC *cont, int allow_if_writers, int max_writers) +{ + Vol *vol = this; + bool agg_error = false; + if (!cont->f.remove) { + agg_error = (!cont->f.update && agg_todo_size > cache_config_agg_write_backlog); +#ifdef CACHE_AGG_FAIL_RATE + agg_error = agg_error || ((uint32_t) mutex->thread_holding->generator.random() < + (uint32_t) (UINT_MAX * CACHE_AGG_FAIL_RATE)); +#endif + } + if (agg_error) { + CACHE_INCREMENT_DYN_STAT(cache_write_backlog_failure_stat); + return ECACHE_WRITE_FAIL; + } + if (open_dir.open_write(cont, allow_if_writers, max_writers)) { +#ifdef CACHE_STAT_PAGES + ink_debug_assert(cont->mutex->thread_holding == this_ethread()); + ink_assert(!cont->stat_link.next && !cont->stat_link.prev); + stat_cache_vcs.enqueue(cont, cont->stat_link); +#endif + return 0; + } + return ECACHE_DOC_BUSY; +} + +TS_INLINE int +Vol::close_write_lock(CacheVC *cont) +{ + EThread *t = cont->mutex->thread_holding; + CACHE_TRY_LOCK(lock, mutex, t); + if (!lock) + return -1; + return close_write(cont); +} + +TS_INLINE int +Vol::open_write_lock(CacheVC *cont, int allow_if_writers, int max_writers) +{ + EThread *t = cont->mutex->thread_holding; + CACHE_TRY_LOCK(lock, mutex, t); + if (!lock) + return -1; + return open_write(cont, allow_if_writers, max_writers); +} + +TS_INLINE OpenDirEntry * +Vol::open_read_lock(INK_MD5 *key, EThread *t) +{ + CACHE_TRY_LOCK(lock, mutex, t); + if (!lock) + return NULL; + return open_dir.open_read(key); +} + +TS_INLINE int +Vol::begin_read_lock(CacheVC *cont) +{ + // no need for evacuation as the entire document is already in memory +#ifndef CACHE_STAT_PAGES + if (cont->f.single_fragment) + return 0; +#endif + // VC is enqueued in stat_cache_vcs in the begin_read call + EThread *t = cont->mutex->thread_holding; + CACHE_TRY_LOCK(lock, mutex, t); + if (!lock) + return -1; + return begin_read(cont); +} + +TS_INLINE int +Vol::close_read_lock(CacheVC *cont) +{ + EThread *t = cont->mutex->thread_holding; + CACHE_TRY_LOCK(lock, mutex, t); + if (!lock) + return -1; + return close_read(cont); +} + +TS_INLINE int +dir_delete_lock(CacheKey *key, Vol *d, ProxyMutex *m, Dir *del) +{ + EThread *thread = m->thread_holding; + CACHE_TRY_LOCK(lock, d->mutex, thread); + if (!lock) + return -1; + return dir_delete(key, d, del); +} + +TS_INLINE int +dir_insert_lock(CacheKey *key, Vol *d, Dir *to_part, ProxyMutex *m) +{ + EThread *thread = m->thread_holding; + CACHE_TRY_LOCK(lock, d->mutex, thread); + if (!lock) + return -1; + return dir_insert(key, d, to_part); +} + +TS_INLINE int +dir_overwrite_lock(CacheKey *key, Vol *d, Dir *to_part, ProxyMutex *m, Dir *overwrite, bool must_overwrite = true) +{ + EThread *thread = m->thread_holding; + CACHE_TRY_LOCK(lock, d->mutex, thread); + if (!lock) + return -1; + return dir_overwrite(key, d, to_part, overwrite, must_overwrite); +} + +void TS_INLINE +rand_CacheKey(CacheKey *next_key, ProxyMutex *mutex) +{ + next_key->b[0] = mutex->thread_holding->generator.random(); + next_key->b[1] = mutex->thread_holding->generator.random(); +} + +extern uint8_t CacheKey_next_table[]; +void TS_INLINE +next_CacheKey(CacheKey *next_key, CacheKey *key) +{ + uint8_t *b = (uint8_t *) next_key; + uint8_t *k = (uint8_t *) key; + b[0] = CacheKey_next_table[k[0]]; + for (int i = 1; i < 16; i++) + b[i] = CacheKey_next_table[(b[i - 1] + k[i]) & 0xFF]; +} +extern uint8_t CacheKey_prev_table[]; +void TS_INLINE +prev_CacheKey(CacheKey *prev_key, CacheKey *key) +{ + uint8_t *b = (uint8_t *) prev_key; + uint8_t *k = (uint8_t *) key; + for (int i = 15; i > 0; i--) + b[i] = 256 + CacheKey_prev_table[k[i]] - k[i - 1]; + b[0] = CacheKey_prev_table[k[0]]; +} + +TS_INLINE unsigned int +next_rand(unsigned int *p) +{ + unsigned int seed = *p; + seed = 1103515145 * seed + 12345; + *p = seed; + return seed; +} + +extern ClassAllocator cacheRemoveContAllocator; + +TS_INLINE CacheRemoveCont * +new_CacheRemoveCont() +{ + CacheRemoveCont *cache_rm = cacheRemoveContAllocator.alloc(); + + cache_rm->mutex = new_ProxyMutex(); + SET_CONTINUATION_HANDLER(cache_rm, &CacheRemoveCont::event_handler); + return cache_rm; +} + +TS_INLINE void +free_CacheRemoveCont(CacheRemoveCont *cache_rm) +{ + cache_rm->mutex = NULL; + cacheRemoveContAllocator.free(cache_rm); +} + +TS_INLINE int +CacheRemoveCont::event_handler(int event, void *data) +{ + (void) event; + (void) data; + free_CacheRemoveCont(this); + return EVENT_DONE; +} + +int64_t cache_bytes_used(void); +int64_t cache_bytes_total(void); + +#ifdef DEBUG +#define CACHE_DEBUG_INCREMENT_DYN_STAT(_x) CACHE_INCREMENT_DYN_STAT(_x) +#define CACHE_DEBUG_SUM_DYN_STAT(_x,_y) CACHE_SUM_DYN_STAT(_x,_y) +#else +#define CACHE_DEBUG_INCREMENT_DYN_STAT(_x) +#define CACHE_DEBUG_SUM_DYN_STAT(_x,_y) +#endif + +struct CacheHostRecord; +struct Vol; +class CacheHostTable; + +struct Cache +{ + volatile int cache_read_done; + volatile int total_good_nvol; + volatile int total_nvol; + volatile int ready; + int64_t cache_size; //in store block size + CacheHostTable *hosttable; + volatile int total_initialized_vol; + int scheme; + + int open(bool reconfigure, bool fix); + int close(); + + Action *lookup(Continuation *cont, CacheKey *key, CacheFragType type, char *hostname, int host_len); + inkcoreapi Action *open_read(Continuation *cont, CacheKey *key, CacheFragType type, char *hostname, int len); + inkcoreapi Action *open_write(Continuation *cont, CacheKey *key, + CacheFragType frag_type, int options = 0, + time_t pin_in_cache = (time_t) 0, char *hostname = 0, int host_len = 0); + inkcoreapi Action *remove(Continuation *cont, CacheKey *key, + CacheFragType type = CACHE_FRAG_TYPE_HTTP, + bool user_agents = true, bool link = false, + char *hostname = 0, int host_len = 0); + Action *scan(Continuation *cont, char *hostname = 0, int host_len = 0, int KB_per_second = 2500); + +#ifdef HTTP_CACHE + Action *lookup(Continuation *cont, URL *url, CacheFragType type); + inkcoreapi Action *open_read(Continuation *cont, CacheKey *key, + CacheHTTPHdr *request, + CacheLookupHttpConfig *params, CacheFragType type, char *hostname, int host_len); + Action *open_read(Continuation *cont, URL *url, CacheHTTPHdr *request, + CacheLookupHttpConfig *params, CacheFragType type); + Action *open_write(Continuation *cont, CacheKey *key, + CacheHTTPInfo *old_info, time_t pin_in_cache = (time_t) 0, + CacheKey *key1 = NULL, + CacheFragType type = CACHE_FRAG_TYPE_HTTP, char *hostname = 0, int host_len = 0); + Action *open_write(Continuation *cont, URL *url, CacheHTTPHdr *request, + CacheHTTPInfo *old_info, time_t pin_in_cache = (time_t) 0, + CacheFragType type = CACHE_FRAG_TYPE_HTTP); + static void generate_key(INK_MD5 *md5, URL *url, CacheHTTPHdr *request); +#endif + + Action *link(Continuation *cont, CacheKey *from, CacheKey *to, CacheFragType type, char *hostname, int host_len); + Action *deref(Continuation *cont, CacheKey *key, CacheFragType type, char *hostname, int host_len); + + void vol_initialized(bool result); + + int open_done(); + + Vol *key_to_vol(CacheKey *key, char *hostname, int host_len); + + Cache() + : cache_read_done(0), total_good_nvol(0), total_nvol(0), ready(CACHE_INITIALIZING), cache_size(0), // in store block size + hosttable(NULL), total_initialized_vol(0), scheme(CACHE_NONE_TYPE) + { } +}; + +extern Cache *theCache; +extern Cache *theStreamCache; +inkcoreapi extern Cache *caches[NUM_CACHE_FRAG_TYPES]; + +#ifdef HTTP_CACHE +TS_INLINE Action * +Cache::open_read(Continuation *cont, CacheURL *url, CacheHTTPHdr *request, + CacheLookupHttpConfig *params, CacheFragType type) +{ + INK_MD5 md5; + int len; + url->MD5_get(&md5); + const char *hostname = url->host_get(&len); + return open_read(cont, &md5, request, params, type, (char *) hostname, len); +} + +TS_INLINE void +Cache::generate_key(INK_MD5 *md5, URL *url, CacheHTTPHdr *request) +{ + NOWARN_UNUSED(request); +#ifdef BROKEN_HACK_FOR_VARY_ON_UA + // We probably should make this configurable, both enabling it and what + // MIME types we want to treat differently. // Leif + + if (cache_config_vary_on_user_agent && request) { + // If we are varying on user-agent, we only want to do + // this for text content-types since expirence says + // images do not vary. Varying on images decimiates + // the hitrate (INKqa04820) + + // HDR FIX ME - mimeTable needs to be updated to support + // ptr/len pairs + + // Note: if 'proxy.config.http.global_user_agent_header' is set, we + // should ignore 'cache_config_vary_on_user_agent' flag because + // all requests to OS were sent with one so-called 'global user agent' + // header instead of original client's 'user-agent' + + MimeTableEntry *url_mime_type_entry = +// mimeTable.get_entry_path(url->path_get()); + NULL; + + if (url_mime_type_entry && strstr(url_mime_type_entry->mime_type, "text")) { + url->MD5_get(md5); + int ua_len; + const char *value = request->value_get(MIME_FIELD_USER_AGENT, + MIME_LEN_USER_AGENT, &ua_len); + if (value) { + INK_DIGEST_CTX context; + // Mix the user-agent and URL INK_MD5's + ink_code_incr_md5_init(&context); + ink_code_incr_md5_update(&context, value, ua_len); + ink_code_incr_md5_update(&context, (char *) md5, sizeof(INK_MD5)); + ink_code_incr_md5_final((char *) md5, &context); + } + return; + } + } +#endif /* BROKEN_HACK_FOR_VARY_ON_UA */ + url->MD5_get(md5); +} + +TS_INLINE Action * +Cache::open_write(Continuation *cont, CacheURL *url, CacheHTTPHdr *request, + CacheHTTPInfo *old_info, time_t pin_in_cache, CacheFragType type) +{ + (void) request; + INK_MD5 url_md5; + url->MD5_get(&url_md5); + int len; + const char *hostname = url->host_get(&len); + + return open_write(cont, &url_md5, old_info, pin_in_cache, NULL, type, (char *) hostname, len); +} +#endif + +TS_INLINE unsigned int +cache_hash(INK_MD5 & md5) +{ + uint64_t f = md5.fold(); + unsigned int mhash = (unsigned int) (f >> 32); + return mhash; +} + +#ifdef HTTP_CACHE +#define CLUSTER_CACHE +#endif +#ifdef CLUSTER_CACHE +#include "P_Net.h" +#include "P_ClusterInternal.h" +// Note: This include must occur here in order to avoid numerous forward +// reference problems. +#include "P_ClusterInline.h" +#endif + +TS_INLINE Action * +CacheProcessor::lookup(Continuation *cont, CacheKey *key, bool local_only, + CacheFragType frag_type, char *hostname, int host_len) +{ + (void) local_only; +#ifdef CLUSTER_CACHE + // Try to send remote, if not possible, handle locally + if ((cache_clustering_enabled > 0) && !local_only) { + Action *a = Cluster_lookup(cont, key, frag_type, hostname, host_len); + if (a) { + return a; + } + } +#endif + return caches[frag_type]->lookup(cont, key, frag_type, hostname, host_len); +} + +TS_INLINE inkcoreapi Action * +CacheProcessor::open_read(Continuation *cont, CacheKey *key, CacheFragType frag_type, char *hostname, int host_len) +{ +#ifdef CLUSTER_CACHE + if (cache_clustering_enabled > 0) { + return open_read_internal(CACHE_OPEN_READ, cont, (MIOBuffer *) 0, + (CacheURL *) 0, (CacheHTTPHdr *) 0, + (CacheLookupHttpConfig *) 0, key, 0, frag_type, hostname, host_len); + } +#endif + return caches[frag_type]->open_read(cont, key, frag_type, hostname, host_len); +} + +TS_INLINE Action * +CacheProcessor::open_read_buffer(Continuation *cont, MIOBuffer *buf, CacheKey *key, CacheFragType frag_type, + char *hostname, int host_len) +{ + (void) buf; +#ifdef CLUSTER_CACHE + if (cache_clustering_enabled > 0) { + return open_read_internal(CACHE_OPEN_READ_BUFFER, cont, buf, + (CacheURL *) 0, (CacheHTTPHdr *) 0, + (CacheLookupHttpConfig *) 0, key, 0, frag_type, hostname, host_len); + } +#endif + return caches[frag_type]->open_read(cont, key, frag_type, hostname, host_len); +} + + +TS_INLINE inkcoreapi Action * +CacheProcessor::open_write(Continuation *cont, CacheKey *key, CacheFragType frag_type, + int expected_size, int options, time_t pin_in_cache, + char *hostname, int host_len) +{ + (void) expected_size; +#ifdef CLUSTER_CACHE + ClusterMachine *m = cluster_machine_at_depth(cache_hash(*key)); + + if (m && (cache_clustering_enabled > 0)) { + return Cluster_write(cont, expected_size, (MIOBuffer *) 0, m, + key, frag_type, options, pin_in_cache, + CACHE_OPEN_WRITE, key, (CacheURL *) 0, + (CacheHTTPHdr *) 0, (CacheHTTPInfo *) 0, hostname, host_len); + } +#endif + return caches[frag_type]->open_write(cont, key, frag_type, options, pin_in_cache, hostname, host_len); +} + +TS_INLINE Action * +CacheProcessor::open_write_buffer(Continuation *cont, MIOBuffer *buf, CacheKey *key, + CacheFragType frag_type, int options, time_t pin_in_cache, + char *hostname, int host_len) +{ + NOWARN_UNUSED(pin_in_cache); + (void)cont; + (void)buf; + (void)key; + (void)frag_type; + (void)options; + (void)hostname; + (void)host_len; + ink_assert(!"implemented"); + return NULL; +} + +TS_INLINE Action * +CacheProcessor::remove(Continuation *cont, CacheKey *key, CacheFragType frag_type, + bool rm_user_agents, bool rm_link, char *hostname, int host_len) +{ + Debug("cache_remove", "[CacheProcessor::remove] Issuing cache delete for %u", cache_hash(*key)); +#ifdef CLUSTER_CACHE + if (cache_clustering_enabled > 0) { + ClusterMachine *m = cluster_machine_at_depth(cache_hash(*key)); + + if (m) { + return Cluster_remove(m, cont, key, rm_user_agents, rm_link, frag_type, hostname, host_len); + } + } +#endif + return caches[frag_type]->remove(cont, key, frag_type, rm_user_agents, rm_link, hostname, host_len); +} + +TS_INLINE Action * +scan(Continuation *cont, char *hostname = 0, int host_len = 0, int KB_per_second = 2500) +{ + return caches[CACHE_FRAG_TYPE_HTTP]->scan(cont, hostname, host_len, KB_per_second); +} + +#ifdef HTTP_CACHE +TS_INLINE Action * +CacheProcessor::lookup(Continuation *cont, URL *url, bool local_only, CacheFragType frag_type) +{ + (void) local_only; + INK_MD5 md5; + url->MD5_get(&md5); + int host_len = 0; + const char *hostname = url->host_get(&host_len); + + return lookup(cont, &md5, local_only, frag_type, (char *) hostname, host_len); +} + +TS_INLINE Action * +CacheProcessor::open_read_buffer(Continuation *cont, MIOBuffer *buf, + URL *url, CacheHTTPHdr *request, CacheLookupHttpConfig *params, CacheFragType type) +{ + (void) buf; +#ifdef CLUSTER_CACHE + if (cache_clustering_enabled > 0) { + return open_read_internal(CACHE_OPEN_READ_BUFFER_LONG, cont, buf, url, + request, params, (CacheKey *) 0, 0, type, (char *) 0, 0); + } +#endif + return caches[type]->open_read(cont, url, request, params, type); +} + +TS_INLINE Action * +CacheProcessor::open_write_buffer(Continuation * cont, MIOBuffer * buf, URL * url, + CacheHTTPHdr * request, CacheHTTPHdr * response, CacheFragType type) +{ + (void) cont; + (void) buf; + (void) url; + (void) request; + (void) response; + (void) type; + ink_assert(!"implemented"); + return NULL; +} + +#endif + + +#ifdef CLUSTER_CACHE +TS_INLINE Action * +CacheProcessor::open_read_internal(int opcode, + Continuation *cont, MIOBuffer *buf, + CacheURL *url, + CacheHTTPHdr *request, + CacheLookupHttpConfig *params, + CacheKey *key, + time_t pin_in_cache, CacheFragType frag_type, char *hostname, int host_len) +{ + INK_MD5 url_md5; + if ((opcode == CACHE_OPEN_READ_LONG) || (opcode == CACHE_OPEN_READ_BUFFER_LONG)) { + Cache::generate_key(&url_md5, url, request); + } else { + url_md5 = *key; + } + ClusterMachine *m = cluster_machine_at_depth(cache_hash(url_md5)); + ClusterMachine *owner_machine = m ? m : this_cluster_machine(); + + if (owner_machine != this_cluster_machine()) { + return Cluster_read(owner_machine, opcode, cont, buf, url, + request, params, key, pin_in_cache, frag_type, hostname, host_len); + } else { + if ((opcode == CACHE_OPEN_READ_LONG) + || (opcode == CACHE_OPEN_READ_BUFFER_LONG)) { + return caches[frag_type]->open_read(cont, &url_md5, request, params, frag_type, hostname, host_len); + } else { + return caches[frag_type]->open_read(cont, key, frag_type, hostname, host_len); + } + } +} +#endif + +#ifdef CLUSTER_CACHE +TS_INLINE Action * +CacheProcessor::link(Continuation *cont, CacheKey *from, CacheKey *to, + CacheFragType type, char *hostname, int host_len) +{ + if (cache_clustering_enabled > 0) { + // Use INK_MD5 in "from" to determine target machine + ClusterMachine *m = cluster_machine_at_depth(cache_hash(*from)); + if (m) { + return Cluster_link(m, cont, from, to, type, hostname, host_len); + } + } + return caches[type]->link(cont, from, to, type, hostname, host_len); +} + +TS_INLINE Action * +CacheProcessor::deref(Continuation *cont, CacheKey *key, CacheFragType type, char *hostname, int host_len) +{ + if (cache_clustering_enabled > 0) { + ClusterMachine *m = cluster_machine_at_depth(cache_hash(*key)); + if (m) { + return Cluster_deref(m, cont, key, type, hostname, host_len); + } + } + return caches[type]->deref(cont, key, type, hostname, host_len); +} +#endif + +TS_INLINE Action * +CacheProcessor::scan(Continuation *cont, char *hostname, int host_len, int KB_per_second) +{ + return caches[CACHE_FRAG_TYPE_HTTP]->scan(cont, hostname, host_len, KB_per_second); +} + +TS_INLINE int +CacheProcessor::IsCacheEnabled() +{ + return CacheProcessor::initialized; +} + +TS_INLINE unsigned int +CacheProcessor::IsCacheReady(CacheFragType type) +{ + if (IsCacheEnabled() != CACHE_INITIALIZED) + return 0; + return (cache_ready & (1 << type)); +} + +TS_INLINE Cache * +local_cache() +{ + return theCache; +} + +LINK_DEFINITION(CacheVC, opendir_link) + +#endif /* _P_CACHE_INTERNAL_H__ */ diff --git a/iocore/cache/P_CacheTest.h b/iocore/cache/P_CacheTest.h new file mode 100644 index 00000000..8ef83ca7 --- /dev/null +++ b/iocore/cache/P_CacheTest.h @@ -0,0 +1,132 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __P_CACHE_TEST_H__ +#define __P_CACHE_TEST_H__ + +#include "P_Cache.h" +#include "RegressionSM.h" + +#define MAX_HOSTS_POSSIBLE 256 +#define PINNED_DOC_TABLE_SIZE 16 +#define PINNED_DOC_TABLES 246 + +struct PinnedDocEntry +{ + CacheKey key; + ink_time_t time; + LINK(PinnedDocEntry, link); +}; + +struct PinnedDocTable: public Continuation +{ + Queue bucket[PINNED_DOC_TABLE_SIZE]; + + void insert(CacheKey * key, ink_time_t time, int update); + int probe(CacheKey * key); + int remove(CacheKey * key); + int cleanup(int event, Event * e); + + PinnedDocTable():Continuation(new_ProxyMutex()) { + memset(bucket, 0, sizeof(Queue) * PINNED_DOC_TABLE_SIZE); + } +}; + +struct CacheTestHost { + char *name; + volatile unsigned int xlast_cachable_id; + double xprev_host_prob; + double xnext_host_prob; + + CacheTestHost():name(NULL), xlast_cachable_id(0), + xprev_host_prob(0), xnext_host_prob(0) {} +}; + +struct CacheTestHeader { + uint64_t serial; +}; + +struct CacheTestSM : public RegressionSM { + int start_memcpy_on_clone; // place all variables to be copied between these markers + Action *timeout; + Action *cache_action; + ink_hrtime start_time; + CacheVConnection *cache_vc; + VIO *cvio; + MIOBuffer *buffer; + IOBufferReader *buffer_reader; +#ifdef HTTP_CACHE + CacheLookupHttpConfig params; + CacheHTTPInfo info; + char urlstr[1024]; +#endif + int64_t total_size; + int64_t nbytes; + CacheKey key; + int repeat_count; + int expect_event; + int expect_initial_event; + int initial_event; + uint64_t content_salt; + CacheTestHeader header; + int end_memcpy_on_clone; // place all variables to be copied between these markers + + void fill_buffer(); + int check_buffer(); + int check_result(int event); + int complete(int event); + int event_handler(int event, void *edata); + void make_request() { + start_time = ink_get_hrtime(); + make_request_internal(); + } + virtual void make_request_internal() = 0; + virtual int open_read_callout(); + virtual int open_write_callout(); + + void cancel_timeout() { + if (timeout) timeout->cancel(); + timeout = 0; + } + + // RegressionSM API + void run() { MUTEX_LOCK(lock, mutex, this_ethread()); timeout = eventProcessor.schedule_imm(this); } + virtual RegressionSM *clone() = 0; + + CacheTestSM(RegressionTest *t); + CacheTestSM(const CacheTestSM &ao); + ~CacheTestSM(); +}; + +// It is 2010 and C++ STILL doesn't have closures, a technology of the 1950s, unbelievable +#define CACHE_SM(_t, _sm, _f) \ + struct CacheTestSM__##_sm : public CacheTestSM { \ + void make_request_internal() _f \ + CacheTestSM__##_sm(RegressionTest *t) : CacheTestSM(t) {} \ + CacheTestSM__##_sm(const CacheTestSM__##_sm &xsm) : CacheTestSM(xsm) {} \ + RegressionSM *clone() { return new CacheTestSM__##_sm(*this); } \ +} _sm(_t); + +void force_link_CacheTest(); + +#endif /* __P_CACHE_TEST_H__ */ diff --git a/iocore/cache/P_CacheVol.h b/iocore/cache/P_CacheVol.h new file mode 100644 index 00000000..2e5b4dc4 --- /dev/null +++ b/iocore/cache/P_CacheVol.h @@ -0,0 +1,533 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef _P_CACHE_VOL_H__ +#define _P_CACHE_VOL_H__ + +#define CACHE_BLOCK_SHIFT 9 +#define CACHE_BLOCK_SIZE (1<sector_size) +#define ROUND_TO(_x, _y) INK_ALIGN((_x), (_y)) + +// Vol (volumes) +#define VOL_MAGIC 0xF1D0F00D +#define START_BLOCKS 16 // 8k, STORE_BLOCK_SIZE +#define START_POS ((off_t)START_BLOCKS * CACHE_BLOCK_SIZE) +#define AGG_SIZE (4 * 1024 * 1024) // 4MB +#define AGG_HIGH_WATER (AGG_SIZE / 2) // 2MB +#define EVACUATION_SIZE (2 * AGG_SIZE) // 8MB +#define MAX_VOL_SIZE ((off_t)512 * 1024 * 1024 * 1024 * 1024) +#define STORE_BLOCKS_PER_CACHE_BLOCK (STORE_BLOCK_SIZE / CACHE_BLOCK_SIZE) +#define MAX_VOL_BLOCKS (MAX_VOL_SIZE / CACHE_BLOCK_SIZE) +#define MAX_FRAG_SIZE (AGG_SIZE - sizeofDoc) // true max +#define LEAVE_FREE DEFAULT_MAX_BUFFER_SIZE +#define PIN_SCAN_EVERY 16 // scan every 1/16 of disk +#define VOL_HASH_TABLE_SIZE 32707 +#define VOL_HASH_EMPTY 0xFFFF +#define LOOKASIDE_SIZE 256 +#define EVACUATION_BUCKET_SIZE (2 * EVACUATION_SIZE) // 16MB +#define RECOVERY_SIZE EVACUATION_SIZE // 8MB +#define AIO_NOT_IN_PROGRESS 0 +#define AIO_AGG_WRITE_IN_PROGRESS -1 +#define AUTO_SIZE_RAM_CACHE -1 // 1-1 with directory size +#define DEFAULT_TARGET_FRAGMENT_SIZE (1048576 - sizeofDoc) // 1MB + + +#define dir_offset_evac_bucket(_o) \ + (_o / (EVACUATION_BUCKET_SIZE / CACHE_BLOCK_SIZE)) +#define dir_evac_bucket(_e) dir_offset_evac_bucket(dir_offset(_e)) +#define offset_evac_bucket(_d, _o) \ + dir_offset_evac_bucket((offset_to_vol_offset(_d, _o) + +// Documents + +#define DOC_MAGIC ((uint32_t)0x5F129B13) +#define DOC_CORRUPT ((uint32_t)0xDEADBABE) +#define DOC_NO_CHECKSUM ((uint32_t)0xA0B0C0D0) + +#define sizeofDoc (((uint32_t)(uintptr_t)&((Doc*)0)->checksum)+(uint32_t)sizeof(uint32_t)) + +struct Cache; +struct Vol; +struct CacheDisk; +struct VolInitInfo; +struct DiskVol; +struct CacheVol; + +struct VolHeaderFooter +{ + unsigned int magic; + VersionNumber version; + time_t create_time; + off_t write_pos; + off_t last_write_pos; + off_t agg_pos; + uint32_t generation; // token generation (vary), this cannot be 0 + uint32_t phase; + uint32_t cycle; + uint32_t sync_serial; + uint32_t write_serial; + uint32_t dirty; + uint32_t sector_size; + uint32_t unused; // pad out to 8 byte boundary + uint16_t freelist[1]; +}; + +// Key and Earliest key for each fragment that needs to be evacuated +struct EvacuationKey +{ + SLink link; + INK_MD5 key; + INK_MD5 earliest_key; +}; + +struct EvacuationBlock +{ + union + { + unsigned int init; + struct + { + unsigned int done:1; // has been evacuated + unsigned int pinned:1; // check pinning timeout + unsigned int evacuate_head:1; // check pinning timeout + unsigned int unused:29; + } f; + }; + + int readers; + Dir dir; + Dir new_dir; + // we need to have a list of evacuationkeys because of collision. + EvacuationKey evac_frags; + CacheVC *earliest_evacuator; + LINK(EvacuationBlock, link); +}; + +struct Vol: public Continuation +{ + char *path; + char *hash_id; + INK_MD5 hash_id_md5; + int fd; + + char *raw_dir; + Dir *dir; + VolHeaderFooter *header; + VolHeaderFooter *footer; + int segments; + off_t buckets; + off_t recover_pos; + off_t prev_recover_pos; + off_t scan_pos; + off_t skip; // start of headers + off_t start; // start of data + off_t len; + off_t data_blocks; + int hit_evacuate_window; + AIOCallbackInternal io; + + Queue agg; + Queue stat_cache_vcs; + Queue sync; + char *agg_buffer; + int agg_todo_size; + int agg_buf_pos; + + Event *trigger; + + OpenDir open_dir; + RamCache *ram_cache; + int evacuate_size; + DLL *evacuate; + DLL lookaside[LOOKASIDE_SIZE]; + CacheVC *doc_evacuator; + + VolInitInfo *init_info; + + CacheDisk *disk; + Cache *cache; + CacheVol *cache_vol; + uint32_t last_sync_serial; + uint32_t last_write_serial; + uint32_t sector_size; + bool recover_wrapped; + bool dir_sync_waiting; + bool dir_sync_in_progress; + bool writing_end_marker; + + CacheKey first_fragment_key; + int64_t first_fragment_offset; + Ptr first_fragment_data; + + void cancel_trigger(); + + int open_write(CacheVC *cont, int allow_if_writers, int max_writers); + int open_write_lock(CacheVC *cont, int allow_if_writers, int max_writers); + int close_write(CacheVC *cont); + int close_write_lock(CacheVC *cont); + int begin_read(CacheVC *cont); + int begin_read_lock(CacheVC *cont); + // unused read-write interlock code + // currently http handles a write-lock failure by retrying the read + OpenDirEntry *open_read(INK_MD5 *key); + OpenDirEntry *open_read_lock(INK_MD5 *key, EThread *t); + int close_read(CacheVC *cont); + int close_read_lock(CacheVC *cont); + + int clear_dir(); + + int init(char *s, off_t blocks, off_t dir_skip, bool clear); + + int handle_dir_clear(int event, void *data); + int handle_dir_read(int event, void *data); + int handle_recover_from_data(int event, void *data); + int handle_recover_write_dir(int event, void *data); + int handle_header_read(int event, void *data); + + int dir_init_done(int event, void *data); + + int dir_check(bool fix); + int db_check(bool fix); + + int is_io_in_progress() + { + return io.aiocb.aio_fildes != AIO_NOT_IN_PROGRESS; + } + int increment_generation() + { + // this is stored in the offset field of the directory (!=0) + ink_debug_assert(mutex->thread_holding == this_ethread()); + header->generation++; + if (!header->generation) + header->generation++; + return header->generation; + } + void set_io_not_in_progress() + { + io.aiocb.aio_fildes = AIO_NOT_IN_PROGRESS; + } + + int aggWriteDone(int event, Event *e); + int aggWrite(int event, void *e); + void agg_wrap(); + + int evacuateWrite(CacheVC *evacuator, int event, Event *e); + int evacuateDocReadDone(int event, Event *e); + int evacuateDoc(int event, Event *e); + + int evac_range(off_t start, off_t end, int evac_phase); + void periodic_scan(); + void scan_for_pinned_documents(); + void evacuate_cleanup_blocks(int i); + void evacuate_cleanup(); + EvacuationBlock *force_evacuate_head(Dir *dir, int pinned); + int within_hit_evacuate_window(Dir *dir); + uint32_t round_to_approx_size(uint32_t l); + + Vol() + : Continuation(new_ProxyMutex()), path(NULL), fd(-1), + dir(0), buckets(0), recover_pos(0), prev_recover_pos(0), scan_pos(0), skip(0), start(0), + len(0), data_blocks(0), hit_evacuate_window(0), agg_todo_size(0), agg_buf_pos(0), trigger(0), + evacuate_size(0), disk(NULL), last_sync_serial(0), last_write_serial(0), recover_wrapped(false), + dir_sync_waiting(0), dir_sync_in_progress(0), writing_end_marker(0) { + open_dir.mutex = mutex; +#if defined(_WIN32) + agg_buffer = (char *) malloc(AGG_SIZE); +#else + agg_buffer = (char *) ink_memalign(sysconf(_SC_PAGESIZE), AGG_SIZE); +#endif + memset(agg_buffer, 0, AGG_SIZE); + SET_HANDLER(&Vol::aggWrite); + } + + ~Vol() { + ink_memalign_free(agg_buffer); + } +}; + +struct AIO_Callback_handler: public Continuation +{ + int handle_disk_failure(int event, void *data); + + AIO_Callback_handler():Continuation(new_ProxyMutex()) { + SET_HANDLER(&AIO_Callback_handler::handle_disk_failure); + } +}; + +struct CacheVol +{ + int vol_number; + int scheme; + int size; + int num_vols; + Vol **vols; + DiskVol **disk_vols; + LINK(CacheVol, link); + // per volume stats + RecRawStatBlock *vol_rsb; + + CacheVol() + : vol_number(-1), scheme(0), size(0), num_vols(0), vols(NULL), disk_vols(0), vol_rsb(0) + { } +}; + +// element of the fragment table in the head of a multi-fragment document +struct Frag { + uint64_t offset; // start offset of data stored in this fragment +}; + +// Note : hdr() needs to be 8 byte aligned. +// If you change this, change sizeofDoc above +struct Doc +{ + uint32_t magic; // DOC_MAGIC + uint32_t len; // length of this segment (including hlen, flen & sizeof(Doc), unrounded) + uint64_t total_len; // total length of document + INK_MD5 first_key; // first key in document (http: vector) + INK_MD5 key; + uint32_t hlen; // header length + uint32_t ftype:8; // fragment type CACHE_FRAG_TYPE_XX + uint32_t flen:24; // fragment table length + uint32_t sync_serial; + uint32_t write_serial; + uint32_t pinned; // pinned until + uint32_t checksum; + + uint32_t data_len(); + uint32_t prefix_len(); + int single_fragment(); + int no_data_in_fragment(); + uint32_t nfrags(); + char *hdr(); + Frag *frags(); + char *data(); +}; + +// Global Data + +extern Vol **gvol; +extern volatile int gnvol; +extern ClassAllocator openDirEntryAllocator; +extern ClassAllocator evacuationBlockAllocator; +extern ClassAllocator evacuationKeyAllocator; +extern unsigned short *vol_hash_table; + +// inline Functions + +TS_INLINE int +vol_headerlen(Vol *d) { + return ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter) + sizeof(uint16_t) * (d->segments-1)); +} + +TS_INLINE size_t +vol_dirlen(Vol *d) +{ + return vol_headerlen(d) + + ROUND_TO_STORE_BLOCK(((size_t)d->buckets) * DIR_DEPTH * d->segments * SIZEOF_DIR) + + ROUND_TO_STORE_BLOCK(sizeof(VolHeaderFooter)); +} + +TS_INLINE int +vol_direntries(Vol *d) +{ + return d->buckets * DIR_DEPTH * d->segments; +} + +TS_INLINE int +vol_out_of_phase_valid(Vol *d, Dir *e) +{ + return (dir_offset(e) - 1 >= ((d->header->agg_pos - d->start) / CACHE_BLOCK_SIZE)); +} + +TS_INLINE int +vol_out_of_phase_agg_valid(Vol *d, Dir *e) +{ + return (dir_offset(e) - 1 >= ((d->header->agg_pos - d->start + AGG_SIZE) / CACHE_BLOCK_SIZE)); +} + +TS_INLINE int +vol_out_of_phase_write_valid(Vol *d, Dir *e) +{ + return (dir_offset(e) - 1 >= ((d->header->write_pos - d->start) / CACHE_BLOCK_SIZE)); +} + +TS_INLINE int +vol_in_phase_valid(Vol *d, Dir *e) +{ + return (dir_offset(e) - 1 < ((d->header->write_pos + d->agg_buf_pos - d->start) / CACHE_BLOCK_SIZE)); +} + +TS_INLINE off_t +vol_offset(Vol *d, Dir *e) +{ + return d->start + (off_t) dir_offset(e) * CACHE_BLOCK_SIZE - CACHE_BLOCK_SIZE; +} + +TS_INLINE off_t +offset_to_vol_offset(Vol *d, off_t pos) +{ + return ((pos - d->start + CACHE_BLOCK_SIZE) / CACHE_BLOCK_SIZE); +} + +TS_INLINE off_t +vol_offset_to_offset(Vol *d, off_t pos) +{ + return d->start + pos * CACHE_BLOCK_SIZE - CACHE_BLOCK_SIZE; +} + +TS_INLINE Dir * +vol_dir_segment(Vol *d, int s) +{ + return (Dir *) (((char *) d->dir) + (s * d->buckets) * DIR_DEPTH * SIZEOF_DIR); +} + +TS_INLINE int +vol_in_phase_agg_buf_valid(Vol *d, Dir *e) +{ + return (vol_offset(d, e) >= d->header->write_pos && vol_offset(d, e) < (d->header->write_pos + d->agg_buf_pos)); +} + +// length of the partition not including the offset of location 0. +TS_INLINE off_t +vol_relative_length(Vol *v, off_t start_offset) +{ + return (v->len + v->skip) - start_offset; +} + +TS_INLINE uint32_t +Doc::prefix_len() +{ + return sizeofDoc + hlen + flen; +} + +TS_INLINE uint32_t +Doc::data_len() +{ + return len - sizeofDoc - hlen - flen; +} + +TS_INLINE int +Doc::single_fragment() +{ + return (total_len && (data_len() == total_len)); +} + +TS_INLINE uint32_t +Doc::nfrags() { + return flen / sizeof(Frag); +} + +TS_INLINE Frag * +Doc::frags() +{ + return (Frag*)(((char *) this) + sizeofDoc); +} + +TS_INLINE char * +Doc::hdr() +{ + return ((char *) this) + sizeofDoc + flen; +} + +TS_INLINE char * +Doc::data() +{ + return ((char *) this) + sizeofDoc + flen + hlen; +} + +int vol_dir_clear(Vol *d); +int vol_init(Vol *d, char *s, off_t blocks, off_t skip, bool clear); + +// inline Functions + +TS_INLINE EvacuationBlock * +evacuation_block_exists(Dir *dir, Vol *p) +{ + EvacuationBlock *b = p->evacuate[dir_evac_bucket(dir)].head; + for (; b; b = b->link.next) + if (dir_offset(&b->dir) == dir_offset(dir)) + return b; + return 0; +} + +TS_INLINE void +Vol::cancel_trigger() +{ + if (trigger) { + trigger->cancel_action(); + trigger = NULL; + } +} + +TS_INLINE EvacuationBlock * +new_EvacuationBlock(EThread *t) +{ + EvacuationBlock *b = THREAD_ALLOC(evacuationBlockAllocator, t); + b->init = 0; + b->readers = 0; + b->earliest_evacuator = 0; + b->evac_frags.link.next = 0; + return b; +} + +TS_INLINE void +free_EvacuationBlock(EvacuationBlock *b, EThread *t) +{ + EvacuationKey *e = b->evac_frags.link.next; + while (e) { + EvacuationKey *n = e->link.next; + evacuationKeyAllocator.free(e); + e = n; + } + THREAD_FREE(b, evacuationBlockAllocator, t); +} + +TS_INLINE OpenDirEntry * +Vol::open_read(INK_MD5 *key) +{ + return open_dir.open_read(key); +} + +TS_INLINE int +Vol::within_hit_evacuate_window(Dir *xdir) +{ + off_t oft = dir_offset(xdir) - 1; + off_t write_off = (header->write_pos + AGG_SIZE - start) / CACHE_BLOCK_SIZE; + off_t delta = oft - write_off; + if (delta >= 0) + return delta < hit_evacuate_window; + else + return -delta > (data_blocks - hit_evacuate_window) && -delta < data_blocks; +} + +TS_INLINE uint32_t +Vol::round_to_approx_size(uint32_t l) { + uint32_t ll = round_to_approx_dir_size(l); + return ROUND_TO_SECTOR(this, ll); +} + +#endif /* _P_CACHE_VOL_H__ */ diff --git a/iocore/cache/P_RamCache.h b/iocore/cache/P_RamCache.h new file mode 100644 index 00000000..9a0ae682 --- /dev/null +++ b/iocore/cache/P_RamCache.h @@ -0,0 +1,44 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_RAM_CACHE_H__ +#define _P_RAM_CACHE_H__ + +#include "I_Cache.h" + +// Generic Ram Cache interface + +struct RamCache { + // returns 1 on found/stored, 0 on not found/stored, if provided auxkey1 and auxkey2 must match + virtual int get(INK_MD5 *key, Ptr *ret_data, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0) = 0; + virtual int put(INK_MD5 *key, IOBufferData *data, uint32_t len, bool copy = false, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0) = 0; + virtual int fixup(INK_MD5 *key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2) = 0; + + virtual void init(int64_t max_bytes, Vol *vol) = 0; + virtual ~RamCache() {}; +}; + +RamCache *new_RamCacheLRU(); +RamCache *new_RamCacheCLFUS(); + +#endif /* _P_RAM_CACHE_H__ */ diff --git a/iocore/cache/RamCacheCLFUS.cc b/iocore/cache/RamCacheCLFUS.cc new file mode 100644 index 00000000..e55c88b3 --- /dev/null +++ b/iocore/cache/RamCacheCLFUS.cc @@ -0,0 +1,649 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +// Clocked Least Frequently Used by Size (CLFUS) replacement policy +// See https://cwiki.apache.org/confluence/display/TS/RamCache + +#include "P_Cache.h" +#include "I_Tasks.h" +#if TS_HAS_LIBZ +#include +#endif +#if TS_HAS_LZMA +#include +#endif + +#define REQUIRED_COMPRESSION 0.9 // must get to this size or declared incompressible +#define REQUIRED_SHRINK 0.8 // must get to this size or keep orignal buffer (with padding) +#define HISTORY_HYSTERIA 10 // extra temporary history +#define ENTRY_OVERHEAD 256 // per-entry overhead to consider when computing cache value/size +#define LZMA_BASE_MEMLIMIT (64 * 1024 * 1024) +//#define CHECK_ACOUNTING 1 // very expensive double checking of all sizes + +#define REQUEUE_HITS(_h) ((_h) ? 1 : 0) +#define CACHE_VALUE_HITS_SIZE(_h, _s) ((float)((_h)+1) / ((_s) + ENTRY_OVERHEAD)) +#define CACHE_VALUE(_x) CACHE_VALUE_HITS_SIZE((_x)->hits, (_x)->size) + +struct RamCacheCLFUSEntry { + INK_MD5 key; + uint32_t auxkey1; + uint32_t auxkey2; + uint64_t hits; + uint32_t size; // memory used including paddding in buffer + uint32_t len; // actual data length + uint32_t compressed_len; + union { + struct { + uint32_t compressed:3; // compression type + uint32_t incompressible:1; + uint32_t lru:1; + uint32_t copy:1; // copy-in-copy-out + } flag_bits; + uint32_t flags; + }; + LINK(RamCacheCLFUSEntry, lru_link); + LINK(RamCacheCLFUSEntry, hash_link); + Ptr data; +}; + +struct RamCacheCLFUS : public RamCache { + int64_t max_bytes; + int64_t bytes; + int64_t objects; + + // returns 1 on found/stored, 0 on not found/stored, if provided auxkey1 and auxkey2 must match + int get(INK_MD5 *key, Ptr *ret_data, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0); + int put(INK_MD5 *key, IOBufferData *data, uint32_t len, bool copy = false, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0); + int fixup(INK_MD5 *key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2); + + void init(int64_t max_bytes, Vol *vol); + + // private + Vol *vol; // for stats + int64_t history; + int ibuckets; + int nbuckets; + DList(RamCacheCLFUSEntry, hash_link) *bucket; + Que(RamCacheCLFUSEntry, lru_link) lru[2]; + uint16_t *seen; + int ncompressed; + RamCacheCLFUSEntry *compressed; // first uncompressed lru[0] entry + void compress_entries(EThread *thread, int do_at_most = INT_MAX); + void resize_hashtable(); + void victimize(RamCacheCLFUSEntry *e); + void move_compressed(RamCacheCLFUSEntry *e); + RamCacheCLFUSEntry *destroy(RamCacheCLFUSEntry *e); + void requeue_victims(RamCacheCLFUS *c, Que(RamCacheCLFUSEntry, lru_link) &victims); + void tick(); // move CLOCK on history + RamCacheCLFUS(): max_bytes(0), bytes(0), objects(0), vol(0), history(0), ibuckets(0), nbuckets(0), bucket(0), + seen(0), ncompressed(0), compressed(0) { } +}; + +ClassAllocator ramCacheCLFUSEntryAllocator("RamCacheCLFUSEntry"); + +static const int bucket_sizes[] = { + 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, + 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, + 134217689, 268435399, 536870909, 1073741789, 2147483647 +}; + +void RamCacheCLFUS::resize_hashtable() { + int anbuckets = bucket_sizes[ibuckets]; + DDebug("ram_cache", "resize hashtable %d", anbuckets); + int64_t s = anbuckets * sizeof(DList(RamCacheCLFUSEntry, hash_link)); + DList(RamCacheCLFUSEntry, hash_link) *new_bucket = (DList(RamCacheCLFUSEntry, hash_link) *)xmalloc(s); + memset(new_bucket, 0, s); + if (bucket) { + for (int64_t i = 0; i < nbuckets; i++) { + RamCacheCLFUSEntry *e = 0; + while ((e = bucket[i].pop())) + new_bucket[e->key.word(3) % anbuckets].push(e); + } + xfree(bucket); + } + bucket = new_bucket; + nbuckets = anbuckets; + if (seen) xfree(seen); + int size = bucket_sizes[ibuckets] * sizeof(uint16_t); + seen = (uint16_t*)xmalloc(size); + memset(seen, 0, size); +} + +void RamCacheCLFUS::init(int64_t abytes, Vol *avol) { + vol = avol; + max_bytes = abytes; + DDebug("ram_cache", "initializing ram_cache %" PRId64 " bytes", abytes); + if (!max_bytes) + return; + resize_hashtable(); +} + +#ifdef CHECK_ACOUNTING +static void check_accounting(RamCacheCLFUS *c) { + int64_t x = 0, xsize = 0, h = 0; + RamCacheCLFUSEntry *y = c->lru[0].head; + while (y) { x++; xsize += y->size + ENTRY_OVERHEAD; y = y->lru_link.next; } + y = c->lru[1].head; + while (y) { h++; y = y->lru_link.next; } + ink_assert(x == c->objects); + ink_assert(xsize == c->bytes); + ink_assert(h == c->history); +} +#else +#define check_accounting(_c) +#endif + +int RamCacheCLFUS::get(INK_MD5 *key, Ptr *ret_data, uint32_t auxkey1, uint32_t auxkey2) { + if (!max_bytes) + return 0; + int64_t i = key->word(3) % nbuckets; + RamCacheCLFUSEntry *e = bucket[i].head; + char *b = 0; + while (e) { + if (e->key == *key && e->auxkey1 == auxkey1 && e->auxkey2 == auxkey2) { + move_compressed(e); + lru[e->flag_bits.lru].remove(e); + lru[e->flag_bits.lru].enqueue(e); + if (!e->flag_bits.lru) { // in memory + e->hits++; + if (e->flag_bits.compressed) { + b = (char*)xmalloc(e->len); + switch (e->flag_bits.compressed) { + default: goto Lfailed; + case CACHE_COMPRESSION_FASTLZ: { + int l = (int)e->len; + if ((l != (int)fastlz_decompress(e->data->data(), e->compressed_len, b, l))) + goto Lfailed; + break; + } +#if TS_HAS_LIBZ + case CACHE_COMPRESSION_LIBZ: { + uLongf l = e->len; + if (Z_OK != uncompress((Bytef*)b, &l, (Bytef*)e->data->data(), e->compressed_len)) + goto Lfailed; + break; + } +#endif +#if TS_HAS_LZMA + case CACHE_COMPRESSION_LIBLZMA: { + size_t l = (size_t)e->len, ipos = 0, opos = 0; + uint64_t memlimit = e->len * 2 + LZMA_BASE_MEMLIMIT; + if (LZMA_OK != lzma_stream_buffer_decode( + &memlimit, 0, NULL, (uint8_t*)e->data->data(), &ipos, e->compressed_len, (uint8_t*)b, &opos, l)) + goto Lfailed; + break; + } +#endif + } + IOBufferData *data = new_xmalloc_IOBufferData(b, e->len); + data->_mem_type = DEFAULT_ALLOC; + if (!e->flag_bits.copy) { // don't bother if we have to copy anyway + int64_t delta = ((int64_t)e->compressed_len) - (int64_t)e->size; + bytes += delta; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, delta); + e->size = e->compressed_len; + check_accounting(this); + e->flag_bits.compressed = 0; + e->data = data; + } + (*ret_data) = data; + } else { + IOBufferData *data = e->data; + if (e->flag_bits.copy) { + data = new_IOBufferData(iobuffer_size_to_index(e->len, MAX_BUFFER_SIZE_INDEX), MEMALIGNED); + memcpy(data->data(), e->data->data(), e->len); + } + (*ret_data) = data; + } + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_hits_stat, 1); + DDebug("ram_cache", "get %X %d %d size %d HIT", key->word(3), auxkey1, auxkey2, e->size); + return 1; + } else { + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_misses_stat, 1); + DDebug("ram_cache", "get %X %d %d HISTORY", key->word(3), auxkey1, auxkey2); + return 0; + } + } + assert(e != e->hash_link.next); + e = e->hash_link.next; + } + DDebug("ram_cache", "get %X %d %d MISS", key->word(3), auxkey1, auxkey2); +Lerror: + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_misses_stat, 1); + return 0; +Lfailed: + xfree(b); + e = destroy(e); + DDebug("ram_cache", "get %X %d %d Z_ERR", key->word(3), auxkey1, auxkey2); + goto Lerror; +} + +void RamCacheCLFUS::tick() { + RamCacheCLFUSEntry *e = lru[1].dequeue(); + if (!e) + return; + e->hits <<= 1; + if (e->hits) { + e->hits = REQUEUE_HITS(e->hits); + lru[1].enqueue(e); + } else + goto Lfree; + if (history <= objects + HISTORY_HYSTERIA) + return; + e = lru[1].dequeue(); +Lfree: + e->flag_bits.lru = 0; + history--; + uint32_t b = e->key.word(3) % nbuckets; + bucket[b].remove(e); + DDebug("ram_cache", "put %X %d %d size %d FREED", e->key.word(3), e->auxkey1, e->auxkey2, e->size); + THREAD_FREE(e, ramCacheCLFUSEntryAllocator, this_ethread()); +} + +void RamCacheCLFUS::victimize(RamCacheCLFUSEntry *e) { + objects--; + DDebug("ram_cache", "put %X %d %d size %d VICTIMIZED", e->key.word(3), e->auxkey1, e->auxkey2, e->size); + e->data = NULL; + e->flag_bits.lru = 1; + lru[1].enqueue(e); + history++; +} + +void RamCacheCLFUS::move_compressed(RamCacheCLFUSEntry *e) { + if (e == compressed) { + if (compressed->lru_link.next) + compressed = compressed->lru_link.next; + else { + ncompressed--; + compressed = compressed->lru_link.prev; + } + } +} + +RamCacheCLFUSEntry *RamCacheCLFUS::destroy(RamCacheCLFUSEntry *e) { + RamCacheCLFUSEntry *ret = e->hash_link.next; + move_compressed(e); + lru[e->flag_bits.lru].remove(e); + if (!e->flag_bits.lru) { + objects--; + bytes -= e->size + ENTRY_OVERHEAD; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, -e->size); + e->data = NULL; + } else + history--; + uint32_t b = e->key.word(3) % nbuckets; + bucket[b].remove(e); + DDebug("ram_cache", "put %X %d %d DESTROYED", e->key.word(3), e->auxkey1, e->auxkey2); + THREAD_FREE(e, ramCacheCLFUSEntryAllocator, this_ethread()); + return ret; +} + +void RamCacheCLFUS::compress_entries(EThread *thread, int do_at_most) { + if (!cache_config_ram_cache_compress) + return; + MUTEX_TAKE_LOCK(vol->mutex, thread); + if (!compressed) { + compressed = lru[0].head; + ncompressed = 0; + } + float target = (cache_config_ram_cache_compress_percent / 100.0) * objects; + int n = 0; + char *b = 0, *bb = 0; + while (compressed && target > ncompressed) { + RamCacheCLFUSEntry *e = compressed; + if (e->flag_bits.incompressible || e->flag_bits.compressed) + goto Lcontinue; + n++; + if (do_at_most < n) + break; + { + e->compressed_len = e->size; + uint32_t l = 0; + int ctype = cache_config_ram_cache_compress; + switch (ctype) { + default: goto Lcontinue; + case CACHE_COMPRESSION_FASTLZ: l = (uint32_t)((double)e->len * 1.05 + 66); break; +#if TS_HAS_LIBZ + case CACHE_COMPRESSION_LIBZ: l = (uint32_t)compressBound(e->len); break; +#endif +#if TS_HAS_LZMA + case CACHE_COMPRESSION_LIBLZMA: l = e->len; break; +#endif + } + // store transient data for lock release + Ptr edata = e->data; + uint32_t elen = e->len; + INK_MD5 key = e->key; + MUTEX_UNTAKE_LOCK(vol->mutex, thread); + b = (char*)xmalloc(l); + bool failed = false; + switch (ctype) { + default: goto Lfailed; + case CACHE_COMPRESSION_FASTLZ: + if (e->len < 16) goto Lfailed; + if ((l = fastlz_compress(edata->data(), elen, b)) <= 0) + failed = true; + break; +#if TS_HAS_LIBZ + case CACHE_COMPRESSION_LIBZ: { + uLongf ll = l; + if ((Z_OK != compress((Bytef*)b, &ll, (Bytef*)edata->data(), elen))) + failed = true; + l = (int)ll; + break; + } +#endif +#if TS_HAS_LZMA + case CACHE_COMPRESSION_LIBLZMA: { + size_t pos = 0, ll = l; + if (LZMA_OK != lzma_easy_buffer_encode(LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE, NULL, + (uint8_t*)edata->data(), elen, (uint8_t*)b, &pos, ll)) + failed = true; + l = (int)pos; + break; + } +#endif + } + MUTEX_TAKE_LOCK(vol->mutex, thread); + // see if the entry is till around + { + uint32_t i = key.word(3) % nbuckets; + RamCacheCLFUSEntry *ee = bucket[i].head; + while (ee) { + if (ee->key == key && ee->data == edata) break; + ee = ee->hash_link.next; + } + if (!ee || ee != e) { + e = compressed; + goto Lcontinue; + } + if (failed) + goto Lfailed; + } + if (l > REQUIRED_COMPRESSION * e->len) + e->flag_bits.incompressible = true; + if (l > REQUIRED_SHRINK * e->size) + goto Lfailed; + if (l < e->len) { + e->flag_bits.compressed = cache_config_ram_cache_compress; + bb = (char*)xmalloc(l); + memcpy(bb, b, l); + xfree(b); + e->compressed_len = l; + int64_t delta = ((int64_t)l) - (int64_t)e->size; + bytes += delta; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, delta); + e->size = l; + } else { + xfree(b); + e->flag_bits.compressed = 0; + bb = (char*)xmalloc(e->len); + memcpy(bb, e->data->data(), e->len); + int64_t delta = ((int64_t)e->len) - (int64_t)e->size; + bytes += delta; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, delta); + e->size = e->len; + l = e->len; + } + e->data = new_xmalloc_IOBufferData(bb, l); + e->data->_mem_type = DEFAULT_ALLOC; + check_accounting(this); + } + goto Lcontinue; + Lfailed: + xfree(b); + e->flag_bits.incompressible = 1; + Lcontinue:; + DDebug("ram_cache", "compress %X %d %d %d %d %d %d %d", + e->key.word(3), e->auxkey1, e->auxkey2, + e->flag_bits.incompressible, e->flag_bits.compressed, + e->len, e->compressed_len, ncompressed); + if (!e->lru_link.next) + break; + compressed = e->lru_link.next; + ncompressed++; + } + MUTEX_UNTAKE_LOCK(vol->mutex, thread); + return; +} + +void RamCacheCLFUS::requeue_victims(RamCacheCLFUS *c, Que(RamCacheCLFUSEntry, lru_link) &victims) { + RamCacheCLFUSEntry *victim = 0; + while ((victim = victims.dequeue())) { + c->bytes += victim->size + ENTRY_OVERHEAD; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, victim->size); + victim->hits = REQUEUE_HITS(victim->hits); + c->lru[0].enqueue(victim); + } +} + +int RamCacheCLFUS::put(INK_MD5 *key, IOBufferData *data, uint32_t len, bool copy, uint32_t auxkey1, uint32_t auxkey2) { + if (!max_bytes) + return 0; + uint32_t i = key->word(3) % nbuckets; + RamCacheCLFUSEntry *e = bucket[i].head; + uint32_t size = copy ? len : data->block_size(); + while (e) { + if (e->key == *key) { + if (e->auxkey1 == auxkey1 && e->auxkey2 == auxkey2) + break; + else { + e = destroy(e); // discard when aux keys conflict + continue; + } + } + e = e->hash_link.next; + } + if (e) { + e->hits++; + if (!e->flag_bits.lru) { // already in cache + move_compressed(e); + lru[e->flag_bits.lru].remove(e); + lru[e->flag_bits.lru].enqueue(e); + int64_t delta = ((int64_t)size) - (int64_t)e->size; + bytes += delta; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, delta); + if (!copy) { + e->size = size; + e->data = data; + } else { + char *b = (char*)xmalloc(len); + memcpy(b, data->data(), len); + e->data = new_xmalloc_IOBufferData(b, len); + e->data->_mem_type = DEFAULT_ALLOC; + e->size = size; + } + check_accounting(this); + e->flag_bits.copy = copy; + e->flag_bits.compressed = 0; + DDebug("ram_cache", "put %X %d %d size %d HIT", key->word(3), auxkey1, auxkey2, e->size); + return 1; + } else + lru[1].remove(e); + } + Que(RamCacheCLFUSEntry, lru_link) victims; + RamCacheCLFUSEntry *victim = 0; + if (!lru[1].head) // initial fill + if (bytes + size <= max_bytes) + goto Linsert; + if (!e) { + uint32_t s = key->word(3) % bucket_sizes[ibuckets]; + uint16_t k = key->word(3) >> 16; + uint16_t kk = seen[s]; + seen[s] = k; + if (history >= objects && kk != k) { + DDebug("ram_cache", "put %X %d %d size %d UNSEEN", key->word(3), auxkey1, auxkey2, size); + return 0; + } + } + while (1) { + victim = lru[0].dequeue(); + if (!victim) { + if (bytes + size <= max_bytes) + goto Linsert; + if (e) + lru[1].enqueue(e); + requeue_victims(this, victims); + DDebug("ram_cache", "put %X %d %d NO VICTIM", key->word(3), auxkey1, auxkey2); + return 0; + } + bytes -= victim->size + ENTRY_OVERHEAD; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, -victim->size); + victims.enqueue(victim); + if (victim == compressed) + compressed = 0; + else + ncompressed--; + victim->hits <<= 1; + tick(); + if (!e) + goto Lhistory; + else { // e from history + DDebug("ram_cache_compare", "put %f %f", CACHE_VALUE(victim), CACHE_VALUE(e)); + if (bytes + victim->size + size > max_bytes && CACHE_VALUE(victim) > CACHE_VALUE(e)) { + requeue_victims(this, victims); + lru[1].enqueue(e); + DDebug("ram_cache", "put %X %d %d size %d INC %d HISTORY", + key->word(3), auxkey1, auxkey2, e->size, e->hits); + return 0; + } + } + if (bytes + size <= max_bytes) + goto Linsert; + } +Linsert: + while ((victim = victims.dequeue())) { + if (bytes + size + victim->size <= max_bytes) { + bytes += victim->size + ENTRY_OVERHEAD; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, victim->size); + victim->hits = REQUEUE_HITS(victim->hits); + lru[0].enqueue(victim); + } else + victimize(victim); + } + if (e) { + history--; // move from history + } else { + e = THREAD_ALLOC(ramCacheCLFUSEntryAllocator, this_ethread()); + e->key = *key; + e->auxkey1 = auxkey1; + e->auxkey2 = auxkey2; + e->hits = 1; + bucket[i].push(e); + if (objects > nbuckets) { + ++ibuckets; + resize_hashtable(); + } + } + check_accounting(this); + e->flags = 0; + if (!copy) + e->data = data; + else { + char *b = (char*)xmalloc(len); + memcpy(b, data->data(), len); + e->data = new_xmalloc_IOBufferData(b, len); + e->data->_mem_type = DEFAULT_ALLOC; + } + e->flag_bits.copy = copy; + bytes += size + ENTRY_OVERHEAD; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, size); + e->size = size; + objects++; + lru[0].enqueue(e); + e->len = len; + check_accounting(this); + DDebug("ram_cache", "put %X %d %d size %d INSERTED", key->word(3), auxkey1, auxkey2, e->size); + return 1; +Lhistory: + requeue_victims(this, victims); + check_accounting(this); + e = THREAD_ALLOC(ramCacheCLFUSEntryAllocator, this_ethread()); + e->key = *key; + e->auxkey1 = auxkey1; + e->auxkey2 = auxkey2; + e->hits = 1; + e->size = data->block_size(); + e->flags = 0; + bucket[i].push(e); + e->flag_bits.lru = 1; + lru[1].enqueue(e); + history++; + DDebug("ram_cache", "put %X %d %d HISTORY", key->word(3), auxkey1, auxkey2); + return 0; +} + +int RamCacheCLFUS::fixup(INK_MD5 * key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2) { + if (!max_bytes) + return 0; + uint32_t i = key->word(3) % nbuckets; + RamCacheCLFUSEntry *e = bucket[i].head; + while (e) { + if (e->key == *key && e->auxkey1 == old_auxkey1 && e->auxkey2 == old_auxkey2) { + e->auxkey1 = new_auxkey1; + e->auxkey2 = new_auxkey2; + return 1; + } + e = e->hash_link.next; + } + return 0; +} + +class RamCacheCLFUSCompressor : public Continuation { public: + RamCacheCLFUS *rc; + int mainEvent(int event, Event *e); + RamCacheCLFUSCompressor(RamCacheCLFUS *arc): rc(arc) { + SET_HANDLER(&RamCacheCLFUSCompressor::mainEvent); + } +}; + +int RamCacheCLFUSCompressor::mainEvent(int event, Event *e) { + NOWARN_UNUSED(event); + switch (cache_config_ram_cache_compress) { + default: + Warning("unknown RAM cache compression type: %d", cache_config_ram_cache_compress); + case CACHE_COMPRESSION_NONE: + case CACHE_COMPRESSION_FASTLZ: + break; + case CACHE_COMPRESSION_LIBZ: +#if ! TS_HAS_LIBZ + Warning("libz not available for RAM cache compression"); +#endif + break; + case CACHE_COMPRESSION_LIBLZMA: +#if ! TS_HAS_LZMA + Warning("lzma not available for RAM cache compression"); +#endif + break; + } + if (cache_config_ram_cache_compress_percent) + rc->compress_entries(e->ethread); + return EVENT_CONT; +} + +RamCache *new_RamCacheCLFUS() { + RamCacheCLFUS *r = new RamCacheCLFUS; + eventProcessor.schedule_every(new RamCacheCLFUSCompressor(r), HRTIME_SECOND, + ET_TASK); + return r; +} diff --git a/iocore/cache/RamCacheLRU.cc b/iocore/cache/RamCacheLRU.cc new file mode 100644 index 00000000..2c64bba8 --- /dev/null +++ b/iocore/cache/RamCacheLRU.cc @@ -0,0 +1,197 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Cache.h" + +struct RamCacheLRUEntry { + INK_MD5 key; + uint32_t auxkey1; + uint32_t auxkey2; + LINK(RamCacheLRUEntry, lru_link); + LINK(RamCacheLRUEntry, hash_link); + Ptr data; +}; + +struct RamCacheLRU: public RamCache { + int64_t max_bytes; + int64_t bytes; + int64_t objects; + + // returns 1 on found/stored, 0 on not found/stored, if provided auxkey1 and auxkey2 must match + int get(INK_MD5 *key, Ptr *ret_data, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0); + int put(INK_MD5 *key, IOBufferData *data, uint32_t len, bool copy = false, uint32_t auxkey1 = 0, uint32_t auxkey2 = 0); + int fixup(INK_MD5 *key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2); + + void init(int64_t max_bytes, Vol *vol); + + // private + uint16_t *seen; + Que(RamCacheLRUEntry, lru_link) lru; + DList(RamCacheLRUEntry, hash_link) *bucket; + int nbuckets; + int ibuckets; + Vol *vol; + + void resize_hashtable(); + RamCacheLRUEntry *remove(RamCacheLRUEntry *e); + + RamCacheLRU():bytes(0), objects(0), seen(0), bucket(0), nbuckets(0), ibuckets(0), vol(NULL) {} +}; + +ClassAllocator ramCacheLRUEntryAllocator("RamCacheLRUEntry"); + +static const int bucket_sizes[] = { + 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, + 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, + 134217689, 268435399, 536870909 +}; + +void RamCacheLRU::resize_hashtable() { + int anbuckets = bucket_sizes[ibuckets]; + DDebug("ram_cache", "resize hashtable %d", anbuckets); + int64_t s = anbuckets * sizeof(DList(RamCacheLRUEntry, hash_link)); + DList(RamCacheLRUEntry, hash_link) *new_bucket = (DList(RamCacheLRUEntry, hash_link) *)xmalloc(s); + memset(new_bucket, 0, s); + if (bucket) { + for (int64_t i = 0; i < nbuckets; i++) { + RamCacheLRUEntry *e = 0; + while ((e = bucket[i].pop())) + new_bucket[e->key.word(3) % anbuckets].push(e); + } + xfree(bucket); + } + bucket = new_bucket; + nbuckets = anbuckets; + if (seen) xfree(seen); + int size = bucket_sizes[ibuckets] * sizeof(uint16_t); + seen = (uint16_t*)xmalloc(size); + memset(seen, 0, size); +} + +void +RamCacheLRU::init(int64_t abytes, Vol *avol) { + vol = avol; + max_bytes = abytes; + DDebug("ram_cache", "initializing ram_cache %" PRId64 " bytes", abytes); + if (!max_bytes) + return; + resize_hashtable(); +} + +int +RamCacheLRU::get(INK_MD5 * key, Ptr *ret_data, uint32_t auxkey1, uint32_t auxkey2) { + if (!max_bytes) + return 0; + uint32_t i = key->word(3) % nbuckets; + RamCacheLRUEntry *e = bucket[i].head; + while (e) { + if (e->key == *key && e->auxkey1 == auxkey1 && e->auxkey2 == auxkey2) { + lru.remove(e); + lru.enqueue(e); + (*ret_data) = e->data; + DDebug("ram_cache", "get %X %d %d HIT", key->word(3), auxkey1, auxkey2); + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_hits_stat, 1); + return 1; + } + e = e->hash_link.next; + } + DDebug("ram_cache", "get %X %d %d MISS", key->word(3), auxkey1, auxkey2); + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_misses_stat, 1); + return 0; +} + +RamCacheLRUEntry * RamCacheLRU::remove(RamCacheLRUEntry *e) { + RamCacheLRUEntry *ret = e->hash_link.next; + uint32_t b = e->key.word(3) % nbuckets; + bucket[b].remove(e); + lru.remove(e); + bytes -= e->data->block_size(); + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, -e->data->block_size()); + DDebug("ram_cache", "put %X %d %d FREED", e->key.word(3), e->auxkey1, e->auxkey2); + e->data = NULL; + THREAD_FREE(e, ramCacheLRUEntryAllocator, this_ethread()); + objects--; + return ret; +} + +// ignore 'len' and 'copy' since we don't touch the data +int RamCacheLRU::put(INK_MD5 *key, IOBufferData *data, uint32_t, bool, uint32_t auxkey1, uint32_t auxkey2) { + if (!max_bytes) + return 0; + uint32_t i = key->word(3) % nbuckets; + RamCacheLRUEntry *e = bucket[i].head; + while (e) { + if (e->key == *key) { + if (e->auxkey1 == auxkey1 && e->auxkey2 == auxkey2) + break; + else { // discard when aux keys conflict + e = remove(e); + continue; + } + } + e = e->hash_link.next; + } + e = THREAD_ALLOC(ramCacheLRUEntryAllocator, this_ethread()); + e->key = *key; + e->auxkey1 = auxkey1; + e->auxkey2 = auxkey2; + e->data = data; + bucket[i].push(e); + lru.enqueue(e); + bytes += data->block_size(); + objects++; + CACHE_SUM_DYN_STAT_THREAD(cache_ram_cache_bytes_stat, data->block_size()); + while (bytes > max_bytes) { + RamCacheLRUEntry *ee = lru.dequeue(); + if (ee) + remove(ee); + else + break; + } + DDebug("ram_cache", "put %X %d %d INSERTED", key->word(3), auxkey1, auxkey2); + if (objects > nbuckets) { + ++ibuckets; + resize_hashtable(); + } + return 1; +} + +int RamCacheLRU::fixup(INK_MD5 * key, uint32_t old_auxkey1, uint32_t old_auxkey2, uint32_t new_auxkey1, uint32_t new_auxkey2) { + if (!max_bytes) + return 0; + uint32_t i = key->word(3) % nbuckets; + RamCacheLRUEntry *e = bucket[i].head; + while (e) { + if (e->key == *key && e->auxkey1 == old_auxkey1 && e->auxkey2 == old_auxkey2) { + e->auxkey1 = new_auxkey1; + e->auxkey2 = new_auxkey2; + return 1; + } + e = e->hash_link.next; + } + return 0; +} + +RamCache *new_RamCacheLRU() { + return new RamCacheLRU; +} diff --git a/iocore/cache/Store.cc b/iocore/cache/Store.cc new file mode 100644 index 00000000..1e482f7f --- /dev/null +++ b/iocore/cache/Store.cc @@ -0,0 +1,1167 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "P_Cache.h" +#include "I_Layout.h" + +// Global +Store theStore; + + +// +// Store +// +Ptr tmp_p; +Store::Store():n_disks(0), disk(NULL) +{ +} + +int +initialize_store() +{ + return theStore.read_config()? -1 : 0; +} + +void +Store::add(Span * ds) +{ + extend(n_disks + 1); + disk[n_disks - 1] = ds; +} + +void +Store::add(Store & s) +{ + // assume on different disks + for (int i = 0; i < s.n_disks; i++) + add(s.disk[i]); + s.n_disks = 0; + s.delete_all(); +} + + + +// should be changed to handle offset in more general +// case (where this is not a free of a "just" allocated +// store +void +Store::free(Store & s) +{ + for (int i = 0; i < s.n_disks; i++) + for (Span * sd = s.disk[i]; sd; sd = sd->link.next) { + for (int j = 0; j < n_disks; j++) + for (Span * d = disk[j]; d; d = d->link.next) + if (!strcmp(sd->pathname, d->pathname)) { + if (sd->offset < d->offset) + d->offset = sd->offset; + d->blocks += sd->blocks; + goto Lfound; + } + ink_release_assert(!"Store::free failed"); + Lfound:; + } +} + +void +Store::sort() +{ + Span **vec = (Span **) alloca(sizeof(Span *) * n_disks); + memset(vec, 0, sizeof(Span *) * n_disks); + int i; + for (i = 0; i < n_disks; i++) { + vec[i] = disk[i]; + disk[i] = NULL; + } + + // sort by device + + int n = 0; + for (i = 0; i < n_disks; i++) { + for (Span * sd = vec[i]; sd; sd = vec[i]) { + vec[i] = vec[i]->link.next; + for (int d = 0; d < n; d++) { + if (sd->disk_id == disk[d]->disk_id) { + sd->link.next = disk[d]; + disk[d] = sd; + goto Ldone; + } + } + disk[n++] = sd; + Ldone:; + } + } + n_disks = n; + + // sort by pathname x offset + + for (i = 0; i < n_disks; i++) { + Lagain: + Span * prev = 0; + for (Span * sd = disk[i]; sd;) { + Span *next = sd->link.next; + if (next && + ((strcmp(sd->pathname, next->pathname) < 0) || + (!strcmp(sd->pathname, next->pathname) && sd->offset > next->offset))) { + if (!prev) { + disk[i] = next; + sd->link.next = next->link.next; + next->link.next = sd; + } else { + prev->link.next = next; + sd->link.next = next->link.next; + next->link.next = sd; + } + goto Lagain; + } + prev = sd; + sd = next; + } + } + + // merge adjacent spans + + for (i = 0; i < n_disks; i++) { + for (Span * sd = disk[i]; sd;) { + Span *next = sd->link.next; + if (next && !strcmp(sd->pathname, next->pathname)) { + if (!sd->file_pathname) { + sd->blocks += next->blocks; + } else if (next->offset <= sd->end()) { + if (next->end() >= sd->end()) + sd->blocks += (next->end() - sd->end()); + } else { + sd = next; + continue; + } + sd->link.next = next->link.next; + delete next; + sd = sd->link.next; + } else + sd = next; + } + } +} + +int +Span::path(char *filename, int64_t * aoffset, char *buf, int buflen) +{ + ink_assert(!aoffset); + Span *ds = this; + + if ((strlen(ds->pathname) + strlen(filename) + 2) > (size_t)buflen) + return -1; + if (!ds->file_pathname) { + ink_filepath_make(buf, buflen, ds->pathname, filename); + } else { + ink_strlcpy(buf, ds->pathname, buflen); + } + + return strlen(buf); +} + +void +Store::delete_all() +{ + for (int i = 0; i < n_disks; i++) + if (disk[i]) + delete disk[i]; + n_disks = 0; + if (disk) + ::xfree(disk); + disk = NULL; +} + +Store::~Store() +{ + delete_all(); +} + +Span::~Span() +{ + if (pathname) + xfree(pathname); + if (link.next) + delete link.next; +} + +inline int +get_int64(int fd, int64_t & data) +{ + char buf[PATH_NAME_MAX + 1]; + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%" PRId64 "", &data) != 1) { + return (-1); + } + return 0; +} + +int +Store::remove(char *n) +{ + bool found = false; +Lagain: + for (int i = 0; i < n_disks; i++) { + Span *p = NULL; + for (Span * sd = disk[i]; sd; sd = sd->link.next) { + if (!strcmp(n, sd->pathname)) { + found = true; + if (p) + p->link.next = sd->link.next; + else + disk[i] = sd->link.next; + sd->link.next = NULL; + delete sd; + goto Lagain; + } + p = sd; + } + } + return found ? 0 : -1; +} + +const char * +Store::read_config(int fd) +{ + int n_dsstore = 0; + int ln = 0; + const char *err = NULL; + Span *sd = NULL, *cur = NULL; + Span *ns; + + // Get pathname if not checking file + + if (fd < 0) { + char storage_path[PATH_NAME_MAX + 1]; + char storage_file[PATH_NAME_MAX + 1]; + // XXX: cache_system_config_directory is initialized + // inside ink_cache_init() which is called AFTER + // initialize_store(). + // + // ink_strncpy(p, cache_system_config_directory, sizeof(p)); + IOCORE_ReadConfigString(storage_file, "proxy.config.cache.storage_filename", PATH_NAME_MAX); + Layout::relative_to(storage_path, PATH_NAME_MAX, Layout::get()->sysconfdir, storage_file); + Debug("cache_init", "Store::read_config, fd = -1, \"%s\"", storage_path); + + fd =::open(storage_path, O_RDONLY); + if (fd < 0) { + err = "error on open"; + goto Lfail; + } + } + // For each line + + char line[256]; + while (ink_file_fd_readline(fd, sizeof(line) - 1, line) > 0) { + // update lines + + line[sizeof(line) - 1] = 0; + ln++; + + // skip comments and blank lines + + if (*line == '#') + continue; + char *n = line; + n += strspn(n, " \t\n"); + if (!*n) + continue; + + // parse + Debug("cache_init", "Store::read_config: \"%s\"", n); + + char *e = strpbrk(n, " \t\n"); + int len = e ? e - n : strlen(n); + (void) len; + int64_t size = -1; + while (e && *e && !ParseRules::is_digit(*e)) + e++; + if (e && *e) { + if ((size = ink_atoi64(e)) <= 0) { + err = "error parsing size"; + goto Lfail; + } + } + + n[len] = 0; + char *pp = Layout::get()->relative(n); + ns = NEW(new Span); + Debug("cache_init", "Store::read_config - ns = NEW (new Span); ns->init(\"%s\",%" PRId64 ")", pp, size); + if ((err = ns->init(pp, size))) { + char buf[4096]; + snprintf(buf, sizeof(buf), "could not initialize storage \"%s\" [%s]", pp, err); + IOCORE_SignalWarning(REC_SIGNAL_SYSTEM_ERROR, buf); + Debug("cache_init", "Store::read_config - %s", buf); + delete ns; + xfree(pp); + continue; + } + xfree(pp); + n_dsstore++; + + // new Span + { + Span *prev = cur; + cur = ns; + if (!sd) + sd = cur; + else + prev->link.next = cur; + } + } + + ::close(fd); + // count the number of disks + + { + extend(n_dsstore); + cur = sd; + Span *next = cur; + int i = 0; + while (cur) { + next = cur->link.next; + cur->link.next = NULL; + disk[i++] = cur; + cur = next; + } + sort(); + } + +Lfail:; + return NULL; + return err; +} + +int +Store::write_config_data(int fd) +{ + for (int i = 0; i < n_disks; i++) + for (Span * sd = disk[i]; sd; sd = sd->link.next) { + char buf[PATH_NAME_MAX + 64]; + snprintf(buf, sizeof(buf), "%s %" PRId64 "\n", sd->pathname, (int64_t) sd->blocks * (int64_t) STORE_BLOCK_SIZE); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + } + return 0; +} + +#if defined(freebsd) || defined(darwin) +// TODO: Those are probably already included from the ink_platform.h +#include +#include +#include +#include +#if defined(freebsd) +#include +//#include +#elif defined(darwin) +#include +#include +#endif +#include + +const char * +Span::init(char *an, int64_t size) +{ + int devnum = 0; + const char *err = NULL; + int ret = 0; + + // + // All file types on Solaris can be mmaped + // + is_mmapable_internal = true; + + // handle symlinks + + char *n = NULL; + int n_len = 0; + char real_n[PATH_NAME_MAX]; + + if ((n_len = readlink(an, real_n, sizeof(real_n) - 1)) > 0) { + real_n[n_len] = 0; + if (*real_n != '/') { + char *rs = strrchr(an, '/'); + int l = 2; + const char *ann = "./"; + + if (rs) { + ann = an; + l = (rs - an) + 1; + } + memmove(real_n + l, real_n, strlen(real_n) + 1); + memcpy(real_n, ann, l); + } + n = real_n; + } else { + n = an; + } + + // stat the file system + + struct stat s; + if ((ret = stat(n, &s)) < 0) { + Warning("unable to stat '%s': %d %d, %s", n, ret, errno, strerror(errno)); + return "error stat of file"; + } + + int fd = socketManager.open(n, O_RDONLY); + if (fd < 0) { + Warning("unable to open '%s': %d, %s", n, fd, strerror(errno)); + return "unable to open"; + } + + struct statfs fs; + if ((ret = fstatfs(fd, &fs)) < 0) { + Warning("unable to statfs '%s': %d %d, %s", n, ret, errno, strerror(errno)); + socketManager.close(fd); + return "unable to statfs"; + } + + hw_sector_size = fs.f_bsize; + int64_t fsize = (int64_t) fs.f_blocks * (int64_t) fs.f_bsize; + + switch ((s.st_mode & S_IFMT)) { + + case S_IFBLK:{ + case S_IFCHR: +#ifdef HAVE_RAW_DISK_SUPPORT // FIXME: darwin, freebsd + struct disklabel dl; + struct diskslices ds; + if (ioctl(fd, DIOCGDINFO, &dl) < 0) { + lvolError: + Warning("unable to get label information for '%s': %s", n, strerror(errno)); + err = "unable to get label information"; + goto Lfail; + } + { + char *s1 = n, *s2; + int slice = -1, part = -1; + if ((s2 = strrchr(s1, '/'))) + s1 = s2 + 1; + else + goto lvolError; + for (s2 = s1; *s2 && !ParseRules::is_digit(*s2); s2++); + if (!*s2 || s2 == s1) + goto lvolError; + while (ParseRules::is_digit(*++s2)); + s1 = s2; + if (*s2 == 's') { + slice = ink_atoi(s2 + 1); + if (slice<1 || slice> MAX_SLICES - BASE_SLICE) + goto lvolError; + slice = BASE_SLICE + slice - 1; + while (ParseRules::is_digit(*++s2)); + } + if (*s2 >= 'a' && *s2 <= 'a' + MAXPARTITIONS - 1) { + if (slice == -1) + slice = COMPATIBILITY_SLICE; + part = *s2++ - 'a'; + } + if (slice >= 0) { + if (ioctl(fd, DIOCGSLICEINFO, &ds) < 0) + goto lvolError; + if (slice >= (int) ds.dss_nslices || !ds.dss_slices[slice].ds_size) + goto lvolError; + fsize = (int64_t) ds.dss_slices[slice].ds_size * dl.d_secsize; + } else { + if (part < 0) + goto lvolError; + // This is odd, the dl struct isn't defined anywhere ... + fsize = (int64_t) dl.d_partitions[part].p_size * dl.d_secsize; + } + devnum = s.st_rdev; + if (size <= 0) + size = fsize; + if (size > fsize) + size = fsize; + break; + } +#else /* !HAVE_RAW_DISK_SUPPORT */ + Warning("Currently Raw Disks are not supported" ); + err = "Currently Raw Disks are not supported"; + goto Lfail; + break; +#endif /* !HAVE_RAW_DISK_SUPPORT */ + } + case S_IFDIR: + case S_IFREG: + if (size <= 0 || size > fsize) { + Warning("bad or missing size for '%s': size %" PRId64 " fsize %" PRId64 "", n, (int64_t) size, fsize); + err = "bad or missing size"; + goto Lfail; + } + devnum = s.st_dev; + break; + + default: + Warning("unknown file type '%s': %d", n, s.st_mode); + return "unknown file type"; + break; + } + + // estimate the disk SOLARIS specific + if ((devnum >> 16) == 0x80) + disk_id = (devnum >> 3) & 0x3F; + else { + disk_id = devnum; + } + + pathname = xstrdup(an); + blocks = size / STORE_BLOCK_SIZE; + file_pathname = !((s.st_mode & S_IFMT) == S_IFDIR); + + if (((s.st_mode & S_IFMT) == S_IFBLK) || ((s.st_mode & S_IFMT) == S_IFCHR)) { + blocks--; + offset = 1; + } +Lfail: + socketManager.close(fd); + return err; +} +#endif + +#if defined(solaris) +// TODO: Those are probably already included from the ink_platform.h +#include +#include +#include +#include +#include +#include +#include + +const char * +Span::init(char *filename, int64_t size) +{ + int devnum = 0; + const char *err = NULL; + int ret = 0; + + // + // All file types on Solaris can be mmaped + // + is_mmapable_internal = true; + + int fd = socketManager.open(filename, O_RDONLY); + if (fd < 0) { + Warning("unable to open '%s': %d, %s", filename, fd, strerror(errno)); + return "unable to open"; + } + + // stat the file system + struct stat s; + if ((ret = fstat(fd, &s)) < 0) { + Warning("unable to fstat '%s': %d %d, %s", filename, ret, errno, strerror(errno)); + err = "unable to fstat"; + goto Lfail; + } + + + switch ((s.st_mode & S_IFMT)) { + + case S_IFBLK: + case S_IFCHR: + devnum = s.st_rdev; + // maybe we should use lseek(fd, 0, SEEK_END) here (it is portable) + size = (int64_t) s.st_size; + hw_sector_size = s.st_blksize; + break; + case S_IFDIR: + case S_IFREG: + int64_t fsize; + struct statvfs fs; + if ((ret = fstatvfs(fd, &fs)) < 0) { + Warning("unable to statvfs '%s': %d %d, %s", filename, ret, errno, strerror(errno)); + err = "unable to statvfs"; + goto Lfail; + } + + hw_sector_size = fs.f_bsize; + fsize = (int64_t) fs.f_blocks * (int64_t) hw_sector_size; + + if (size <= 0 || size > fsize) { + Warning("bad or missing size for '%s': size %" PRId64 " fsize %" PRId64 "", filename, (int64_t) size, fsize); + err = "bad or missing size"; + goto Lfail; + } + + devnum = s.st_dev; + break; + + default: + Warning("unknown file type '%s': %d", filename, s.st_mode); + err = "unknown file type"; + goto Lfail; + } + + // estimate the disk SOLARIS specific + if ((devnum >> 16) == 0x80) { + disk_id = (devnum >> 3) & 0x3F; + } else { + disk_id = devnum; + } + + pathname = xstrdup(filename); + // is this right Seems like this should be size / hw_sector_size + blocks = size / STORE_BLOCK_SIZE; + file_pathname = !((s.st_mode & S_IFMT) == S_IFDIR); + + Debug("cache_init", "Span::init - %s hw_sector_size = %d size = %" PRId64 ", blocks = %" PRId64 ", disk_id = %d, file_pathname = %d", filename, hw_sector_size, size, blocks, disk_id, file_pathname); + +Lfail: + socketManager.close(fd); + return err; +} +#endif + +#if defined(linux) +// TODO: Axe extra includes +#include +#include +#include +#include /* for close() */ +#include +#include /* for struct hd_geometry */ +#include /* for BLKGETSIZE. sys/mount.h is another candidate */ + + +const char * +Span::init(char *filename, int64_t size) +{ + int devnum = 0, fd, arg = 0; + int ret = 0, is_disk = 0; + unsigned int heads, sectors, cylinders, adjusted_sec; + + /* Fetch file type */ + struct stat stat_buf; + Debug("cache_init", "Span::init(\"%s\",%" PRId64 ")", filename, size); + if ((ret = stat(filename, &stat_buf)) < 0) { + Warning("unable to stat '%s': %d %d, %s", filename, ret, errno, strerror(errno)); + return "cannot stat file"; + } + switch (stat_buf.st_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + devnum = stat_buf.st_rdev; + Debug("cache_init", "Span::init - %s - devnum = %d", + ((stat_buf.st_mode & S_IFMT) == S_IFBLK) ? "S_IFBLK" : "S_IFCHR", devnum); + break; + case S_IFDIR: + devnum = stat_buf.st_dev; + file_pathname = 0; + Debug("cache_init", "Span::init - S_IFDIR - devnum = %d", devnum); + break; + case S_IFREG: + devnum = stat_buf.st_dev; + file_pathname = 1; + size = stat_buf.st_size; + Debug("cache_init", "Span::init - S_IFREG - devnum = %d", devnum); + break; + default: + break; + } + + if ((fd = socketManager.open(filename, O_RDONLY)) < 0) { + Warning("unable to open '%s': %d, %s", filename, fd, strerror(errno)); + return "unable to open"; + } + Debug("cache_init", "Span::init - socketManager.open(\"%s\", O_RDONLY) = %d", filename, fd); + + adjusted_sec = 1; +#ifdef BLKPBSZGET + if (ioctl(fd, BLKPBSZGET, &arg) == 0) +#else + if (ioctl(fd, BLKSSZGET, &arg) == 0) +#endif + { + hw_sector_size = arg; + is_disk = 1; + adjusted_sec = hw_sector_size / 512; + Debug("cache_init", "Span::init - %s hw_sector_size = %d,is_disk = %d,adjusted_sec = %d", filename, hw_sector_size, is_disk,adjusted_sec); + } + + alignment = 0; +#ifdef BLKALIGNOFF + if (ioctl(fd, BLKALIGNOFF, &arg) == 0) { + alignment = arg; + Debug("cache_init", "Span::init - %s alignment = %d", filename, alignment); + } +#endif + + if (is_disk) { + uint32_t physsectors = 0; + + /* Disks cannot be mmapped */ + is_mmapable_internal = false; + + if (!ioctl(fd, BLKGETSIZE, &physsectors)) { + heads = 1; + cylinders = 1; + sectors = physsectors / adjusted_sec; + } else { + struct hd_geometry geometry; + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { + heads = geometry.heads; + sectors = geometry.sectors; + cylinders = geometry.cylinders; + cylinders /= adjusted_sec; /* do not round up */ + } else { + /* Almost certainly something other than a disk device. */ + Warning("unable to get geometry '%s': %d %s", filename, errno, strerror(errno)); + return ("unable to get geometry"); + } + } + + blocks = heads * sectors * cylinders; + + if (size > 0 && blocks * hw_sector_size != size) { + Warning("Warning: you specified a size of %" PRId64 " for %s,\n", size, filename); + Warning("but the device size is %" PRId64 ". Using minimum of the two.\n", blocks * hw_sector_size); + if (blocks * hw_sector_size < size) + size = blocks * hw_sector_size; + } else { + size = blocks * hw_sector_size; + } + + /* I don't know why I'm redefining blocks to be something that is quite + * possibly something other than the actual number of blocks, but the + * code for other arches seems to. Revisit this, perhaps. */ + blocks = size / STORE_BLOCK_SIZE; + + Debug("cache_init", "Span::init physical sectors %u total size %" PRId64 " geometry size %" PRId64 " store blocks %" PRId64 "", + physsectors, hw_sector_size * (int64_t)physsectors, size, blocks); + + pathname = xstrdup(filename); + file_pathname = 1; + } else { + Debug("cache_init", "Span::init - is_disk = %d, raw device = %s", is_disk, (major(devnum) == 162) ? "yes" : "no"); + if (major(devnum) == 162) { + /* Oh, a raw device, how cute. */ + + if (minor(devnum) == 0) + return "The raw device control file (usually /dev/raw; major 162, minor 0) is not a valid cache location.\n"; + + is_disk = 1; + is_mmapable_internal = false; /* I -think- */ + file_pathname = 1; + pathname = xstrdup(filename); + isRaw = 1; + + if (size <= 0) + return "When using raw devices for cache storage, you must specify a size\n"; + } else { + /* Files can be mmapped */ + is_mmapable_internal = true; + + /* The code for other arches seems to want to dereference symlinks, but I + * don't particularly understand that behaviour, so I'll just ignore it. + * :) */ + + pathname = xstrdup(filename); + if (!file_pathname) + if (size <= 0) + return "When using directories for cache storage, you must specify a size\n"; + Debug("cache_init", "Span::init - mapped file \"%s\", %" PRId64 "", pathname, size); + } + blocks = size / STORE_BLOCK_SIZE; + } + + disk_id = devnum; + + socketManager.close(fd); + + return NULL; +} +#endif + + + +void +Store::normalize() +{ + int ndisks = 0; + for (int i = 0; i < n_disks; i++) + if (disk[i]) + disk[ndisks++] = disk[i]; + n_disks = ndisks; +} + +static unsigned int +try_alloc(Store & target, Span * source, unsigned int start_blocks, bool one_only = false) +{ + unsigned int blocks = start_blocks; + Span *ds = NULL; + while (source && blocks) { + if (source->blocks) { + unsigned int a; // allocated + if (blocks > source->blocks) + a = source->blocks; + else + a = blocks; + Span *d = NEW(new Span(*source)); + + d->pathname = xstrdup(source->pathname); + d->blocks = a; + d->file_pathname = source->file_pathname; + d->offset = source->offset; + d->link.next = ds; + + if (d->file_pathname) + source->offset += a; + source->blocks -= a; + ds = d; + blocks -= a; + if (one_only) + break; + } + source = source->link.next; + } + if (ds) + target.add(ds); + return start_blocks - blocks; +} + +void +Store::spread_alloc(Store & s, unsigned int blocks, bool mmapable) +{ + // + // Count the eligable disks.. + // + int mmapable_disks = 0; + for (int k = 0; k < n_disks; k++) { + if (disk[k]->is_mmapable()) { + mmapable_disks++; + } + } + + int spread_over = n_disks; + if (mmapable) { + spread_over = mmapable_disks; + } + + if (spread_over == 0) { + return; + } + + int disks_left = spread_over; + + for (int i = 0; blocks && i < n_disks; i++) { + if (!(mmapable && !disk[i]->is_mmapable())) { + unsigned int target = blocks / disks_left; + if (blocks - target > total_blocks(i + 1)) + target = blocks - total_blocks(i + 1); + blocks -= try_alloc(s, disk[i], target); + disks_left--; + } + } +} + +void +Store::try_realloc(Store & s, Store & diff) +{ + int i = 0; + for (i = 0; i < s.n_disks; i++) { + Span *prev = 0; + for (Span * sd = s.disk[i]; sd;) { + for (int j = 0; j < n_disks; j++) + for (Span * d = disk[j]; d; d = d->link.next) + if (!strcmp(sd->pathname, d->pathname)) { + if (sd->offset >= d->offset && (sd->end() <= d->end())) { + if (!sd->file_pathname || (sd->end() == d->end())) { + d->blocks -= sd->blocks; + goto Lfound; + } else if (sd->offset == d->offset) { + d->blocks -= sd->blocks; + d->offset += sd->blocks; + goto Lfound; + } else { + Span *x = NEW(new Span(*d)); + x->pathname = xstrdup(x->pathname); + // d will be the first vol + d->blocks = sd->offset - d->offset; + d->link.next = x; + // x will be the last vol + x->offset = sd->offset + sd->blocks; + x->blocks -= x->offset - d->offset; + goto Lfound; + } + } + } + { + if (!prev) + s.disk[i] = s.disk[i]->link.next; + else + prev->link.next = sd->link.next; + diff.extend(i + 1); + sd->link.next = diff.disk[i]; + diff.disk[i] = sd; + sd = prev ? prev->link.next : s.disk[i]; + continue; + } + Lfound:; + prev = sd; + sd = sd->link.next; + } + } + normalize(); + s.normalize(); + diff.normalize(); +} + +// +// Stupid grab first availabled space allocator +// +void +Store::alloc(Store & s, unsigned int blocks, bool one_only, bool mmapable) +{ + unsigned int oblocks = blocks; + for (int i = 0; blocks && i < n_disks; i++) { + if (!(mmapable && !disk[i]->is_mmapable())) { + blocks -= try_alloc(s, disk[i], blocks, one_only); + if (one_only && oblocks != blocks) + break; + } + } +} + +int +Span::write(int fd) +{ + char buf[32]; + + if (ink_file_fd_writestring(fd, (char *) (pathname ? pathname : ")")) == -1) + return (-1); + if (ink_file_fd_writestring(fd, "\n") == -1) + return (-1); + + snprintf(buf, sizeof(buf), "%" PRId64 "\n", blocks); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + + snprintf(buf, sizeof(buf), "%d\n", file_pathname); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + + snprintf(buf, sizeof(buf), "%" PRId64 "\n", offset); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + + snprintf(buf, sizeof(buf), "%d\n", (int) is_mmapable()); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + + return 0; +} + +int +Store::write(int fd, char *name) +{ + char buf[32]; + + if (ink_file_fd_writestring(fd, name) == -1) + return (-1); + if (ink_file_fd_writestring(fd, "\n") == -1) + return (-1); + + snprintf(buf, sizeof(buf), "%d\n", n_disks); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + + for (int i = 0; i < n_disks; i++) { + int n = 0; + Span *sd = NULL; + for (sd = disk[i]; sd; sd = sd->link.next) + n++; + + snprintf(buf, sizeof(buf), "%d\n", n); + if (ink_file_fd_writestring(fd, buf) == -1) + return (-1); + + for (sd = disk[i]; sd; sd = sd->link.next) { + if (sd->write(fd)) + return -1; + } + } + return 0; +} + +int +Span::read(int fd) +{ + char buf[PATH_NAME_MAX + 1], p[PATH_NAME_MAX + 1]; + + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%s", p) != 1) { + return (-1); + } + pathname = xstrdup(p); + if (get_int64(fd, blocks) < 0) { + return -1; + } + + int b = 0; + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%d", &b) != 1) + return (-1); + file_pathname = (b ? true : false); + + if (get_int64(fd, offset) < 0) { + return -1; + } + + int tmp; + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%d", &tmp) != 1) + return (-1); + set_mmapable(tmp != 0); + + return (0); +} + +int +Store::read(int fd, char *aname) +{ + char *name = aname; + char tname[PATH_NAME_MAX + 1]; + char buf[PATH_NAME_MAX + 1]; + if (!aname) + name = tname; + + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%s\n", name) != 1) + return (-1); + + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%d\n", &n_disks) != 1) + return (-1); + + disk = (Span **) xmalloc(sizeof(Span *) * n_disks); + if (!disk) + return -1; + memset(disk, 0, sizeof(Span *) * n_disks); + int i; + for (i = 0; i < n_disks; i++) { + int n = 0; + + if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0) + return (-1); + // the above line will guarantee buf to be no longer than PATH_NAME_MAX + // so the next statement should be a safe use of sscanf + // coverity[secure_coding] + if (sscanf(buf, "%d\n", &n) != 1) + return (-1); + + Span *sd = NULL; + while (n--) { + Span *last = sd; + sd = NEW(new Span); + + if (!last) + disk[i] = sd; + else + last->link.next = sd; + if (sd->read(fd)) + goto Lbail; + } + } + return 0; +Lbail: + for (i = 0; i < n_disks; i++) { + if (disk[i]) + delete disk[i]; + } + return -1; +} + +Span * +Span::dup() +{ + Span *ds = NEW(new Span(*this)); + ds->pathname = xstrdup(pathname); + if (ds->link.next) + ds->link.next = ds->link.next->dup(); + return ds; +} + +void +Store::dup(Store & s) +{ + s.n_disks = n_disks; + s.disk = (Span **) xmalloc(sizeof(Span *) * n_disks); + for (int i = 0; i < n_disks; i++) + s.disk[i] = disk[i]->dup(); +} + +int +Store::clear(char *filename, bool clear_dirs) +{ + char z[STORE_BLOCK_SIZE]; + memset(z, 0, STORE_BLOCK_SIZE); + for (int i = 0; i < n_disks; i++) { + Span *ds = disk[i]; + for (int j = 0; j < disk[i]->paths(); j++) { + char path[PATH_NAME_MAX + 1]; + Span *d = ds->nth(j); + if (!clear_dirs && !d->file_pathname) + continue; + int r = d->path(filename, NULL, path, PATH_NAME_MAX); + if (r < 0) + return -1; + int fd =::open(path, O_RDWR | O_CREAT, 0644); + if (fd < 0) + return -1; + for (int b = 0; d->blocks; b++) + if (socketManager.pwrite(fd, z, STORE_BLOCK_SIZE, d->offset + (b * STORE_BLOCK_SIZE)) < 0) { + close(fd); + return -1; + } + close(fd); + } + } + return 0; +} diff --git a/iocore/cluster/ClusterAPI.cc b/iocore/cluster/ClusterAPI.cc new file mode 100644 index 00000000..af614e64 --- /dev/null +++ b/iocore/cluster/ClusterAPI.cc @@ -0,0 +1,589 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterAPI.cc + + Support for Cluster RPC API. +****************************************************************************/ +#include "P_Cluster.h" + +#ifdef NON_MODULAR +#include "InkAPIInternal.h" + +class ClusterAPIPeriodicSM; +static void send_machine_online_list(TSClusterStatusHandle_t *); + +typedef struct node_callout_entry +{ + Ptr mutex; + TSClusterStatusFunction func; + int state; // See NE_STATE_XXX defines +} node_callout_entry_t; + +#define NE_STATE_FREE 0 +#define NE_STATE_INITIALIZED 1 + +#define MAX_CLUSTERSTATUS_CALLOUTS 32 + +static ProxyMutex *ClusterAPI_mutex; +static ClusterAPIPeriodicSM *periodicSM; + +static node_callout_entry_t status_callouts[MAX_CLUSTERSTATUS_CALLOUTS]; +static TSClusterRPCFunction RPC_Functions[API_END_CLUSTER_FUNCTION]; + +#define INDEX_TO_CLUSTER_STATUS_HANDLE(i) ((TSClusterStatusHandle_t)((i))) +#define CLUSTER_STATUS_HANDLE_TO_INDEX(h) ((int) ((h))) +#define NODE_HANDLE_TO_IP(h) (*((struct in_addr *) &((h)))) +#define RPC_FUNCTION_KEY_TO_CLUSTER_NUMBER(k) ((int)((k))) +#define IP_TO_NODE_HANDLE(ip) ((TSNodeHandle_t)((ip))) +#define SIZEOF_RPC_MSG_LESS_DATA (sizeof(TSClusterRPCMsg_t) - \ + (sizeof(TSClusterRPCMsg_t) - sizeof(TSClusterRPCHandle_t))) + +typedef struct RPCHandle +{ + union + { // Note: All union elements are assumed to be the same size + // sizeof(u.internal) == sizeof(u.external) + TSClusterRPCHandle_t external; + struct real_format + { + int cluster_function; + int magic; + } internal; + } u; +} RPCHandle_t; + +#define RPC_HANDLE_MAGIC 0x12345678 + +class MachineStatusSM; +typedef int (MachineStatusSM::*MachineStatusSMHandler) (int, void *); +class MachineStatusSM:public Continuation +{ +public: + // Broadcast constructor + MachineStatusSM(TSNodeHandle_t h, TSNodeStatus_t s):_node_handle(h), _node_status(s), _status_handle(0), + _broadcast(1), _restart(0), _next_n(0) + { + SET_HANDLER((MachineStatusSMHandler) + & MachineStatusSM::MachineStatusSMEvent); + } + // Unicast constructor + MachineStatusSM(TSNodeHandle_t h, TSNodeStatus_t s, + TSClusterStatusHandle_t sh):_node_handle(h), _node_status(s), _status_handle(sh), + _broadcast(0), _restart(0), _next_n(0) + { + SET_HANDLER((MachineStatusSMHandler) + & MachineStatusSM::MachineStatusSMEvent); + } + // Send machine online list constructor +MachineStatusSM(TSClusterStatusHandle_t sh): + _node_handle(0), _node_status(NODE_ONLINE), _status_handle(sh), _broadcast(0), _restart(0), _next_n(0) { + SET_HANDLER((MachineStatusSMHandler) + & MachineStatusSM::MachineStatusSMEvent); + } + ~MachineStatusSM() { + } + int MachineStatusSMEvent(Event * e, void *d); + +private: + TSNodeHandle_t _node_handle; + TSNodeStatus_t _node_status; + TSClusterStatusHandle_t _status_handle; // Valid only if !_broadcast + int _broadcast; + int _restart; + int _next_n; +}; + +int +MachineStatusSM::MachineStatusSMEvent(Event * e, void *d) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(d); + int n; + EThread *et = this_ethread(); + + if (_broadcast) { + ///////////////////////////////////////////////////// + // Broadcast node transition to all subscribers + ///////////////////////////////////////////////////// + n = _restart ? _next_n : 0; + for (; n < MAX_CLUSTERSTATUS_CALLOUTS; ++n) { + if (status_callouts[n].func && (status_callouts[n].state == NE_STATE_INITIALIZED)) { + + MUTEX_TRY_LOCK(lock, status_callouts[n].mutex, et); + if (lock) { + status_callouts[n].func(&_node_handle, _node_status); + Debug("cluster_api", "callout: n %d ([%u.%u.%u.%u], %d)", n, DOT_SEPARATED(_node_handle), _node_status); + } else { + _restart = 1; + _next_n = n; + return EVENT_CONT; + } + } + } + } else { + if (!_node_handle) { + ///////////////////////////////////////////////////// + // Send online node list to a specific subscriber + ///////////////////////////////////////////////////// + n = CLUSTER_STATUS_HANDLE_TO_INDEX(_status_handle); + if (status_callouts[n].func) { + MUTEX_TRY_LOCK(lock, status_callouts[n].mutex, et); + if (lock) { + int mi; + unsigned int my_ipaddr = (this_cluster_machine())->ip; + ClusterConfiguration *cc; + + TSNodeHandle_t nh; + + cc = this_cluster()->current_configuration(); + if (cc) { + for (mi = 0; mi < cc->n_machines; ++mi) { + if (cc->machines[mi]->ip != my_ipaddr) { + nh = IP_TO_NODE_HANDLE(cc->machines[mi]->ip); + status_callouts[n].func(&nh, NODE_ONLINE); + + Debug("cluster_api", + "initial callout: n %d ([%u.%u.%u.%u], %d)", n, DOT_SEPARATED(cc->machines[mi]->ip), NODE_ONLINE); + } + } + } + status_callouts[n].state = NE_STATE_INITIALIZED; + + } else { + _restart = 1; + _next_n = n; + return EVENT_CONT; + } + } + } else { + ///////////////////////////////////////////////////// + // Send node status to a specific subscriber + ///////////////////////////////////////////////////// + n = CLUSTER_STATUS_HANDLE_TO_INDEX(_status_handle); + if (status_callouts[n].func) { + MUTEX_TRY_LOCK(lock, status_callouts[n].mutex, et); + if (lock) { + status_callouts[n].func(&_node_handle, _node_status); + + Debug("cluster_api", + "directed callout: n %d ([%u.%u.%u.%u], %d)", n, DOT_SEPARATED(_node_handle), _node_status); + } else { + _restart = 1; + _next_n = n; + return EVENT_CONT; + } + } + } + } + delete this; + return EVENT_DONE; +} + +class ClusterAPIPeriodicSM; +typedef int (ClusterAPIPeriodicSM::*ClusterAPIPeriodicSMHandler) (int, void *); +class ClusterAPIPeriodicSM:public Continuation +{ +public: + ClusterAPIPeriodicSM(ProxyMutex * m):Continuation(m), _active_msmp(0) + { + SET_HANDLER((ClusterAPIPeriodicSMHandler) + & ClusterAPIPeriodicSM::ClusterAPIPeriodicSMEvent); + } + ~ClusterAPIPeriodicSM() + { + } + int ClusterAPIPeriodicSMEvent(int, void *); + MachineStatusSM *GetNextSM(); + +private: + MachineStatusSM * _active_msmp; +}; + +static InkAtomicList status_callout_atomic_q; +static Queue status_callout_q; + +MachineStatusSM * +ClusterAPIPeriodicSM::GetNextSM() +{ + MachineStatusSM *msmp; + MachineStatusSM *msmp_next; + + while (1) { + msmp = status_callout_q.pop(); + if (!msmp) { + msmp = (MachineStatusSM *) + ink_atomiclist_popall(&status_callout_atomic_q); + if (msmp) { + while (msmp) { + msmp_next = (MachineStatusSM *) msmp->link.next; + msmp->link.next = 0; + status_callout_q.push(msmp); + msmp = msmp_next; + } + continue; + } else { + break; + } + } else { + break; + } + } + return msmp; +} + +int +ClusterAPIPeriodicSM::ClusterAPIPeriodicSMEvent(int e, void *d) +{ + // Maintain node status event order by serializing the processing. + int ret; + + while (1) { + if (_active_msmp) { + ret = _active_msmp->handleEvent(e, d); + if (ret != EVENT_DONE) { + return EVENT_CONT; + } + } + _active_msmp = GetNextSM(); + if (!_active_msmp) { + break; + } + } + return EVENT_CONT; +} + +void +clusterAPI_init() +{ + MachineStatusSM *mssmp = 0; + // XXX: BIG RED WARNING!!! Direct null pointer dereference + // Either create MachineStatusSM before ose or axe this function. + // It is used only if NON_MODULAR is defined making that + // flag crashing ClusterProcessor::init() + // + ink_atomiclist_init(&status_callout_atomic_q, + "cluster API status_callout_q", (char *) &mssmp->link.next - (char *) mssmp); + ClusterAPI_mutex = new_ProxyMutex(); + MUTEX_TRY_LOCK(lock, ClusterAPI_mutex, this_ethread()); + ink_release_assert(lock); // Should never fail + periodicSM = NEW(new ClusterAPIPeriodicSM(ClusterAPI_mutex)); + + // TODO: Should we do something with this return value? + eventProcessor.schedule_every(periodicSM, HRTIME_SECONDS(1), ET_CALL); +} + +/* + * Add the given function to the node status callout list which is + * invoked on each machine up/down transition. + * + * Note: Using blocking mutex since interface is synchronous and is only + * called at plugin load time. + */ +int +TSAddClusterStatusFunction(TSClusterStatusFunction Status_Function, TSMutex m, TSClusterStatusHandle_t * h) +{ + Debug("cluster_api", "TSAddClusterStatusFunction func 0x%x", Status_Function); + int n; + EThread *e = this_ethread(); + + ink_release_assert(Status_Function); + MUTEX_TAKE_LOCK(ClusterAPI_mutex, e); + for (n = 0; n < MAX_CLUSTERSTATUS_CALLOUTS; ++n) { + if (!status_callouts[n].func) { + status_callouts[n].mutex = (ProxyMutex *) m; + status_callouts[n].func = Status_Function; + MUTEX_UNTAKE_LOCK(ClusterAPI_mutex, e); + *h = INDEX_TO_CLUSTER_STATUS_HANDLE(n); + + Debug("cluster_api", "TSAddClusterStatusFunction: func 0x%x n %d", Status_Function, n); + return 0; + } + } + MUTEX_UNTAKE_LOCK(ClusterAPI_mutex, e); + return 1; +} + +/* + * Remove the given function from the node status callout list + * established via TSAddClusterStatusFunction(). + * + * Note: Using blocking mutex since interface is synchronous and is only + * called at plugin unload time (unload currently not supported). + */ +int +TSDeleteClusterStatusFunction(TSClusterStatusHandle_t * h) +{ + int n = CLUSTER_STATUS_HANDLE_TO_INDEX(*h); + EThread *e = this_ethread(); + + ink_release_assert((n >= 0) && (n < MAX_CLUSTERSTATUS_CALLOUTS)); + Debug("cluster_api", "TSDeleteClusterStatusFunction: n %d", n); + + MUTEX_TAKE_LOCK(ClusterAPI_mutex, e); + status_callouts[n].mutex = 0; + status_callouts[n].func = (TSClusterStatusFunction) 0; + status_callouts[n].state = NE_STATE_FREE; + MUTEX_UNTAKE_LOCK(ClusterAPI_mutex, e); + + return 0; +} + +int +TSNodeHandleToIPAddr(TSNodeHandle_t * h, struct in_addr *in) +{ + *in = NODE_HANDLE_TO_IP(*h); + return 0; +} + +void +TSGetMyNodeHandle(TSNodeHandle_t * h) +{ + *h = IP_TO_NODE_HANDLE((this_cluster_machine())->ip); +} + +/* + * Enable node status callouts for the added callout entry. + * Issued once after the call to TSAddClusterStatusFunction() + * to get the current node configuration. All subsequent + * callouts are updates to the state obtained at this point. + */ +void +TSEnableClusterStatusCallout(TSClusterStatusHandle_t * h) +{ + int ci = CLUSTER_STATUS_HANDLE_TO_INDEX(*h); + // This isn't used. + // int my_ipaddr = (this_cluster_machine())->ip; + ink_release_assert((ci >= 0) && (ci < MAX_CLUSTERSTATUS_CALLOUTS)); + + if (status_callouts[ci].state == NE_STATE_INITIALIZED) { + return; + } + + Debug("cluster_api", "TSEnableClusterStatusCallout: n %d", ci); + send_machine_online_list(h); +} + +static void +send_machine_online_list(TSClusterStatusHandle_t * h) +{ + MachineStatusSM *msm = NEW(new MachineStatusSM(*h)); + + ink_atomiclist_push(&status_callout_atomic_q, (void *) msm); +} + +/* + * Send node online to a specific cluster status entry. + */ +// This doesn't seem to be used... +#ifdef NOT_USED_HERE +static void +directed_machine_online(int Ipaddr, TSClusterStatusHandle_t * h) +{ + MachineStatusSM *msm = NEW(new MachineStatusSM(IP_TO_NODE_HANDLE(Ipaddr), NODE_ONLINE, *h)); + + ink_atomiclist_push(&status_callout_atomic_q, (void *) msm); +} +#endif + +/* + * Called directly by the Cluster upon detection of node online. + */ +void +machine_online_APIcallout(int Ipaddr) +{ + MachineStatusSM *msm = NEW(new MachineStatusSM(IP_TO_NODE_HANDLE(Ipaddr), NODE_ONLINE)); + + ink_atomiclist_push(&status_callout_atomic_q, (void *) msm); +} + +/* + * Called directly by the Cluster upon detection of node offline. + */ +void +machine_offline_APIcallout(int Ipaddr) +{ + MachineStatusSM *msm = NEW(new MachineStatusSM(IP_TO_NODE_HANDLE(Ipaddr), NODE_OFFLINE)); + + ink_atomiclist_push(&status_callout_atomic_q, (void *) msm); +} + +/* + * Associate the given RPC function with the given key. + * + * Note: Using blocking mutex since interface is synchronous and is only + * called at plugin load time. + */ +int +TSAddClusterRPCFunction(TSClusterRPCKey_t k, TSClusterRPCFunction func, TSClusterRPCHandle_t * h) +{ + RPCHandle_t handle; + int n = RPC_FUNCTION_KEY_TO_CLUSTER_NUMBER(k); + EThread *e = this_ethread(); + + ink_release_assert(func); + ink_release_assert((n >= API_STARECT_CLUSTER_FUNCTION) + && (n <= API_END_CLUSTER_FUNCTION)); + Debug("cluster_api", "TSAddClusterRPCFunction: key %d func 0x%x", k, func); + + handle.u.internal.cluster_function = n; + handle.u.internal.magic = RPC_HANDLE_MAGIC; + + MUTEX_TAKE_LOCK(ClusterAPI_mutex, e); + if (n < API_END_CLUSTER_FUNCTION) + RPC_Functions[n] = func; + MUTEX_UNTAKE_LOCK(ClusterAPI_mutex, e); + + *h = handle.u.external; + return 0; +} + +/* + * Remove the given RPC function added via TSAddClusterRPCFunction(). + * + * Note: Using blocking mutex since interface is synchronous and is only + * called at plugin unload time (unload currently not supported). + */ +int +TSDeleteClusterRPCFunction(TSClusterRPCHandle_t * rpch) +{ + RPCHandle_t *h = (RPCHandle_t *) rpch; + EThread *e = this_ethread(); + + ink_release_assert(((h->u.internal.cluster_function >= API_STARECT_CLUSTER_FUNCTION) + && (h->u.internal.cluster_function <= API_END_CLUSTER_FUNCTION))); + Debug("cluster_api", "TSDeleteClusterRPCFunction: n %d", h->u.internal.cluster_function); + + MUTEX_TAKE_LOCK(ClusterAPI_mutex, e); + RPC_Functions[h->u.internal.cluster_function] = 0; + MUTEX_UNTAKE_LOCK(ClusterAPI_mutex, e); + return 0; +} + +/* + * Cluster calls us here for each RPC API function. + */ +void +default_api_ClusterFunction(ClusterMachine * m, void *data, int len) +{ + Debug("cluster_api", "default_api_ClusterFunction: [%u.%u.%u.%u] data 0x%x len %d", DOT_SEPARATED(m->ip), data, len); + + TSClusterRPCMsg_t *msg = (TSClusterRPCMsg_t *) data; + RPCHandle_t *rpch = (RPCHandle_t *) & msg->m_handle; + int cluster_function = rpch->u.internal.cluster_function; + + ink_release_assert((size_t) len >= sizeof(TSClusterRPCMsg_t)); + ink_release_assert(((cluster_function >= API_STARECT_CLUSTER_FUNCTION) + && (cluster_function <= API_END_CLUSTER_FUNCTION))); + + if (cluster_function < API_END_CLUSTER_FUNCTION && RPC_Functions[cluster_function]) { + int msg_data_len = len - SIZEOF_RPC_MSG_LESS_DATA; + TSNodeHandle_t nh = IP_TO_NODE_HANDLE(m->ip); + (*RPC_Functions[cluster_function]) (&nh, msg, msg_data_len); + } else { + clusterProcessor.free_remote_data((char *) data, len); + } +} + +/* + * Free TSClusterRPCMsg_t received via the RPC function. + */ +void +TSFreeRPCMsg(TSClusterRPCMsg_t * msg, int msg_data_len) +{ + RPCHandle_t *rpch = (RPCHandle_t *) & msg->m_handle; + ink_release_assert(rpch->u.internal.magic == RPC_HANDLE_MAGIC); + Debug("cluster_api", "TSFreeRPCMsg: msg 0x%x msg_data_len %d", msg, msg_data_len); + + clusterProcessor.free_remote_data((char *) msg, msg_data_len + SIZEOF_RPC_MSG_LESS_DATA); +} + +/* + * Allocate a message structure for use in the call to TSSendClusterRPC(). + */ +TSClusterRPCMsg_t * +TSAllocClusterRPCMsg(TSClusterRPCHandle_t * h, int data_size) +{ + ink_debug_assert(data_size >= 4); + if (data_size < 4) { + /* Message must be at least 4 bytes in length */ + return (TSClusterRPCMsg_t *) 0; + } + + TSClusterRPCMsg_t *rpcm; + OutgoingControl *c = OutgoingControl::alloc(); + + c->len = sizeof(OutgoingControl *) + SIZEOF_RPC_MSG_LESS_DATA + data_size; + c->alloc_data(); + *((OutgoingControl **) c->data) = c; + + rpcm = (TSClusterRPCMsg_t *) (c->data + sizeof(OutgoingControl *)); + rpcm->m_handle = *h; + + /* + * Note: We have carefully constructed TSClusterRPCMsg_t so + * m_data[] is 8 byte aligned. This allows the user to + * cast m_data[] to any type without any consideration + * for alignment issues. + */ + return rpcm; +} + +/* + * Send the given message to the specified node. + */ +int +TSSendClusterRPC(TSNodeHandle_t * nh, TSClusterRPCMsg_t * msg) +{ + struct in_addr ipaddr = NODE_HANDLE_TO_IP(*nh); + RPCHandle_t *rpch = (RPCHandle_t *) & msg->m_handle; + + OutgoingControl *c = *((OutgoingControl **) + ((char *) msg - sizeof(OutgoingControl *))); + ClusterConfiguration * cc = this_cluster()->current_configuration(); + ClusterMachine *m; + + ink_release_assert(rpch->u.internal.magic == RPC_HANDLE_MAGIC); + + if ((m = cc->find(ipaddr.s_addr))) { + int len = c->len - sizeof(OutgoingControl *); + ink_release_assert((size_t) len >= sizeof(TSClusterRPCMsg_t)); + + clusterProcessor.invoke_remote(m, rpch->u.internal.cluster_function, + msg, len, (CLUSTER_OPT_STEAL | CLUSTER_OPT_DATA_IS_OCONTROL)); + Debug("cluster_api", "TSSendClusterRPC: msg 0x%x dlen %d [%u.%u.%u.%u] sent", msg, len, DOT_SEPARATED(ipaddr.s_addr)); + } else { + Debug("cluster_api", "TSSendClusterRPC: msg 0x%x to [%u.%u.%u.%u] dropped", msg, DOT_SEPARATED(ipaddr.s_addr)); + c->freeall(); + } + + return 0; +} +#endif /* NON_MODULAR */ + +/* + * End of ClusterAPI.cc + */ diff --git a/iocore/cluster/ClusterCache.cc b/iocore/cluster/ClusterCache.cc new file mode 100644 index 00000000..3f0a330d --- /dev/null +++ b/iocore/cluster/ClusterCache.cc @@ -0,0 +1,3215 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ClusterCache.cc +****************************************************************************/ + +#include "P_Cluster.h" + +#ifdef DEBUG +#define CLUSTER_TEST_DEBUG 1 +#endif + +#ifdef ENABLE_TIME_TRACE +int callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +int cache_callbacks = 0; + +int rmt_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +int rmt_cache_callbacks = 0; + +int lkrmt_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +int lkrmt_cache_callbacks = 0; + +int cntlck_acquire_time_dist[TIME_DIST_BUCKETS_SIZE]; +int cntlck_acquire_events = 0; + +int open_delay_time_dist[TIME_DIST_BUCKETS_SIZE]; +int open_delay_events = 0; + +#endif // ENABLE_TIME_TRACE + +// default will be read from config +int cache_migrate_on_demand = false; + +///////////////// +// Static Data // +///////////////// +static ClassAllocator cacheContAllocator("cacheContAllocator"); + +static Queue remoteCacheContQueue[REMOTE_CONNECT_HASH]; +static Ptr remoteCacheContQueueMutex[REMOTE_CONNECT_HASH]; + +// 0 is an illegal sequence number +#define CACHE_NO_RESPONSE 0 +static int cluster_sequence_number = 1; + +#ifdef CLUSTER_TEST_DEBUG +static ink_hrtime cache_cluster_timeout = HRTIME_SECONDS(65536); +#else +static ink_hrtime cache_cluster_timeout = CACHE_CLUSTER_TIMEOUT; +#endif + +/////////////////// +// Declarations // +/////////////////// +static CacheContinuation *find_cache_continuation(unsigned int, unsigned int); + +static unsigned int new_cache_sequence_number(); + +#define DOT_SEPARATED(_x) \ +((unsigned char*)&(_x))[0], ((unsigned char*)&(_x))[1], \ + ((unsigned char*)&(_x))[2], ((unsigned char*)&(_x))[3] + +#define ET_CACHE_CONT_SM ET_NET +#define ALLOW_THREAD_STEAL true + +/**********************************************************************/ +#ifdef CACHE_MSG_TRACE +/**********************************************************************/ + +/**********************************************************************/ +// Debug trace support for cache RPC messages +/**********************************************************************/ + +#define MAX_TENTRIES 4096 +struct traceEntry +{ + unsigned int seqno; + int op; + char *type; +}; +struct traceEntry recvTraceTable[MAX_TENTRIES]; +struct traceEntry sndTraceTable[MAX_TENTRIES]; + +static recvTraceTable_index = 0; +static sndTraceTable_index = 0; + +void +log_cache_op_msg(unsigned int seqno, int op, char *type) +{ + int t = ink_atomic_increment(&recvTraceTable_index, 1); + int n = recvTraceTable_index % MAX_TENTRIES; + recvTraceTable[n].seqno = seqno; + recvTraceTable[n].op = op; + recvTraceTable[n].type = type; +} + +void +log_cache_op_sndmsg(unsigned int seqno, int op, char *type) +{ + int t = ink_atomic_increment(&sndTraceTable_index, 1); + int n = sndTraceTable_index % MAX_TENTRIES; + sndTraceTable[n].seqno = seqno; + sndTraceTable[n].op = op; + sndTraceTable[n].type = type; +} + +void +dump_recvtrace_table() +{ + int n; + printf("\n"); + for (n = 0; n < MAX_TENTRIES; ++n) + printf("[%d] seqno=%d, op=%d type=%s\n", n, recvTraceTable[n].seqno, + recvTraceTable[n].op, recvTraceTable[n].type ? recvTraceTable[n].type : ""); +} + +void +dump_sndtrace_table() +{ + int n; + printf("\n"); + for (n = 0; n < MAX_TENTRIES; ++n) + printf("[%d] seqno=%d, op=%d type=%s\n", n, sndTraceTable[n].seqno, + sndTraceTable[n].op, sndTraceTable[n].type ? sndTraceTable[n].type : ""); +} + +/**********************************************************************/ +#endif // CACHE_MSG_TRACE +/**********************************************************************/ + +/////////////////////////////////////////////////////////////////////// +// Cluster write VC cache. +/////////////////////////////////////////////////////////////////////// +// +// In the event that a remote open read fails (HTTP only), an +// open write is issued and if successful a open write connection +// is returned for the open read. We cache the open write VC and +// resolve the subsequent open write locally from the write VC cache +// using the INK_MD5 of the URL. +// Note that this is a global per node cache. +/////////////////////////////////////////////////////////////////////// + +class ClusterVConnectionCache +{ +public: + ClusterVConnectionCache() + { + memset(hash_event, 0, sizeof(hash_event)); + } + void init(); + int MD5ToIndex(INK_MD5 * p); + int insert(INK_MD5 *, ClusterVConnection *); + ClusterVConnection *lookup(INK_MD5 *); + +public: + struct Entry + { + LINK(Entry, link); + bool mark_for_delete; + INK_MD5 key; + ClusterVConnection *vc; + + Entry():mark_for_delete(0), vc(0) + { + } + ~Entry() + { + } + }; + + enum + { MAX_TABLE_ENTRIES = 256, // must be power of 2 + SCAN_INTERVAL = 10 // seconds + }; + Queue hash_table[MAX_TABLE_ENTRIES]; + Ptr hash_lock[MAX_TABLE_ENTRIES]; + Event *hash_event[MAX_TABLE_ENTRIES]; +}; + +static ClassAllocator < + ClusterVConnectionCache::Entry > +ClusterVCCacheEntryAlloc("ClusterVConnectionCache::Entry"); + +ClusterVConnectionCache *GlobalOpenWriteVCcache = 0; + +///////////////////////////////////////////////////////////////// +// Perform periodic purges of ClusterVConnectionCache entries +///////////////////////////////////////////////////////////////// +class ClusterVConnectionCacheEvent:public Continuation +{ +public: + ClusterVConnectionCacheEvent(ClusterVConnectionCache * c, int n) + : Continuation(new_ProxyMutex()), cache(c), hash_index(n) + { + SET_HANDLER(&ClusterVConnectionCacheEvent::eventHandler); + } + int eventHandler(int, Event *); + +private: + ClusterVConnectionCache * cache; + int hash_index; +}; + +void +ClusterVConnectionCache::init() +{ + int n; + ClusterVConnectionCacheEvent *eh; + + for (n = 0; n < MAX_TABLE_ENTRIES; ++n) { + hash_lock[n] = new_ProxyMutex(); + } + for (n = 0; n < MAX_TABLE_ENTRIES; ++n) { + // Setup up periodic purge events on each hash list + + eh = new ClusterVConnectionCacheEvent(this, n); + hash_event[n] = + eventProcessor.schedule_in(eh, HRTIME_SECONDS(ClusterVConnectionCache::SCAN_INTERVAL), ET_CACHE_CONT_SM); + } +} +inline int +ClusterVConnectionCache::MD5ToIndex(INK_MD5 * p) +{ + uint64_t i = p->fold(); + int32_t h, l; + + h = i >> 32; + l = i & 0xFFFFFFFF; + return ((h ^ l) % MAX_TABLE_ENTRIES) & (MAX_TABLE_ENTRIES - 1); +} + +int +ClusterVConnectionCache::insert(INK_MD5 * key, ClusterVConnection * vc) +{ + int index = MD5ToIndex(key); + Entry *e; + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + MUTEX_TRY_LOCK(lock, hash_lock[index], thread); + if (!lock) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_INSERT_LOCK_MISSES_STAT); + return 0; // lock miss, retry later + + } else { + // Add entry to list + + e = ClusterVCCacheEntryAlloc.alloc(); + e->key = *key; + e->vc = vc; + hash_table[index].enqueue(e); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_INSERTS_STAT); + } + return 1; // Success +} + +ClusterVConnection * +ClusterVConnectionCache::lookup(INK_MD5 * key) +{ + int index = MD5ToIndex(key); + Entry *e; + ClusterVConnection *vc = 0; + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + MUTEX_TRY_LOCK(lock, hash_lock[index], thread); + if (!lock) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_LOOKUP_LOCK_MISSES_STAT); + return vc; // lock miss, retry later + + } else { + e = hash_table[index].head; + while (e) { + if (*key == e->key) { // Hit + vc = e->vc; + hash_table[index].remove(e); + ClusterVCCacheEntryAlloc.free(e); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_LOOKUP_HITS_STAT); + return vc; + + } else { + e = e->link.next; + } + } + } + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_LOOKUP_MISSES_STAT); + return (ClusterVConnection *) - 1; // Miss +} + +int +ClusterVConnectionCacheEvent::eventHandler(int event, Event * e) +{ + NOWARN_UNUSED(event); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_SCANS_STAT); + MUTEX_TRY_LOCK(lock, cache->hash_lock[hash_index], this_ethread()); + if (!lock) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_SCAN_LOCK_MISSES_STAT); + e->schedule_in(HRTIME_MSECONDS(10)); + return EVENT_DONE; + } + // Perform purge action on unreferenced VC(s). + + ClusterVConnectionCache::Entry * entry; + ClusterVConnectionCache::Entry * next_entry; + entry = cache->hash_table[hash_index].head; + + while (entry) { + if (entry->mark_for_delete) { + next_entry = entry->link.next; + + cache->hash_table[hash_index].remove(entry); + entry->vc->allow_remote_close(); + entry->vc->do_io(VIO::CLOSE); + + ClusterVCCacheEntryAlloc.free(entry); + entry = next_entry; + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_CACHE_PURGES_STAT); + + } else { + entry->mark_for_delete = true; + entry = entry->link.next; + } + } + + // Setup for next purge event + + e->schedule_in(HRTIME_SECONDS(ClusterVConnectionCache::SCAN_INTERVAL), ET_CACHE_CONT_SM); + return EVENT_DONE; +} + +/////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////// +// init() +// Global initializations for CacheContinuation +//////////////////////////////////////////////////// +int +CacheContinuation::init() +{ + int n; + for (n = 0; n < REMOTE_CONNECT_HASH; ++n) + remoteCacheContQueueMutex[n] = new_ProxyMutex(); + + GlobalOpenWriteVCcache = new ClusterVConnectionCache; + GlobalOpenWriteVCcache->init(); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +// do_op() +// Main function to do a cluster cache operation +/////////////////////////////////////////////////////////////////////// +Action * +CacheContinuation::do_op(Continuation * c, ClusterMachine * mp, void *args, + int user_opcode, char *data, int data_len, int nbytes, MIOBuffer * b) +{ + CacheContinuation *cc = 0; + Action *act = 0; + char *msg = 0; + + ///////////////////////////////////////////////////////////////////// + // Unconditionally map open read buffer interfaces to open read. + // open read buffer interfaces are now deprecated. + ///////////////////////////////////////////////////////////////////// + int opcode = user_opcode; + switch (opcode) { + case CACHE_OPEN_READ_BUFFER: + opcode = CACHE_OPEN_READ; + break; + case CACHE_OPEN_READ_BUFFER_LONG: + opcode = CACHE_OPEN_READ_LONG; + break; + default: + break; + } + + if (c) { + cc = cacheContAllocator_alloc(); + cc->target_machine = mp; + cc->request_opcode = opcode; + cc->mutex = c->mutex; + cc->action = c; + cc->action.cancelled = false; + cc->start_time = ink_get_hrtime(); + cc->from = mp; + cc->result = op_failure(opcode); + SET_CONTINUATION_HANDLER(cc, (CacheContHandler) + & CacheContinuation::remoteOpEvent); + act = &cc->action; + + // set up sequence number so we can find this continuation + + cc->target_ip = mp->ip; + cc->seq_number = new_cache_sequence_number(); + + // establish timeout for cache op + + unsigned int hash = FOLDHASH(cc->target_ip, cc->seq_number); + MUTEX_TRY_LOCK(queuelock, remoteCacheContQueueMutex[hash], this_ethread()); + if (!queuelock) { + + // failed to acquire lock: no problem, retry later + cc->timeout = eventProcessor.schedule_in(cc, CACHE_RETRY_PERIOD, ET_CACHE_CONT_SM); + } else { + remoteCacheContQueue[hash].enqueue(cc); + MUTEX_RELEASE(queuelock); + cc->timeout = eventProcessor.schedule_in(cc, cache_cluster_timeout, ET_CACHE_CONT_SM); + } + } + // + // Determine the type of the "Over The Wire" (OTW) message header and + // initialize it. + // +#ifdef PURIFY + if (data) + memset(data, 0, op_to_sizeof_fixedlen_msg(opcode)); +#endif + Debug("cache_msg", + "do_op opcode=%d seqno=%d Machine=0x%x data=0x%x datalen=%d mio=0x%x", + opcode, (c ? cc->seq_number : CACHE_NO_RESPONSE), mp, data, data_len, b); + + switch (opcode) { + case CACHE_OPEN_WRITE_BUFFER: + case CACHE_OPEN_WRITE_BUFFER_LONG: + { + ink_release_assert(!"write buffer not supported"); + break; + } + case CACHE_OPEN_READ_BUFFER: + case CACHE_OPEN_READ_BUFFER_LONG: + { + ink_release_assert(!"read buffer not supported"); + break; + } + case CACHE_OPEN_WRITE: + case CACHE_OPEN_READ: + { + ink_release_assert(c > 0); + ////////////////////// + // Use short format // + ////////////////////// + if (!data) { + data_len = op_to_sizeof_fixedlen_msg(opcode); + data = (char *) ALLOCA_DOUBLE(data_len); +#ifdef PURIFY + memset(data, 0, data_len); +#endif + } + msg = (char *) data; + CacheOpMsg_short *m = (CacheOpMsg_short *) msg; + m->init(); + m->opcode = opcode; + m->cfl_flags = ((CacheOpArgs_General *) args)->cfl_flags; + m->md5 = *((CacheOpArgs_General *) args)->url_md5; + cc->url_md5 = m->md5; + m->seq_number = (c ? cc->seq_number : CACHE_NO_RESPONSE); + m->frag_type = ((CacheOpArgs_General *) args)->frag_type; + if (opcode == CACHE_OPEN_WRITE) { + m->nbytes = nbytes; + m->data = (uint32_t) ((CacheOpArgs_General *) args)->pin_in_cache; + } else { + m->nbytes = 0; + m->data = 0; + } + + if (opcode == CACHE_OPEN_READ) { + // + // Set upper limit on initial data received with response + // for open read response + // + m->buffer_size = DEFAULT_MAX_BUFFER_SIZE; + } else { + m->buffer_size = 0; + } + + // + // Establish the local VC + // + int res = setup_local_vc(msg, data_len, cc, mp, &act); + if (!res) { + ///////////////////////////////////////////////////// + // Unable to setup local VC, request aborted. + // Remove request from pending list and deallocate. + ///////////////////////////////////////////////////// + cc->remove_and_delete(0, (Event *) 0); + return act; + + } else if (res != -1) { + /////////////////////////////////////// + // VC established, send request + /////////////////////////////////////// + break; + + } else { + ////////////////////////////////////////////////////// + // Unable to setup VC, delay required, await callback + ////////////////////////////////////////////////////// + goto no_send_exit; + } + } + + case CACHE_OPEN_READ_LONG: + case CACHE_OPEN_WRITE_LONG: + { + ink_release_assert(c > 0); + ////////////////////// + // Use long format // + ////////////////////// + msg = data; + CacheOpMsg_long *m = (CacheOpMsg_long *) msg; + m->init(); + m->opcode = opcode; + m->cfl_flags = ((CacheOpArgs_General *) args)->cfl_flags; + m->url_md5 = *((CacheOpArgs_General *) args)->url_md5; + cc->url_md5 = m->url_md5; + m->seq_number = (c ? cc->seq_number : CACHE_NO_RESPONSE); + m->nbytes = nbytes; + m->data = (uint32_t) ((CacheOpArgs_General *) args)->pin_in_cache; + m->frag_type = (uint32_t) ((CacheOpArgs_General *) args)->frag_type; + + if (opcode == CACHE_OPEN_READ_LONG) { + // + // Set upper limit on initial data received with response + // for open read response + // + m->buffer_size = DEFAULT_MAX_BUFFER_SIZE; + } else { + m->buffer_size = 0; + } + // + // Establish the local VC + // + int res = setup_local_vc(msg, data_len, cc, mp, &act); + if (!res) { + ///////////////////////////////////////////////////// + // Unable to setup local VC, request aborted. + // Remove request from pending list and deallocate. + ///////////////////////////////////////////////////// + cc->remove_and_delete(0, (Event *) 0); + return act; + + } else if (res != -1) { + /////////////////////////////////////// + // VC established, send request + /////////////////////////////////////// + break; + + } else { + ////////////////////////////////////////////////////// + // Unable to setup VC, delay required, await callback + ////////////////////////////////////////////////////// + goto no_send_exit; + } + } + case CACHE_UPDATE: + case CACHE_REMOVE: + case CACHE_DEREF: + { + ////////////////////// + // Use short format // + ////////////////////// + msg = data; + CacheOpMsg_short *m = (CacheOpMsg_short *) msg; + m->init(); + m->opcode = opcode; + m->frag_type = ((CacheOpArgs_Deref *) args)->frag_type; + m->cfl_flags = ((CacheOpArgs_Deref *) args)->cfl_flags; + if (opcode == CACHE_DEREF) + m->md5 = *((CacheOpArgs_Deref *) args)->md5; + else + m->md5 = *((CacheOpArgs_General *) args)->url_md5; + m->seq_number = (c ? cc->seq_number : CACHE_NO_RESPONSE); + break; + } + case CACHE_LINK: + { + //////////////////////// + // Use short_2 format // + //////////////////////// + msg = data; + CacheOpMsg_short_2 *m = (CacheOpMsg_short_2 *) msg; + m->init(); + m->opcode = opcode; + m->cfl_flags = ((CacheOpArgs_Link *) args)->cfl_flags; + m->md5_1 = *((CacheOpArgs_Link *) args)->from; + m->md5_2 = *((CacheOpArgs_Link *) args)->to; + m->seq_number = (c ? cc->seq_number : CACHE_NO_RESPONSE); + m->frag_type = ((CacheOpArgs_Link *) args)->frag_type; + break; + } + default: + msg = 0; + break; + } +#ifdef CACHE_MSG_TRACE + log_cache_op_sndmsg((c ? cc->seq_number : CACHE_NO_RESPONSE), 0, "do_op"); +#endif + clusterProcessor.invoke_remote(mp, + op_needs_marshalled_coi(opcode) ? CACHE_OP_MALLOCED_CLUSTER_FUNCTION + : CACHE_OP_CLUSTER_FUNCTION, (char *) msg, data_len); + +no_send_exit: + if (c) { + return act; + } else { + return (Action *) 0; + } +} + +int +CacheContinuation::setup_local_vc(char *data, int data_len, CacheContinuation * cc, ClusterMachine * mp, Action ** act) +{ + bool read_op = op_is_read(cc->request_opcode); + bool short_msg = op_is_shortform(cc->request_opcode); + + // Alloc buffer, copy message and attach to continuation + cc->setMsgBufferLen(data_len); + cc->allocMsgBuffer(); + memcpy(cc->getMsgBuffer(), data, data_len); + + SET_CONTINUATION_HANDLER(cc, (CacheContHandler) + & CacheContinuation::localVCsetupEvent); + + if (short_msg) { + Debug("cache_proto", "open_local-s (%s) seqno=%d", (read_op ? "R" : "W"), ((CacheOpMsg_short *) data)->seq_number); + } else { + Debug("cache_proto", "open_local-l (%s) seqno=%d", (read_op ? "R" : "W"), ((CacheOpMsg_long *) data)->seq_number); + } + + // Create local VC + ClusterVConnection *vc; + + if (!read_op && (cc->request_opcode == CACHE_OPEN_WRITE_LONG)) { + // Determine if the open_write has already been established. + vc = cc->lookupOpenWriteVC(); + + } else { + vc = clusterProcessor.open_local(cc, mp, cc->open_local_token, + (CLUSTER_OPT_ALLOW_IMMEDIATE | + (read_op ? CLUSTER_OPT_CONN_READ : CLUSTER_OPT_CONN_WRITE))); + } + if (!vc) { + // Error, abort request + if (short_msg) { + Debug("cache_proto", "0open_local-s (%s) failed, seqno=%d", + (read_op ? "R" : "W"), ((CacheOpMsg_short *) data)->seq_number); + } else { + Debug("cache_proto", "1open_local-l (%s) failed, seqno=%d", + (read_op ? "R" : "W"), ((CacheOpMsg_long *) data)->seq_number); + } + cc->freeMsgBuffer(); + if (cc->timeout) + cc->timeout->cancel(); + cc->timeout = NULL; + + // Post async failure callback on a different continuation. + *act = callback_failure(&cc->action, (read_op ? CACHE_EVENT_OPEN_READ_FAILED : CACHE_EVENT_OPEN_WRITE_FAILED), 0); + return 0; + + } else if (vc != CLUSTER_DELAYED_OPEN) { + // We have established the VC + if (read_op) { + cc->read_cluster_vc = vc; + } else { + cc->write_cluster_vc = vc; + } + cc->cluster_vc_channel = vc->channel; + vc->current_cont = cc; + + if (short_msg) { + CacheOpMsg_short *ms = (CacheOpMsg_short *) data; + ms->channel = vc->channel; + ms->token = cc->open_local_token; + Debug("cache_proto", + "0open_local-s (%s) success, seqno=%d chan=%d token=%d,%d VC=0x%x", + (read_op ? "R" : "W"), ms->seq_number, vc->channel, ms->token.ip_created, ms->token.sequence_number, vc); + } else { + CacheOpMsg_long *ml = (CacheOpMsg_long *) data; + ml->channel = vc->channel; + ml->token = cc->open_local_token; + Debug("cache_proto", + "1open_local-l (%s) success, seqno=%d chan=%d token=%d,%d VC=0x%x", + (read_op ? "R" : "W"), ml->seq_number, vc->channel, ml->token.ip_created, ml->token.sequence_number, vc); + } + cc->freeMsgBuffer(); + SET_CONTINUATION_HANDLER(cc, (CacheContHandler) + & CacheContinuation::remoteOpEvent); + return 1; + + } else { + ////////////////////////////////////////////////////// + // Unable to setup VC, delay required, await callback + ////////////////////////////////////////////////////// + return -1; + } +} + +ClusterVConnection * +CacheContinuation::lookupOpenWriteVC() +{ + /////////////////////////////////////////////////////////////// + // See if we already have an open_write ClusterVConnection + // which was established in a previous remote open_read which + // failed. + /////////////////////////////////////////////////////////////// + ClusterVConnection *vc; + CacheOpMsg_long *ml = (CacheOpMsg_long *) getMsgBuffer(); + + vc = GlobalOpenWriteVCcache->lookup(&ml->url_md5); + + if (vc == ((ClusterVConnection *) 0)) { + // Retry lookup + SET_CONTINUATION_HANDLER(this, (CacheContHandler) + & CacheContinuation::lookupOpenWriteVCEvent); + // + // Note: In the lookupOpenWriteVCEvent handler, we use EVENT_IMMEDIATE + // to distinguish the lookup retry from a request timeout + // which uses EVENT_INTERVAL. + // + lookup_open_write_vc_event = eventProcessor.schedule_imm(this, ET_CACHE_CONT_SM); + + } else if (vc != ((ClusterVConnection *) - 1)) { + // Hit, found open_write VC in cache. + // Post open_write completion by simulating a + // remote cache op result message. + + vc->action_ = action; // establish new continuation + + SET_CONTINUATION_HANDLER(this, (CacheContHandler) + & CacheContinuation::localVCsetupEvent); + this->handleEvent(CLUSTER_EVENT_OPEN_EXISTS, vc); + + CacheOpReplyMsg msg; + int msglen; + + msglen = CacheOpReplyMsg::sizeof_fixedlen_msg(); + msg.result = CACHE_EVENT_OPEN_WRITE; + msg.seq_number = seq_number; + msg.token = vc->token; + + cache_op_result_ClusterFunction(from, (void *) &msg, msglen); + + } else { + // Miss, establish local VC and send remote open_write request + + SET_CONTINUATION_HANDLER(this, (CacheContHandler) + & CacheContinuation::localVCsetupEvent); + vc = clusterProcessor.open_local(this, from, open_local_token, + (CLUSTER_OPT_ALLOW_IMMEDIATE | CLUSTER_OPT_CONN_WRITE)); + if (!vc) { + this->handleEvent(CLUSTER_EVENT_OPEN_FAILED, 0); + + } else if (vc != CLUSTER_DELAYED_OPEN) { + this->handleEvent(CLUSTER_EVENT_OPEN, vc); + } + } + return CLUSTER_DELAYED_OPEN; // force completion in callback +} + +int +CacheContinuation::lookupOpenWriteVCEvent(int event, Event * e) +{ + if (event == EVENT_IMMEDIATE) { + // Retry open_write VC lookup + lookupOpenWriteVC(); + + } else { + lookup_open_write_vc_event->cancel(); + SET_CONTINUATION_HANDLER(this, (CacheContHandler) + & CacheContinuation::localVCsetupEvent); + this->handleEvent(event, e); + } + return EVENT_DONE; +} + +int +CacheContinuation::remove_and_delete(int event, Event * e) +{ + NOWARN_UNUSED(event); + unsigned int hash = FOLDHASH(target_ip, seq_number); + MUTEX_TRY_LOCK(queuelock, remoteCacheContQueueMutex[hash], this_ethread()); + if (queuelock) { + if (remoteCacheContQueue[hash].in(this)) { + remoteCacheContQueue[hash].remove(this); + } + MUTEX_RELEASE(queuelock); + if (use_deferred_callback) + callback_failure(&action, result, result_error, this); + else + cacheContAllocator_free(this); + + } else { + SET_HANDLER((CacheContHandler) & CacheContinuation::remove_and_delete); + if (!e) { + timeout = eventProcessor.schedule_in(this, cache_cluster_timeout, ET_CACHE_CONT_SM); + } else { + e->schedule_in(cache_cluster_timeout); + } + } + return EVENT_DONE; +} + +int +CacheContinuation::localVCsetupEvent(int event, ClusterVConnection * vc) +{ + ink_assert(magicno == (int) MagicNo); + ink_assert(getMsgBuffer()); + bool short_msg = op_is_shortform(request_opcode); + bool read_op = op_is_read(request_opcode); + + if (event == EVENT_INTERVAL) { + Event *e = (Event *) vc; + unsigned int hash = FOLDHASH(target_ip, seq_number); + + MUTEX_TRY_LOCK(queuelock, remoteCacheContQueueMutex[hash], e->ethread); + if (!queuelock) { + e->schedule_in(CACHE_RETRY_PERIOD); + return EVENT_CONT; + } + + if (!remoteCacheContQueue[hash].in(this)) { + //////////////////////////////////////////////////// + // Not yet queued on outstanding operations list + //////////////////////////////////////////////////// + remoteCacheContQueue[hash].enqueue(this); + ink_assert(timeout == e); + MUTEX_RELEASE(queuelock); + e->schedule_in(cache_cluster_timeout); + return EVENT_CONT; + + } else { + ///////////////////////////////////////////////////// + // Timeout occurred + ///////////////////////////////////////////////////// + remoteCacheContQueue[hash].remove(this); + MUTEX_RELEASE(queuelock); + Debug("cluster_timeout", "0cluster op timeout %d", seq_number); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_REMOTE_OP_TIMEOUTS_STAT); + timeout = (Event *) 1; // Note timeout + ///////////////////////////////////////////////////////////////// + // Note: Failure callback is sent now, but the deallocation of + // the CacheContinuation is deferred until we receive the + // open_local() callback. + ///////////////////////////////////////////////////////////////// + if (!action.cancelled) + action.continuation->handleEvent((read_op ? CACHE_EVENT_OPEN_READ_FAILED : CACHE_EVENT_OPEN_WRITE_FAILED), 0); + return EVENT_DONE; + } + + } else if (((event == CLUSTER_EVENT_OPEN) || (event == CLUSTER_EVENT_OPEN_EXISTS)) + && (((ptrdiff_t) timeout & (ptrdiff_t) 1) == 0)) { + ink_hrtime now; + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_OPEN_DELAY_TIME_STAT, now - start_time); + LOG_EVENT_TIME(start_time, open_delay_time_dist, open_delay_events); + if (read_op) { + read_cluster_vc = vc; + } else { + write_cluster_vc = vc; + } + cluster_vc_channel = vc->channel; + vc->current_cont = this; + + if (short_msg) { + CacheOpMsg_short *ms = (CacheOpMsg_short *) getMsgBuffer(); + ms->channel = vc->channel; + ms->token = open_local_token; + + Debug("cache_proto", + "2open_local-s (%s) success, seqno=%d chan=%d token=%d,%d VC=0x%x", + (read_op ? "R" : "W"), ms->seq_number, vc->channel, ms->token.ip_created, ms->token.sequence_number, vc); + + } else { + CacheOpMsg_long *ml = (CacheOpMsg_long *) getMsgBuffer(); + ml->channel = vc->channel; + ml->token = open_local_token; + + Debug("cache_proto", + "3open_local-l (%s) success, seqno=%d chan=%d token=%d,%d VC=0x%x", + (read_op ? "R" : "W"), ml->seq_number, vc->channel, ml->token.ip_created, ml->token.sequence_number, vc); + } + SET_HANDLER((CacheContHandler) & CacheContinuation::remoteOpEvent); + + if (event != CLUSTER_EVENT_OPEN_EXISTS) { + // Send request message + clusterProcessor.invoke_remote(from, + (op_needs_marshalled_coi(request_opcode) ? + CACHE_OP_MALLOCED_CLUSTER_FUNCTION : + CACHE_OP_CLUSTER_FUNCTION), (char *) getMsgBuffer(), getMsgBufferLen()); + } + + } else { + int send_failure_callback = 1; + + if (((ptrdiff_t) timeout & (ptrdiff_t) 1) == 0) { + if (short_msg) { + Debug("cache_proto", "2open_local-s (%s) failed, seqno=%d", + (read_op ? "R" : "W"), ((CacheOpMsg_short *) getMsgBuffer())->seq_number); + } else { + Debug("cache_proto", "3open_local-l (%s) failed, seqno=%d", + (read_op ? "R" : "W"), ((CacheOpMsg_long *) getMsgBuffer())->seq_number); + } + + } else { + Debug("cache_proto", "4open_local cancelled due to timeout, seqno=%d", seq_number); + this->timeout = 0; + + // Deallocate VC if successfully acquired + + if (event == CLUSTER_EVENT_OPEN) { + vc->pending_remote_fill = 0; + vc->remote_closed = 1; // avoid remote close msg + vc->do_io(VIO::CLOSE); + } + send_failure_callback = 0; // already sent. + } + + if (this->timeout) + this->timeout->cancel(); + this->timeout = NULL; + + freeMsgBuffer(); + if (send_failure_callback) { + // + // Action corresponding to "this" already sent back to user, + // use "this" to establish the failure callback after + // removing ourselves from the active list. + // + this->use_deferred_callback = true; + this->result = (read_op ? CACHE_EVENT_OPEN_READ_FAILED : CACHE_EVENT_OPEN_WRITE_FAILED); + this->result_error = 0; + remove_and_delete(0, (Event *) 0); + + } else { + cacheContAllocator_free(this); + } + return EVENT_DONE; + } + // Free message + freeMsgBuffer(); + + return EVENT_DONE; +} + +/////////////////////////////////////////////////////////////////////////// +// cache_op_ClusterFunction() +// On the receiving side, handle a general cluster cache operation +/////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// Marshaling functions for OTW message headers +//////////////////////////////////////////////////////////////////////// + +inline CacheOpMsg_long * +unmarshal_CacheOpMsg_long(void *data, int NeedByteSwap) +{ + if (NeedByteSwap) + ((CacheOpMsg_long *) data)->SwapBytes(); + return (CacheOpMsg_long *) data; +} + +inline CacheOpMsg_short * +unmarshal_CacheOpMsg_short(void *data, int NeedByteSwap) +{ + if (NeedByteSwap) + ((CacheOpMsg_short *) data)->SwapBytes(); + return (CacheOpMsg_short *) data; +} + +inline CacheOpMsg_short_2 * +unmarshal_CacheOpMsg_short_2(void *data, int NeedByteSwap) +{ + if (NeedByteSwap) + ((CacheOpMsg_short_2 *) data)->SwapBytes(); + return (CacheOpMsg_short_2 *) data; +} + +// init_from_long() support routine for cache_op_ClusterFunction() +inline void +init_from_long(CacheContinuation * cont, CacheOpMsg_long * msg, ClusterMachine * m) +{ + cont->no_reply_message = (msg->seq_number == CACHE_NO_RESPONSE); + cont->seq_number = msg->seq_number; + cont->cfl_flags = msg->cfl_flags; + cont->from = m; + cont->url_md5 = msg->url_md5; + cont->cluster_vc_channel = msg->channel; + cont->frag_type = (CacheFragType) msg->frag_type; + if ((cont->request_opcode == CACHE_OPEN_WRITE_LONG) + || (cont->request_opcode == CACHE_OPEN_READ_LONG)) { + cont->pin_in_cache = (time_t) msg->data; + } else { + cont->pin_in_cache = 0; + } + cont->token = msg->token; + cont->nbytes = (((int) msg->nbytes < 0) ? 0 : msg->nbytes); + + if (cont->request_opcode == CACHE_OPEN_READ_LONG) { + cont->caller_buf_freebytes = msg->buffer_size; + } else { + cont->caller_buf_freebytes = 0; + } +} + +// init_from_short() support routine for cache_op_ClusterFunction() +inline void +init_from_short(CacheContinuation * cont, CacheOpMsg_short * msg, ClusterMachine * m) +{ + cont->no_reply_message = (msg->seq_number == CACHE_NO_RESPONSE); + cont->seq_number = msg->seq_number; + cont->cfl_flags = msg->cfl_flags; + cont->from = m; + cont->url_md5 = msg->md5; + cont->cluster_vc_channel = msg->channel; + cont->token = msg->token; + cont->nbytes = (((int) msg->nbytes < 0) ? 0 : msg->nbytes); + cont->frag_type = (CacheFragType) msg->frag_type; + + if (cont->request_opcode == CACHE_OPEN_WRITE) { + cont->pin_in_cache = (time_t) msg->data; + } else { + cont->pin_in_cache = 0; + } + + if (cont->request_opcode == CACHE_OPEN_READ) { + cont->caller_buf_freebytes = msg->buffer_size; + } else { + cont->caller_buf_freebytes = 0; + } +} + +// init_from_short_2() support routine for cache_op_ClusterFunction() +inline void +init_from_short_2(CacheContinuation * cont, CacheOpMsg_short_2 * msg, ClusterMachine * m) +{ + cont->no_reply_message = (msg->seq_number == CACHE_NO_RESPONSE); + cont->seq_number = msg->seq_number; + cont->cfl_flags = msg->cfl_flags; + cont->from = m; + cont->url_md5 = msg->md5_1; + cont->frag_type = (CacheFragType) msg->frag_type; +} + +void +cache_op_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + //////////////////////////////////////////////////////// + // Note: we are running on the ET_CLUSTER thread + //////////////////////////////////////////////////////// + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CACHE_OUTSTANDING_STAT); + + int opcode; + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + + if (mh->GetMsgVersion() != CacheOpMsg_long::CACHE_OP_LONG_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"cache_op_ClusterFunction() bad msg version"); + } + opcode = ((CacheOpMsg_long *) data)->opcode; + + // If necessary, create a continuation to reflect the response back + + CacheContinuation *c = CacheContinuation::cacheContAllocator_alloc(); + c->mutex = new_ProxyMutex(); + MUTEX_TRY_LOCK(lock, c->mutex, this_ethread()); + c->request_opcode = opcode; + c->token.clear(); + c->start_time = ink_get_hrtime(); + SET_CONTINUATION_HANDLER(c, (CacheContHandler) + & CacheContinuation::replyOpEvent); + + switch (opcode) { + case CACHE_OPEN_WRITE_BUFFER: + case CACHE_OPEN_WRITE_BUFFER_LONG: + ink_release_assert(!"cache_op_ClusterFunction WRITE_BUFFER not supported"); + break; + + case CACHE_OPEN_READ_BUFFER: + case CACHE_OPEN_READ_BUFFER_LONG: + ink_release_assert(!"cache_op_ClusterFunction READ_BUFFER not supported"); + break; + + case CACHE_OPEN_READ: + { + CacheOpMsg_short *msg = unmarshal_CacheOpMsg_short(data, mh->NeedByteSwap()); + init_from_short(c, msg, from); + Debug("cache_msg", + "cache_op-s op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); + // + // Establish the remote side of the ClusterVConnection + // + c->write_cluster_vc = clusterProcessor.connect_local((Continuation *) 0, + &c->token, + c->cluster_vc_channel, + (CLUSTER_OPT_IMMEDIATE | CLUSTER_OPT_CONN_READ)); + if (!c->write_cluster_vc) { + // Unable to setup channel, abort processing. + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CHAN_INUSE_STAT); + Debug("chan_inuse", + "1Remote chan=%d inuse tok.ip=%u.%u.%u.%u tok.seqno=%d seqno=%d", + c->cluster_vc_channel, DOT_SEPARATED(c->token.ip_created), c->token.sequence_number, c->seq_number); + + // Send cluster op failed reply + c->replyOpEvent(CACHE_EVENT_OPEN_READ_FAILED, (VConnection *) - ECLUSTER_CHANNEL_INUSE); + break; + + } else { + c->write_cluster_vc->current_cont = c; + } + ink_release_assert(c->write_cluster_vc != CLUSTER_DELAYED_OPEN); + ink_release_assert((opcode == CACHE_OPEN_READ) + || c->write_cluster_vc->pending_remote_fill); + + SET_CONTINUATION_HANDLER(c, (CacheContHandler) + & CacheContinuation::setupVCdataRead); + Debug("cache_proto", + "0read op, seqno=%d chan=%d bufsize=%d token=%d,%d", + msg->seq_number, msg->channel, msg->buffer_size, msg->token.ip_created, msg->token.sequence_number); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_open_read"); +#endif + CacheKey key(msg->md5); + + char *hostname = NULL; + int host_len = len - op_to_sizeof_fixedlen_msg(opcode); + if (host_len) { + hostname = (char *) msg->moi; + } + Cache *call_cache = caches[c->frag_type]; + c->cache_action = call_cache->open_read(c, &key, c->frag_type, hostname, host_len); + break; + } + case CACHE_OPEN_READ_LONG: + { + // Cache needs message data, copy it. + c->setMsgBufferLen(len); + c->allocMsgBuffer(); + memcpy(c->getMsgBuffer(), (char *) data, len); + + int flen = CacheOpMsg_long::sizeof_fixedlen_msg(); + CacheOpMsg_long *msg = unmarshal_CacheOpMsg_long(c->getMsgBuffer(), mh->NeedByteSwap()); + init_from_long(c, msg, from); + Debug("cache_msg", + "cache_op-l op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_open_read_long"); +#endif + // + // Establish the remote side of the ClusterVConnection + // + c->write_cluster_vc = clusterProcessor.connect_local((Continuation *) 0, + &c->token, + c->cluster_vc_channel, + (CLUSTER_OPT_IMMEDIATE | CLUSTER_OPT_CONN_READ)); + if (!c->write_cluster_vc) { + // Unable to setup channel, abort processing. + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CHAN_INUSE_STAT); + Debug("chan_inuse", + "2Remote chan=%d inuse tok.ip=%u.%u.%u.%u tok.seqno=%d seqno=%d", + c->cluster_vc_channel, DOT_SEPARATED(c->token.ip_created), c->token.sequence_number, c->seq_number); + + // Send cluster op failed reply + c->replyOpEvent(CACHE_EVENT_OPEN_READ_FAILED, (VConnection *) - ECLUSTER_CHANNEL_INUSE); + break; + + } else { + c->write_cluster_vc->current_cont = c; + } + ink_release_assert(c->write_cluster_vc != CLUSTER_DELAYED_OPEN); + ink_release_assert((opcode == CACHE_OPEN_READ_LONG) + || c->write_cluster_vc->pending_remote_fill); + + SET_CONTINUATION_HANDLER(c, (CacheContHandler) + & CacheContinuation::setupReadWriteVC); + Debug("cache_proto", + "1read op, seqno=%d chan=%d bufsize=%d token=%d,%d", + msg->seq_number, msg->channel, msg->buffer_size, msg->token.ip_created, msg->token.sequence_number); + + const char *p = (const char *) msg + flen; + int moi_len = len - flen; + int res; + + ink_assert(moi_len > 0); + + // Unmarshal CacheHTTPHdr + res = c->ic_request.unmarshal((char *) p, moi_len, NULL); + ink_assert(res > 0); + ink_assert(c->ic_request.valid()); + moi_len -= res; + p += res; + ink_assert(moi_len > 0); + // Unmarshal CacheLookupHttpConfig + c->ic_params = new(CacheLookupHttpConfigAllocator.alloc()) + CacheLookupHttpConfig(); + res = c->ic_params->unmarshal(&c->ic_arena, (const char *) p, moi_len); + ink_assert(res > 0); + + moi_len -= res; + p += res; + + CacheKey key(msg->url_md5); + + char *hostname = NULL; + int host_len = 0; + + if (moi_len) { + hostname = (char *) p; + host_len = moi_len; + + // Save hostname and attach it to the continuation since we may + // need it if we convert this to an open_write. + + c->ic_hostname = new_IOBufferData(iobuffer_size_to_index(host_len)); + c->ic_hostname_len = host_len; + + memcpy(c->ic_hostname->data(), hostname, host_len); + } + + Cache *call_cache = caches[c->frag_type]; + Action *a = call_cache->open_read(c, &key, &c->ic_request, + c->ic_params, + c->frag_type, hostname, host_len); + // Get rid of purify warnings since 'c' can be freed by open_read. + if (a != ACTION_RESULT_DONE) { + c->cache_action = a; + } + break; + } + case CACHE_OPEN_WRITE: + { + CacheOpMsg_short *msg = unmarshal_CacheOpMsg_short(data, mh->NeedByteSwap()); + init_from_short(c, msg, from); + Debug("cache_msg", + "cache_op-s op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_open_write"); +#endif + // + // Establish the remote side of the ClusterVConnection + // + c->read_cluster_vc = clusterProcessor.connect_local((Continuation *) 0, + &c->token, + c->cluster_vc_channel, + (CLUSTER_OPT_IMMEDIATE | CLUSTER_OPT_CONN_WRITE)); + if (!c->read_cluster_vc) { + // Unable to setup channel, abort processing. + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CHAN_INUSE_STAT); + Debug("chan_inuse", + "3Remote chan=%d inuse tok.ip=%u.%u.%u.%u tok.seqno=%d seqno=%d", + c->cluster_vc_channel, DOT_SEPARATED(c->token.ip_created), c->token.sequence_number, c->seq_number); + + // Send cluster op failed reply + c->replyOpEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (VConnection *) - ECLUSTER_CHANNEL_INUSE); + break; + + } else { + c->read_cluster_vc->current_cont = c; + } + ink_release_assert(c->read_cluster_vc != CLUSTER_DELAYED_OPEN); + + CacheKey key(msg->md5); + + char *hostname = NULL; + int host_len = len - op_to_sizeof_fixedlen_msg(opcode); + if (host_len) { + hostname = (char *) msg->moi; + } + + Cache *call_cache = caches[c->frag_type]; + Action *a = call_cache->open_write(c, &key, c->frag_type, + !!(c->cfl_flags & CFL_OVERWRITE_ON_WRITE), + c->pin_in_cache, hostname, host_len); + if (a != ACTION_RESULT_DONE) { + c->cache_action = a; + } + break; + } + case CACHE_OPEN_WRITE_LONG: + { + // Cache needs message data, copy it. + c->setMsgBufferLen(len); + c->allocMsgBuffer(); + memcpy(c->getMsgBuffer(), (char *) data, len); + + int flen = CacheOpMsg_long::sizeof_fixedlen_msg(); + CacheOpMsg_long *msg = unmarshal_CacheOpMsg_long(c->getMsgBuffer(), mh->NeedByteSwap()); + init_from_long(c, msg, from); + Debug("cache_msg", + "cache_op-l op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_open_write_long"); +#endif + // + // Establish the remote side of the ClusterVConnection + // + c->read_cluster_vc = clusterProcessor.connect_local((Continuation *) 0, + &c->token, + c->cluster_vc_channel, + (CLUSTER_OPT_IMMEDIATE | CLUSTER_OPT_CONN_WRITE)); + if (!c->read_cluster_vc) { + // Unable to setup channel, abort processing. + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CHAN_INUSE_STAT); + Debug("chan_inuse", + "4Remote chan=%d inuse tok.ip=%u.%u.%u.%u tok.seqno=%d seqno=%d", + c->cluster_vc_channel, DOT_SEPARATED(c->token.ip_created), c->token.sequence_number, c->seq_number); + + // Send cluster op failed reply + c->replyOpEvent(CACHE_EVENT_OPEN_WRITE_FAILED, (VConnection *) - ECLUSTER_CHANNEL_INUSE); + break; + + } else { + c->read_cluster_vc->current_cont = c; + } + ink_release_assert(c->read_cluster_vc != CLUSTER_DELAYED_OPEN); + + CacheHTTPInfo *ci = 0; + const char *p; + int res = 0; + int moi_len = len - flen; + + if (moi_len && c->cfl_flags & CFL_LOPENWRITE_HAVE_OLDINFO) { + p = (const char *) msg + flen; + + // Unmarshal old CacheHTTPInfo + res = HTTPInfo::unmarshal((char *) p, moi_len, NULL); + ink_assert(res > 0); + c->ic_old_info.get_handle((char *) p, moi_len); + ink_assert(c->ic_old_info.valid()); + ci = &c->ic_old_info; + } else { + p = (const char *) 0; + } + if (c->cfl_flags & CFL_ALLOW_MULTIPLE_WRITES) { + ink_assert(!ci); + ci = (CacheHTTPInfo *) CACHE_ALLOW_MULTIPLE_WRITES; + } + moi_len -= res; + p += res; + + CacheKey key(msg->url_md5); + char *hostname = NULL; + + if (moi_len) { + hostname = (char *) p; + } + + Cache *call_cache = caches[c->frag_type]; + Action *a = call_cache->open_write(c, &key, ci, c->pin_in_cache, + NULL, c->frag_type, hostname, len); + if (a != ACTION_RESULT_DONE) { + c->cache_action = a; + } + break; + } + case CACHE_REMOVE: + { + CacheOpMsg_short *msg = unmarshal_CacheOpMsg_short(data, mh->NeedByteSwap()); + init_from_short(c, msg, from); + Debug("cache_msg", + "cache_op op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_remove"); +#endif + CacheKey key(msg->md5); + + char *hostname = NULL; + int host_len = len - op_to_sizeof_fixedlen_msg(opcode); + if (host_len) { + hostname = (char *) msg->moi; + } + + Cache *call_cache = caches[c->frag_type]; + Action *a = call_cache->remove(c, &key, c->frag_type, + !!(c->cfl_flags & CFL_REMOVE_USER_AGENTS), + !!(c->cfl_flags & CFL_REMOVE_LINK), + hostname, host_len); + if (a != ACTION_RESULT_DONE) { + c->cache_action = a; + } + break; + } + case CACHE_LINK: + { + CacheOpMsg_short_2 *msg = unmarshal_CacheOpMsg_short_2(data, mh->NeedByteSwap()); + init_from_short_2(c, msg, from); + Debug("cache_msg", + "cache_op op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_link"); +#endif + + CacheKey key1(msg->md5_1); + CacheKey key2(msg->md5_2); + + char *hostname = NULL; + int host_len = len - op_to_sizeof_fixedlen_msg(opcode); + if (host_len) { + hostname = (char *) msg->moi; + } + + Cache *call_cache = caches[c->frag_type]; + Action *a = call_cache->link(c, &key1, &key2, c->frag_type, + hostname, host_len); + if (a != ACTION_RESULT_DONE) { + c->cache_action = a; + } + break; + } + case CACHE_DEREF: + { + CacheOpMsg_short *msg = unmarshal_CacheOpMsg_short(data, mh->NeedByteSwap()); + init_from_short(c, msg, from); + Debug("cache_msg", + "cache_op op=%d seqno=%d data=0x%x len=%d machine=0x%x", opcode, c->seq_number, data, len, from); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, len, "cache_op_deref"); +#endif + + CacheKey key(msg->md5); + + char *hostname = NULL; + int host_len = len - op_to_sizeof_fixedlen_msg(opcode); + if (host_len) { + hostname = (char *) msg->moi; + } + + Cache *call_cache = caches[c->frag_type]; + Action *a = call_cache->deref(c, &key, c->frag_type, + hostname, host_len); + if (a != ACTION_RESULT_DONE) { + c->cache_action = a; + } + break; + } + + default: + { + ink_release_assert(0); + } + } // End of switch +} + +void +cache_op_malloc_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + cache_op_ClusterFunction(from, data, len); + // We own the message data, free it back to the Cluster subsystem + clusterProcessor.free_remote_data((char *) data, len); +} + +int +CacheContinuation::setupVCdataRead(int event, VConnection * vc) +{ + ink_assert(magicno == (int) MagicNo); + // + // Setup the initial data read for the given Cache VC. + // This data is sent back in the response message. + // + if (event == CACHE_EVENT_OPEN_READ) { + ////////////////////////////////////////// + // Allocate buffer and initiate read. + ////////////////////////////////////////// + Debug("cache_proto", "setupVCdataRead CACHE_EVENT_OPEN_READ seqno=%d", seq_number); + ink_release_assert(caller_buf_freebytes); + SET_HANDLER((CacheContHandler) & CacheContinuation::VCdataRead); + + int64_t size_index = iobuffer_size_to_index(caller_buf_freebytes); + MIOBuffer *buf = new_MIOBuffer(size_index); + readahead_reader = buf->alloc_reader(); + + MUTEX_TRY_LOCK(lock, mutex, this_ethread()); // prevent immediate callback + readahead_vio = vc->do_io_read(this, caller_buf_freebytes, buf); + return EVENT_DONE; + + } else { + // Error case, deflect processing to replyOpEvent. + SET_HANDLER((CacheContHandler) & CacheContinuation::replyOpEvent); + return handleEvent(event, vc); + } +} + +int +CacheContinuation::VCdataRead(int event, VIO * target_vio) +{ + ink_release_assert(magicno == (int) MagicNo); + ink_release_assert(readahead_vio == target_vio); + + VConnection *vc = target_vio->vc_server; + int reply = CACHE_EVENT_OPEN_READ; + int32_t object_size; + + switch (event) { + case VC_EVENT_EOS: + { + if (!target_vio->ndone) { + // Doc with zero byte body, handle as read failure + goto read_failed; + } + // Fall through + } + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + { + int clone_bytes; + int current_ndone = target_vio->ndone; + + ink_assert(current_ndone); + ink_assert(current_ndone <= readahead_reader->read_avail()); + + object_size = getObjectSize(vc, request_opcode, &cache_vc_info); + have_all_data = ((object_size <= caller_buf_freebytes) && (object_size == current_ndone)); + + // Use no more than the caller's max buffer limit + + clone_bytes = current_ndone; + if (!have_all_data) { + if (current_ndone > caller_buf_freebytes) { + clone_bytes = caller_buf_freebytes; + } + } + // Clone data + + IOBufferBlock *tail; + readahead_data = clone_IOBufferBlockList(readahead_reader->get_current_block(), + readahead_reader->start_offset, clone_bytes, &tail); + + if (have_all_data) { + // Close VC, since no more data and also to avoid VC_EVENT_EOS + + MIOBuffer *mbuf = target_vio->buffer.writer(); + vc->do_io(VIO::CLOSE); + free_MIOBuffer(mbuf); + readahead_vio = 0; + } + SET_HANDLER((CacheContHandler) & CacheContinuation::replyOpEvent); + handleEvent(reply, vc); + return EVENT_CONT; + } + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + default: + { + read_failed: + // Read failed, deflect to replyOpEvent. + + MIOBuffer * mbuf = target_vio->buffer.writer(); + vc->do_io(VIO::CLOSE); + free_MIOBuffer(mbuf); + readahead_vio = 0; + reply = CACHE_EVENT_OPEN_READ_FAILED; + + SET_HANDLER((CacheContHandler) & CacheContinuation::replyOpEvent); + handleEvent(reply, (VConnection *) - ECLUSTER_ORB_DATA_READ); + return EVENT_DONE; + } + } // End of switch +} + +int +CacheContinuation::setupReadWriteVC(int event, VConnection * vc) +{ + // Only handles OPEN_READ_LONG processing. + + switch (event) { + case CACHE_EVENT_OPEN_READ: + { + // setup readahead + + SET_HANDLER((CacheContHandler) & CacheContinuation::setupVCdataRead); + return handleEvent(event, vc); + break; + } + case CACHE_EVENT_OPEN_READ_FAILED: + { + if (frag_type == CACHE_FRAG_TYPE_HTTP) { + // HTTP open read failed, attempt open write now to avoid an additional + // message round trip + + CacheKey key(url_md5); + + Cache *call_cache = caches[frag_type]; + Action *a = call_cache->open_write(this, &key, 0, pin_in_cache, + NULL, frag_type, ic_hostname->data(), + ic_hostname_len); + if (a != ACTION_RESULT_DONE) { + cache_action = a; + } + } else { + SET_HANDLER((CacheContHandler) & CacheContinuation::replyOpEvent); + return handleEvent(CACHE_EVENT_OPEN_READ_FAILED, 0); + } + break; + } + case CACHE_EVENT_OPEN_WRITE: + { + // Convert from read to write connection + + ink_assert(!read_cluster_vc && write_cluster_vc); + read_cluster_vc = write_cluster_vc; + read_cluster_vc->set_type(CLUSTER_OPT_CONN_WRITE); + write_cluster_vc = 0; + + SET_HANDLER((CacheContHandler) & CacheContinuation::replyOpEvent); + return handleEvent(event, vc); + break; + } + case CACHE_EVENT_OPEN_WRITE_FAILED: + default: + { + SET_HANDLER((CacheContHandler) & CacheContinuation::replyOpEvent); + return handleEvent(CACHE_EVENT_OPEN_READ_FAILED, 0); + break; + } + } // end of switch + + return EVENT_DONE; +} + +///////////////////////////////////////////////////////////////////////// +// replyOpEvent() +// Reflect the (local) reply back to the (remote) requesting node. +///////////////////////////////////////////////////////////////////////// +int +CacheContinuation::replyOpEvent(int event, VConnection * cvc) +{ + ink_assert(magicno == (int) MagicNo); + Debug("cache_proto", "replyOpEvent(this=%x,event=%d,VC=%x)", this, event, cvc); + ink_hrtime now; + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CACHE_CALLBACK_TIME_STAT, now - start_time); + LOG_EVENT_TIME(start_time, callback_time_dist, cache_callbacks); + ink_release_assert(expect_cache_callback); + expect_cache_callback = false; // make sure we are called back exactly once + + + result = event; + bool open = event_is_open(event); + bool read_op = op_is_read(request_opcode); + bool open_read_now_open_write = false; + + // Reply message initializations + CacheOpReplyMsg rmsg; + CacheOpReplyMsg *msg = &rmsg; + msg->result = event; + + if ((request_opcode == CACHE_OPEN_READ_LONG) + && cvc && (event == CACHE_EVENT_OPEN_WRITE)) { + ////////////////////////////////////////////////////////////////////////// + // open read failed, but open write succeeded, set result to + // CACHE_EVENT_OPEN_READ_FAILED and make result token non zero to + // signal to the remote node that we have established a write connection. + ////////////////////////////////////////////////////////////////////////// + msg->result = CACHE_EVENT_OPEN_READ_FAILED; + open_read_now_open_write = true; + } + + msg->seq_number = seq_number; + int flen = CacheOpReplyMsg::sizeof_fixedlen_msg(); // include token + int len = 0; + int vers = 0; + + int results_expected = 1; + + if (no_reply_message) // CACHE_NO_RESPONSE request + goto free_exit; + + if (open) { + + // prepare for CACHE_OPEN_EVENT + + results_expected = 2; + cache_vc = cvc; + cache_read = (event == CACHE_EVENT_OPEN_READ); + + if (read_op && !open_read_now_open_write) { + ink_release_assert(write_cluster_vc->pending_remote_fill); + ink_assert(have_all_data || (readahead_vio == &((CacheVC *) cache_vc)->vio)); + Debug("cache_proto", "connect_local success seqno=%d alldata=%d", seq_number, (have_all_data ? 1 : 0)); + + if (have_all_data) { + msg->token.clear(); // Tell sender no conn established + + } else { + msg->token = token; // Tell sender conn established + setupReadBufTunnel(cache_vc, write_cluster_vc); + } + + } else { + Debug("cache_proto", "cache_open [%s] success seqno=%d", (cache_read ? "R" : "W"), seq_number); + msg->token = token; // Tell sender conn established + + OneWayTunnel *pOWT = OneWayTunnel::OneWayTunnel_alloc(); + pOWT->init(read_cluster_vc, cache_vc, NULL, nbytes ? nbytes : DEFAULT_MAX_BUFFER_SIZE, this->mutex); + read_cluster_vc->allow_remote_close(); + results_expected--; + } + + // For cache reads, marshal the associated CacheHTTPInfo in the reply + if (cache_read) { + int res; + + if (!cache_vc_info.valid()) { + (void) getObjectSize(cache_vc, request_opcode, &cache_vc_info); + } + // Determine data length and allocate + len = cache_vc_info.marshal_length(); + CacheOpReplyMsg *reply = (CacheOpReplyMsg *) ALLOCA_DOUBLE(flen + len); + + // Initialize reply message header + *reply = *msg; + + // Marshal response data into reply message + res = cache_vc_info.marshal((char *) reply + flen, len); + ink_assert(res >= 0 && res <= len); + + // Make reply message the current message + msg = reply; + } + + } else { + Debug("cache_proto", "cache operation failed result=%d seqno=%d (this=%x)", event, seq_number, this); + msg->token.clear(); // Tell sender no conn established + + // Reallocate reply message, allowing for marshalled data + len += sizeof(int32_t); + CacheOpReplyMsg *reply = (CacheOpReplyMsg *) ALLOCA_DOUBLE(flen + len); + + // Initialize reply message header + *reply = *msg; + + if (request_opcode != CACHE_LINK) { + // + // open read/write failed, close preallocated VC + // + if (read_cluster_vc) { + read_cluster_vc->remote_closed = 1; // avoid remote close msg + read_cluster_vc->do_io(VIO::CLOSE); + } + if (write_cluster_vc) { + write_cluster_vc->pending_remote_fill = 0; + write_cluster_vc->remote_closed = 1; // avoid remote close msg + write_cluster_vc->do_io(VIO::CLOSE); + } + *((int32_t *) reply->moi) = (int32_t) ((uintptr_t) cvc & 0xffffffff); // code describing failure + } + // Make reply message the current message + msg = reply; + } + CLUSTER_DECREMENT_DYN_STAT(CLUSTER_CACHE_OUTSTANDING_STAT); + + // + // Send reply message + // +#ifdef CACHE_MSG_TRACE + log_cache_op_sndmsg(msg->seq_number, 0, "replyOpEvent"); +#endif + vers = CacheOpReplyMsg::protoToVersion(from->msg_proto_major); + if (vers == CacheOpReplyMsg::CACHE_OP_REPLY_MESSAGE_VERSION) { + if (read_op) { + // Transmit reply message and object data in same cluster message + Debug("cache_proto", "Sending reply/data seqno=%d buflen=%d", + seq_number, readahead_data ? bytes_IOBufferBlockList(readahead_data, 1) : 0); + clusterProcessor.invoke_remote_data(from, + CACHE_OP_RESULT_CLUSTER_FUNCTION, + (void *) msg, (flen + len), + readahead_data, + cluster_vc_channel, &token, + &CacheContinuation::disposeOfDataBuffer, (void *) this, CLUSTER_OPT_STEAL); + } else { + Debug("cache_proto", "Sending reply seqno=%d, (this=%x)", seq_number, this); + clusterProcessor.invoke_remote(from, CACHE_OP_RESULT_CLUSTER_FUNCTION, + (void *) msg, (flen + len), CLUSTER_OPT_STEAL); + } + + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"replyOpEvent() bad msg version"); + } + +free_exit: + results_expected--; + if (results_expected <= 0) { + Debug("cache_proto", "replyOpEvent: freeing this=%x", this, event, cvc); + cacheContAllocator_free(this); + } + return EVENT_DONE; +} + +void +CacheContinuation::setupReadBufTunnel(VConnection * cache_read_vc, VConnection * cluster_write_vc) +{ + //////////////////////////////////////////////////////////// + // Setup OneWayTunnel and tunnel close event handler. + // Used in readahead processing on open read connections. + //////////////////////////////////////////////////////////// + tunnel_cont = cacheContAllocator_alloc(); + tunnel_cont->mutex = this->mutex; + SET_CONTINUATION_HANDLER(tunnel_cont, (CacheContHandler) + & CacheContinuation::tunnelClosedEvent); + int64_t ravail = bytes_IOBufferBlockList(readahead_data, 1); + + tunnel_mutex = tunnel_cont->mutex; + tunnel_closed = false; + + tunnel = OneWayTunnel::OneWayTunnel_alloc(); + readahead_reader->consume(ravail); // allow for bytes sent in initial reply + tunnel->init(cache_read_vc, cluster_write_vc, tunnel_cont, readahead_vio, readahead_reader); + tunnel_cont->action = this; + tunnel_cont->tunnel = tunnel; + tunnel_cont->tunnel_cont = tunnel_cont; + + // Disable cluster_write_vc + ((ClusterVConnection *) cluster_write_vc)->write.enabled = 0; + + // Disable cache read VC + readahead_vio->nbytes = readahead_vio->ndone; + + ///////////////////////////////////////////////////////////////////// + // At this point, the OneWayTunnel is blocked awaiting a reenable + // on both the source and target VCs. Reenable occurs after the + // message containing the initial data and open read reply are sent. + ///////////////////////////////////////////////////////////////////// +} + +/////////////////////////////////////////////////////////////////////// +// Tunnnel exited event handler, used for readahead on open read. +/////////////////////////////////////////////////////////////////////// +int +CacheContinuation::tunnelClosedEvent(int event, void *c) +{ + NOWARN_UNUSED(event); + ink_assert(magicno == (int) MagicNo); + // Note: We are called with the tunnel_mutex held. + CacheContinuation *tc = (CacheContinuation *) c; + ink_release_assert(tc->tunnel_cont == tc); + CacheContinuation *real_cc = (CacheContinuation *) tc->action.continuation; + + if (real_cc) { + // Notify the real continuation of the tunnel closed event + real_cc->tunnel = 0; + real_cc->tunnel_cont = 0; + real_cc->tunnel_closed = true; + } + OneWayTunnel::OneWayTunnel_free(tc->tunnel); + cacheContAllocator_free(tc); + + return EVENT_DONE; +} + +//////////////////////////////////////////////////////////// +// Retry DisposeOfDataBuffer continuation +//////////////////////////////////////////////////////////// +struct retryDisposeOfDataBuffer; +typedef int (retryDisposeOfDataBuffer::*rtryDisOfDBufHandler) (int, void *); +struct retryDisposeOfDataBuffer:public Continuation +{ + CacheContinuation *c; + + int handleRetryEvent(int event, Event * e) + { + if (CacheContinuation::handleDisposeEvent(event, c) == EVENT_DONE) { + delete this; + return EVENT_DONE; + } else + { + e->schedule_in(HRTIME_MSECONDS(10)); + return EVENT_CONT; + } + } + retryDisposeOfDataBuffer(CacheContinuation * cont) +: Continuation(new_ProxyMutex()), c(cont) { + SET_HANDLER((rtryDisOfDBufHandler) + & retryDisposeOfDataBuffer::handleRetryEvent); + } +}; + +////////////////////////////////////////////////////////////////// +// Callback from cluster to dispose of data passed in +// call to invoke_remote_data(). +////////////////////////////////////////////////////////////////// +void +CacheContinuation::disposeOfDataBuffer(void *d) +{ + ink_assert(d); + CacheContinuation *cc = (CacheContinuation *) d; + ink_assert(cc->have_all_data || cc->readahead_vio); + ink_assert(cc->have_all_data || (cc->readahead_vio == &((CacheVC *) cc->cache_vc)->vio)); + + if (cc->have_all_data) { + // + // All object data resides in the buffer, no OneWayTunnel + // started and the Cache VConnection has already been closed. + // Close write_cluster_vc and set remote close to avoid send of + // close message to remote node. + // + cc->write_cluster_vc->pending_remote_fill = 0; + cc->write_cluster_vc->remote_closed = 1; + cc->write_cluster_vc->do_io(VIO::CLOSE); + cc->readahead_data = 0; + + cacheContAllocator_free(cc); + + } else { + cc->write_cluster_vc->pending_remote_fill = 0; + cc->write_cluster_vc->allow_remote_close(); + if (handleDisposeEvent(0, cc) == EVENT_CONT) { + // Setup retry continuation. + retryDisposeOfDataBuffer *retryCont = NEW(new retryDisposeOfDataBuffer(cc)); + eventProcessor.schedule_in(retryCont, HRTIME_MSECONDS(10), ET_CALL); + } + } +} + +int +CacheContinuation::handleDisposeEvent(int event, CacheContinuation * cc) +{ + NOWARN_UNUSED(event); + ink_assert(cc->magicno == (int) MagicNo); + MUTEX_TRY_LOCK(lock, cc->tunnel_mutex, this_ethread()); + if (lock) { + // Write of initial object data is complete. + + if (!cc->tunnel_closed) { + // Start tunnel by reenabling source and target VCs. + + cc->tunnel->vioSource->nbytes = getObjectSize(cc->tunnel->vioSource->vc_server, cc->request_opcode, 0); + cc->tunnel->vioSource->reenable_re(); + cc->tunnel->vioTarget->reenable(); + + // Tell tunnel event we are gone + cc->tunnel_cont->action.continuation = 0; + } + cacheContAllocator_free(cc); + return EVENT_DONE; + + } else { + // Lock acquire failed, retry operation. + return EVENT_CONT; + } +} + +///////////////////////////////////////////////////////////////////////////// +// cache_op_result_ClusterFunction() +// Invoked on the machine which initiated a remote op, this +// unmarshals the result and calls a continuation in the requesting thread. +///////////////////////////////////////////////////////////////////////////// +void +cache_op_result_ClusterFunction(ClusterMachine * from, void *d, int l) +{ + (void) from; + //////////////////////////////////////////////////////// + // Note: we are running on the ET_CACHE_CONT_SM thread + //////////////////////////////////////////////////////// + + // Copy reply message data + Ptr iob = new_IOBufferData(iobuffer_size_to_index(l)); + memcpy(iob->data(), (char *) d, l); + char *data = iob->data(); + int flen, len = l; + CacheHTTPInfo ci; + CacheOpReplyMsg *msg = (CacheOpReplyMsg *) data; + int32_t op_result_error = 0; + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + + if (mh->GetMsgVersion() != CacheOpReplyMsg::CACHE_OP_REPLY_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"cache_op_result_ClusterFunction() bad msg version"); + } + + flen = CacheOpReplyMsg::sizeof_fixedlen_msg(); + if (mh->NeedByteSwap()) + msg->SwapBytes(); + + Debug("cluster_cache", "received cache op result, seqno=%d result=%d", msg->seq_number, msg->result); + + // If applicable, unmarshal any response data + if ((len > flen) && event_reply_may_have_moi(msg->result)) { + switch (msg->result) { + case CACHE_EVENT_OPEN_READ: + { + char *p = (char *) msg + flen; + int res; + + // Unmarshal CacheHTTPInfo + res = HTTPInfo::unmarshal(p, len, NULL); + ci.get_handle(p, len); + ink_assert(res > 0); + ink_assert(ci.valid()); + break; + } + case CACHE_EVENT_LINK: + case CACHE_EVENT_LINK_FAILED: + break; + case CACHE_EVENT_OPEN_READ_FAILED: + case CACHE_EVENT_OPEN_WRITE_FAILED: + case CACHE_EVENT_REMOVE_FAILED: + case CACHE_EVENT_UPDATE_FAILED: + case CACHE_EVENT_DEREF_FAILED: + { + // Unmarshal the error code + ink_assert(((len - flen) == sizeof(int32_t))); + op_result_error = *(int32_t *) msg->moi; + if (mh->NeedByteSwap()) + swap32((uint32_t *) & op_result_error); + op_result_error = -op_result_error; + break; + } + default: + { + ink_release_assert(!"invalid moi data for received msg"); + break; + } + } // end of switch + } + // See if this response is still expected (expected case == yes) + + unsigned int hash = FOLDHASH(from->ip, msg->seq_number); + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + if (MUTEX_TAKE_TRY_LOCK(remoteCacheContQueueMutex[hash], thread)) { + + // Find it in pending list + + CacheContinuation *c = find_cache_continuation(msg->seq_number, + from->ip); + if (!c) { + // Reply took to long, response no longer expected. + MUTEX_UNTAKE_LOCK(remoteCacheContQueueMutex[hash], thread); + Debug("cluster_timeout", "0cache reply timeout: %d", msg->seq_number); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_REMOTE_OP_REPLY_TIMEOUTS_STAT); + if (ci.valid()) + ci.destroy(); + return; + } + // Try to send the message + + MUTEX_TRY_LOCK(lock, c->mutex, thread); + + // Failed to acquire lock, defer + + if (!lock) { + MUTEX_UNTAKE_LOCK(remoteCacheContQueueMutex[hash], thread); + goto Lretry; + } + c->result_error = op_result_error; + + // send message, release lock + + c->freeMsgBuffer(); + if (ci.valid()) { + // Unmarshaled CacheHTTPInfo contained in reply message, copy it. + c->setMsgBufferLen(len, iob); + c->ic_new_info = ci; + } + msg->seq_number = len; // HACK ALERT: reusing variable + c->handleEvent(CACHE_EVENT_RESPONSE_MSG, data); + + } else { + + // Failed to wake it up, defer by creating a timed continuation + + Lretry: + CacheContinuation * c = CacheContinuation::cacheContAllocator_alloc(); + c->mutex = new_ProxyMutex(); + c->seq_number = msg->seq_number; + c->target_ip = from->ip; + SET_CONTINUATION_HANDLER(c, (CacheContHandler) + & CacheContinuation::handleReplyEvent); + c->start_time = ink_get_hrtime(); + c->result = msg->result; + if (event_is_open(msg->result)) + c->token = msg->token; + if (ci.valid()) { + // Unmarshaled CacheHTTPInfo contained in reply message, copy it. + c->setMsgBufferLen(len, iob); + c->ic_new_info = ci; + } + c->result_error = op_result_error; + eventProcessor.schedule_in(c, CACHE_RETRY_PERIOD, ET_CACHE_CONT_SM); + } +} + +//////////////////////////////////////////////////////////////////////// +// handleReplyEvent() +// If we cannot acquire any of the locks to handle the response +// inline, it is defered and later handled by this function. +//////////////////////////////////////////////////////////////////////// +int +CacheContinuation::handleReplyEvent(int event, Event * e) +{ + (void) event; + + // take lock on outstanding message queue + + EThread *t = e->ethread; + unsigned int hash = FOLDHASH(target_ip, seq_number); + + if (!MUTEX_TAKE_TRY_LOCK(remoteCacheContQueueMutex[hash], t)) { + e->schedule_in(CACHE_RETRY_PERIOD); + return EVENT_CONT; + } + + LOG_EVENT_TIME(start_time, cntlck_acquire_time_dist, cntlck_acquire_events); + + // See if this response is still expected + + CacheContinuation *c = find_cache_continuation(seq_number, target_ip); + if (c) { + + // Acquire the lock to the continuation mutex + + MUTEX_TRY_LOCK(lock, c->mutex, e->ethread); + if (!lock) { + + // If we fail to acquire the lock, reschedule + + MUTEX_UNTAKE_LOCK(remoteCacheContQueueMutex[hash], t); + e->schedule_in(CACHE_RETRY_PERIOD); + return EVENT_CONT; + } + + // If unmarshalled CacheHTTPInfo exists, pass it along + + if (ic_new_info.valid()) { + c->freeMsgBuffer(); + c->setMsgBufferLen(getMsgBufferLen(), getMsgBufferIOBData()); + c->ic_new_info = ic_new_info; + ic_new_info.clear(); + } + // send message, release lock + + c->handleEvent(CACHE_EVENT_RESPONSE, this); + + } else { + MUTEX_UNTAKE_LOCK(remoteCacheContQueueMutex[hash], t); + Debug("cluster_timeout", "cache reply timeout: %d", seq_number); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_REMOTE_OP_REPLY_TIMEOUTS_STAT); + } + + // Free this continuation + + cacheContAllocator_free(this); + return EVENT_DONE; +} + +////////////////////////////////////////////////////////////////////////// +// remoteOpEvent() +// On the requesting node, handle the timeout and response to the user. +// There may be two CacheContinuations involved: +// 1) One waiting to respond to the user. +// This case is CACHE_EVENT_RESPONSE_MSG which is handled +// inline (without delay). +// 2) One which is carrying the response from the remote machine which +// has been delayed for a lock. This case is CACHE_EVENT_RESPONSE. +////////////////////////////////////////////////////////////////////////// +int +CacheContinuation::remoteOpEvent(int event_code, Event * e) +{ + ink_assert(magicno == (int) MagicNo); + int event = event_code; + ink_hrtime now; + if (start_time) { + int res; + if (event != EVENT_INTERVAL) { + if (event == CACHE_EVENT_RESPONSE) { + CacheContinuation *ccont = (CacheContinuation *) e; + res = ccont->result; + } else { + CacheOpReplyMsg *rmsg = (CacheOpReplyMsg *) e; + res = rmsg->result; + } + if ((res == CACHE_EVENT_LOOKUP) || (res == CACHE_EVENT_LOOKUP_FAILED)) { + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CACHE_LKRMT_CALLBACK_TIME_STAT, now - start_time); + LOG_EVENT_TIME(start_time, lkrmt_callback_time_dist, lkrmt_cache_callbacks); + } else { + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CACHE_RMT_CALLBACK_TIME_STAT, now - start_time); + LOG_EVENT_TIME(start_time, rmt_callback_time_dist, rmt_cache_callbacks); + } + } + start_time = 0; + } + // for CACHE_EVENT_RESPONSE/XXX the lock was acquired at the higher level + intptr_t return_error = 0; + ClusterVCToken *pToken = NULL; + +retry: + + switch (event) { + default: + ink_assert(!"bad case"); + return EVENT_DONE; + + case EVENT_INTERVAL:{ + + unsigned int hash = FOLDHASH(target_ip, seq_number); + + MUTEX_TRY_LOCK(queuelock, remoteCacheContQueueMutex[hash], e->ethread); + if (!queuelock) { + e->schedule_in(CACHE_RETRY_PERIOD); + return EVENT_CONT; + } + // we are not yet enqueued on the list of outstanding operations + + if (!remoteCacheContQueue[hash].in(this)) { + remoteCacheContQueue[hash].enqueue(this); + ink_assert(timeout == e); + MUTEX_RELEASE(queuelock); + e->schedule_in(cache_cluster_timeout); + return EVENT_CONT; + } + // a timeout has occurred + + if (find_cache_continuation(seq_number, target_ip)) { + // Valid timeout + MUTEX_RELEASE(queuelock); + + Debug("cluster_timeout", "cluster op timeout %d", seq_number); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_REMOTE_OP_TIMEOUTS_STAT); + request_timeout = true; + timeout = 0; + // + // Post error completion now and defer deallocation of + // the continuation until we receive the reply or the + // target node goes down. + // + if (!action.cancelled) + action.continuation->handleEvent(result, (void *) -ECLUSTER_OP_TIMEOUT); + action.cancelled = 1; + + if (target_machine->dead) { + event = CACHE_EVENT_RESPONSE_MSG; + goto retry; + } else { + timeout = e; + e->schedule_in(cache_cluster_timeout); + return EVENT_DONE; + } + + } else { + // timeout not expected for continuation; log and ignore + MUTEX_RELEASE(queuelock); + Debug("cluster_timeout", "unknown cluster op timeout %d", seq_number); + Note("Unexpected CacheCont timeout, [%u.%u.%u.%u] seqno=%d", DOT_SEPARATED(target_ip), seq_number); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_REMOTE_OP_TIMEOUTS_STAT); + return EVENT_DONE; + } + } + + case CACHE_EVENT_RESPONSE: + case CACHE_EVENT_RESPONSE_MSG:{ + + // the response has arrived, cancel timeout + + if (timeout) { + timeout->cancel(); + timeout = 0; + } + // remove from the pending queue + unsigned int hash = FOLDHASH(target_ip, seq_number); + + remoteCacheContQueue[hash].remove(this); + MUTEX_UNTAKE_LOCK(remoteCacheContQueueMutex[hash], this_ethread()); + // Fall through + } + + case CACHE_EVENT_RESPONSE_RETRY:{ + + // determine result code + + CacheContinuation *c = (CacheContinuation *) e; + CacheOpReplyMsg *msg = (CacheOpReplyMsg *) e; + if (event == CACHE_EVENT_RESPONSE_MSG) { + result = (request_timeout ? result : msg->result); + pToken = (request_timeout ? &token : &msg->token); + } else if (event == CACHE_EVENT_RESPONSE) { + result = (request_timeout ? result : c->result); + pToken = &c->token; + } else if (event == CACHE_EVENT_RESPONSE_RETRY) { + pToken = &token; + } else { + ink_release_assert(!"remoteOpEvent bad event code"); + } + + // handle response + + if (result == CACHE_EVENT_LOOKUP) { + callback_user(result, 0); + return EVENT_DONE; + + } else if (event_is_open(result)) { + bool read_op = ((request_opcode == CACHE_OPEN_READ) + || (request_opcode == CACHE_OPEN_READ_LONG)); + if (read_op) { + ink_release_assert(read_cluster_vc->pending_remote_fill > 1); + read_cluster_vc->pending_remote_fill = 0; + + have_all_data = pToken->is_clear(); // no conn implies all data + if (have_all_data) { + read_cluster_vc->have_all_data = 1; + } else { + read_cluster_vc->have_all_data = 0; + } + // Move CacheHTTPInfo reply data into VC + read_cluster_vc->marshal_buf = this->getMsgBufferIOBData(); + read_cluster_vc->alternate = this->ic_new_info; + this->ic_new_info.clear(); + ink_release_assert(read_cluster_vc->alternate.object_size_get()); + + if (!action.cancelled) { + ClusterVConnection *target_vc = read_cluster_vc; + callback_user(result, target_vc); // "this" is deallocated + target_vc->allow_remote_close(); + } else { + read_cluster_vc->allow_remote_close(); + read_cluster_vc->do_io(VIO::ABORT); + cacheContAllocator_free(this); + } + + } else { + ink_assert(result == CACHE_EVENT_OPEN_WRITE); + ink_assert(!pToken->is_clear()); + + ClusterVConnection *result_vc = write_cluster_vc; + if (!action.cancelled) { + callback_user(result, result_vc); + result_vc->allow_remote_close(); + } else { + result_vc->allow_remote_close(); + result_vc->do_io(VIO::ABORT); + cacheContAllocator_free(this); + } + } + return EVENT_DONE; + } + break; + } // End of case + } // End of switch + + // Handle failure cases + + if (result == CACHE_EVENT_LOOKUP_FAILED) { + + + // check for local probes + + ClusterMachine *m = cluster_machine_at_depth(cache_hash(url_md5)); + + // if the current configuration indicates that this + // machine is the master (or the owner machine has failed), go to + // the local machine. Also if PROBE_LOCAL_CACHE_LAST. + // + int len = getMsgBufferLen(); + char *hostname = (len ? getMsgBuffer() : 0); + + if (!m || PROBE_LOCAL_CACHE_LAST) { + SET_HANDLER((CacheContHandler) & CacheContinuation::probeLookupEvent); + CacheKey key(url_md5); + + Cache *call_cache = caches[frag_type]; + call_cache->lookup(this, &key, frag_type, hostname, len); + return EVENT_DONE; + } + if (PROBE_LOCAL_CACHE_FIRST) { + callback_user(CACHE_EVENT_LOOKUP_FAILED, 0); + } else { + SET_HANDLER((CacheContHandler) & CacheContinuation::probeLookupEvent); + CacheKey key(url_md5); + + Cache *call_cache = caches[frag_type]; + call_cache->lookup(this, &key, frag_type, hostname, len); + } + return EVENT_DONE; + + } else { + // Handle failure of all ops except for lookup + + ClusterVConnection *cacheable_vc = 0; + if ((request_opcode == CACHE_OPEN_READ_LONG) && !pToken->is_clear()) { + ink_assert(read_cluster_vc && !write_cluster_vc); + // + // OPEN_READ_LONG has failed, but the remote node was able to + // establish an OPEN_WRITE_LONG connection. + // Convert the cluster read VC to a write VC and insert it + // into the global write VC cache. This will allow us to + // locally resolve the subsequent OPEN_WRITE_LONG request. + // + + // Note: We do not allow remote close on this VC while + // it resides in cache + // + read_cluster_vc->set_type(CLUSTER_OPT_CONN_WRITE); + // FIX ME. ajitb 12/21/99 + // Compiler bug in CC: WorkShop Compilers 5.0 98/12/15 C++ 5.0 + // Does not accept assignment of ((Continuation *) NULL) + { + Continuation *temp = NULL; + read_cluster_vc->action_ = temp; + } + if (!GlobalOpenWriteVCcache->insert(&url_md5, read_cluster_vc)) { + // Unable to insert VC into cache, try later + cacheable_vc = read_cluster_vc; + } + read_cluster_vc = 0; + } + if (read_cluster_vc) { + read_cluster_vc->remote_closed = 0; // send remote close + read_cluster_vc->allow_remote_close(); + read_cluster_vc->do_io(VIO::ABORT); + read_cluster_vc = 0; + } + if (write_cluster_vc) { + write_cluster_vc->remote_closed = 0; // send remote close + write_cluster_vc->allow_remote_close(); + write_cluster_vc->do_io(VIO::ABORT); + write_cluster_vc = 0; + } + if (!request_timeout) { + if (!return_error) { + return_error = result_error; + } + if (cacheable_vc) { + insert_cache_callback_user(cacheable_vc, result, (void *) return_error); + } else { + callback_user(result, (void *) return_error); + } + } else { + // callback already made at timeout, just free continuation + if (cacheable_vc) { + cacheable_vc->allow_remote_close(); + cacheable_vc->do_io(VIO::CLOSE); + cacheable_vc = 0; + } + cacheContAllocator_free(this); + } + return EVENT_DONE; + } +} + +////////////////////////////////////////////////////////////////////////// +// probeLookupEvent() +// After a local probe, return the response to the client and cleanup. +////////////////////////////////////////////////////////////////////////// + +int +CacheContinuation::probeLookupEvent(int event, void *d) +{ + NOWARN_UNUSED(d); + ink_assert(magicno == (int) MagicNo); + callback_user(event, 0); + return EVENT_DONE; +} + +/////////////////////////////////////////////////////////// +// lookupEvent() +// Result of a local lookup for PROBE_LOCAL_CACHE_FIRST +/////////////////////////////////////////////////////////// +int +CacheContinuation::lookupEvent(int event, void *d) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(d); + ink_release_assert(!"Invalid call CacheContinuation::lookupEvent"); + return EVENT_DONE; + +} + + + +////////////////////////////////////////////////////////////////////////// +// do_remote_lookup() +// If the object is supposed to be on a remote machine, probe there. +// Returns: Non zero (Action *) if a probe was initiated +// Zero (Action *) if no probe +////////////////////////////////////////////////////////////////////////// +Action * +CacheContinuation::do_remote_lookup(Continuation * cont, CacheKey * key, + CacheContinuation * c, CacheFragType ft, char *hostname, int hostname_len) +{ + int probe_depth = 0; + ClusterMachine *past_probes[CONFIGURATION_HISTORY_PROBE_DEPTH] = { 0 }; + int mlen = op_to_sizeof_fixedlen_msg(CACHE_LOOKUP_OP) + ((hostname && hostname_len) ? hostname_len : 0); + CacheLookupMsg *msg = (CacheLookupMsg *) ALLOCA_DOUBLE(mlen); +#ifdef PURIFY + memset((char *) msg, 0, mlen); +#endif + msg->init(); + + + if (key) { + msg->url_md5 = *key; + } else { + ink_assert(c); + msg->url_md5 = c->url_md5; + } + + ClusterMachine *m = NULL; + + if (cache_migrate_on_demand) { + m = cluster_machine_at_depth(cache_hash(msg->url_md5), + c ? &c->probe_depth : &probe_depth, c ? c->past_probes : past_probes); + } else { + + // If migrate-on-demand is off, do not probe beyond one level. + + if (c && c->probe_depth) + return (Action *) 0; + m = cluster_machine_at_depth(cache_hash(msg->url_md5)); + if (c) + c->probe_depth = 1; + } + + if (!m) + return (Action *) 0; + + // If we do not have a continuation, build one + + if (!c) { + c = cacheContAllocator_alloc(); + c->mutex = cont->mutex; + c->probe_depth = probe_depth; + memcpy(c->past_probes, past_probes, sizeof(past_probes)); + } + // Save hostname data in case we need to do a local lookup. + if (hostname && hostname_len) { + // Alloc buffer, copy hostname data and attach to continuation + c->setMsgBufferLen(hostname_len); + c->allocMsgBuffer(); + memcpy(c->getMsgBuffer(), hostname, hostname_len); + } + + c->url_md5 = msg->url_md5; + c->action.cancelled = false; + c->action = cont; + c->start_time = ink_get_hrtime(); + SET_CONTINUATION_HANDLER(c, (CacheContHandler) + & CacheContinuation::remoteOpEvent); + c->result = CACHE_EVENT_LOOKUP_FAILED; + + // set up sequence number so we can find this continuation + + c->target_ip = m->ip; + c->seq_number = new_cache_sequence_number(); + msg->seq_number = c->seq_number; + c->frag_type = ft; + msg->frag_type = ft; + + // establish timeout for lookup + + unsigned int hash = FOLDHASH(c->target_ip, c->seq_number); + MUTEX_TRY_LOCK(queuelock, remoteCacheContQueueMutex[hash], this_ethread()); + if (!queuelock) { + // failed to acquire lock: no problem, retry later + c->timeout = eventProcessor.schedule_in(c, CACHE_RETRY_PERIOD, ET_CACHE_CONT_SM); + } else { + remoteCacheContQueue[hash].enqueue(c); + MUTEX_RELEASE(queuelock); + c->timeout = eventProcessor.schedule_in(c, cache_cluster_timeout, ET_CACHE_CONT_SM); + } + + char *data; + int len; + int vers = CacheLookupMsg::protoToVersion(m->msg_proto_major); + + if (vers == CacheLookupMsg::CACHE_LOOKUP_MESSAGE_VERSION) { + msg->seq_number = c->seq_number; + data = (char *) msg; + len = mlen; + if (hostname && hostname_len) { + memcpy(msg->moi, hostname, hostname_len); + } + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"CacheLookupMsg bad msg version"); + } + + // send the message + +#ifdef CACHE_MSG_TRACE + log_cache_op_sndmsg(msg.seq_number, 0, "cache_lookup"); +#endif + clusterProcessor.invoke_remote(m, CACHE_LOOKUP_CLUSTER_FUNCTION, data, len); + return &c->action; +} + + +//////////////////////////////////////////////////////////////////////////// +// cache_lookup_ClusterFunction() +// This function is invoked on a remote machine to do a remote lookup. +// It unmarshals the URL and does a local lookup, with its own +// continuation set to CacheContinuation::replyLookupEvent() +//////////////////////////////////////////////////////////////////////////// +void +cache_lookup_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + (void) from; + (void) len; + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + //////////////////////////////////////////////////////// + // Note: we are running on the ET_CLUSTER thread + //////////////////////////////////////////////////////// + + CacheLookupMsg *msg = (CacheLookupMsg *) data; + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + + if (mh->GetMsgVersion() != CacheLookupMsg::CACHE_LOOKUP_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"cache_lookup_ClusterFunction() bad msg version"); + } + + if (mh->NeedByteSwap()) + msg->SwapBytes(); + + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CACHE_OUTSTANDING_STAT); + + CacheContinuation *c = CacheContinuation::cacheContAllocator_alloc(); + c->mutex = new_ProxyMutex(); + MUTEX_TRY_LOCK(lock, c->mutex, this_ethread()); + c->no_reply_message = (msg->seq_number == CACHE_NO_RESPONSE); + c->seq_number = msg->seq_number; + c->from = from; + c->url_md5 = msg->url_md5; + SET_CONTINUATION_HANDLER(c, (CacheContHandler) + & CacheContinuation::replyLookupEvent); + + CacheKey key(msg->url_md5); +#ifdef CACHE_MSG_TRACE + log_cache_op_msg(msg->seq_number, 0, "cache_lookup"); +#endif + + // Extract hostname data if passed. + + char *hostname; + int hostname_len = len - op_to_sizeof_fixedlen_msg(CACHE_LOOKUP_OP); + hostname = (hostname_len ? (char *) msg->moi : 0); + + // Note: Hostname data invalid after return from lookup + Cache *call_cache = caches[msg->frag_type]; + call_cache->lookup(c, &key, (CacheFragType) msg->frag_type, hostname, hostname_len); +} + +///////////////////////////////////////////////////////////////////////// +// replyLookupEvent() +// This function handles the result of a lookup on a remote machine. +// It packages up the result and sends it back to the calling machine. +///////////////////////////////////////////////////////////////////////// +int +CacheContinuation::replyLookupEvent(int event, void *d) +{ + NOWARN_UNUSED(d); + ink_hrtime now; + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CACHE_CALLBACK_TIME_STAT, now - start_time); + LOG_EVENT_TIME(start_time, callback_time_dist, cache_callbacks); + + int vers = CacheOpReplyMsg::protoToVersion(from->msg_proto_major); + if (vers == CacheOpReplyMsg::CACHE_OP_REPLY_MESSAGE_VERSION) { + CacheOpReplyMsg *msg; + int flen = CacheOpReplyMsg::sizeof_fixedlen_msg(); +#ifdef PURIFY + msg = (CacheOpReplyMsg *) xmalloc(flen); +#else + msg = (CacheOpReplyMsg *) ALLOCA_DOUBLE(flen); +#endif + msg->init(); + CLUSTER_DECREMENT_DYN_STAT(CLUSTER_CACHE_OUTSTANDING_STAT); + int len = flen - sizeof(msg->token); + + if (!no_reply_message) { + msg->seq_number = seq_number; + msg->result = event; +#ifdef CACHE_MSG_TRACE + log_cache_op_sndmsg(seq_number, event, "cache_result"); +#endif + clusterProcessor.invoke_remote(from, CACHE_OP_RESULT_CLUSTER_FUNCTION, msg, len); +#ifdef PURIFY + xfree(msg); +#endif + } + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"replyLookupEvent() bad msg version"); + } + + // Free up everything + + cacheContAllocator_free(this); + return EVENT_DONE; +} + +int32_t CacheContinuation::getObjectSize(VConnection * vc, int opcode, CacheHTTPInfo * ret_ci) +{ + CacheHTTPInfo *ci = 0; + int64_t object_size = 0; + + if ((opcode == CACHE_OPEN_READ_LONG) + || (opcode == CACHE_OPEN_READ_BUFFER_LONG)) { + + ((CacheVC *) vc)->get_http_info(&ci); + if (ci) { + object_size = ci->object_size_get(); + + } else { + ci = 0; + object_size = 0; + } + + } else { + object_size = ((CacheVC *)vc)->get_object_size(); + } + + if (ret_ci && !ret_ci->valid()) { + CacheHTTPInfo + new_ci; + new_ci.create(); + if (ci) { + // Initialize copy + new_ci.copy(ci); + } else { + new_ci.object_size_set(object_size); + } + new_ci.m_alt->m_writeable = 1; + ret_ci->copy_shallow(&new_ci); + } + ink_release_assert(object_size); + return object_size; +} + +////////////////////////////////////////////////////////////////////////// +// insert_cache_callback_user() +// Insert write VC into global cache prior to performing user callback. +////////////////////////////////////////////////////////////////////////// +void +CacheContinuation::insert_cache_callback_user(ClusterVConnection * vc, int res, void *e) +{ + if (GlobalOpenWriteVCcache->insert(&url_md5, vc)) { + // Inserted + callback_user(res, e); + + } else { + // Unable to insert, try later + result = res; + callback_data = e; + callback_data_2 = (void *) vc; + SET_HANDLER((CacheContHandler) & CacheContinuation::insertCallbackEvent); + eventProcessor.schedule_imm(this, ET_CACHE_CONT_SM); + } +} + +int +CacheContinuation::insertCallbackEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + if (GlobalOpenWriteVCcache->insert(&url_md5, (ClusterVConnection *) + callback_data_2)) { + // Inserted + callback_user(result, callback_data); + + } else { + // Unable to insert, try later + eventProcessor.schedule_imm(this, ET_CACHE_CONT_SM); + } + return EVENT_DONE; +} + +/////////////////////////////////////////////////////////////////// +// callback_user() +// Invoke handleEvent on the given continuation (cont) with +// considerations for Action. +/////////////////////////////////////////////////////////////////// +void +CacheContinuation::callback_user(int res, void *e) +{ + EThread *et = this_ethread(); + + if (!is_ClusterThread(et)) { + MUTEX_TRY_LOCK(lock, mutex, et); + if (lock) { + if (!action.cancelled) { + action.continuation->handleEvent(res, e); + } + cacheContAllocator_free(this); + + } else { + // Unable to acquire lock, retry later + defer_callback_result(res, e); + } + } else { + // Can not post completion on ET_CLUSTER thread. + defer_callback_result(res, e); + } +} + +void +CacheContinuation::defer_callback_result(int r, void *e) +{ + result = r; + callback_data = e; + SET_HANDLER((CacheContHandler) & CacheContinuation::callbackResultEvent); + eventProcessor.schedule_imm(this, ET_CACHE_CONT_SM); +} + +int +CacheContinuation::callbackResultEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + if (!action.cancelled) + action.continuation->handleEvent(result, callback_data); + cacheContAllocator_free(this); + return EVENT_DONE; +} + +//----------------------------------------------------------------- +// CacheContinuation static member functions +//----------------------------------------------------------------- + +/////////////////////////////////////////////////////////////////////// +// cacheContAllocator_alloc() +/////////////////////////////////////////////////////////////////////// +CacheContinuation * +CacheContinuation::cacheContAllocator_alloc() +{ + return cacheContAllocator.alloc(); +} + + +/////////////////////////////////////////////////////////////////////// +// cacheContAllocator_free() +/////////////////////////////////////////////////////////////////////// +void +CacheContinuation::cacheContAllocator_free(CacheContinuation * c) +{ + ink_assert(c->magicno == (int) MagicNo); +// ink_assert(!c->cache_op_ClusterFunction); + c->magicno = -1; +#ifdef ENABLE_TIME_TRACE + c->start_time = 0; +#endif + c->free(); + c->mutex = NULL; + // FIX ME. ajitb 12/21/99 + // Compiler bug in CC: WorkShop Compilers 5.0 98/12/15 C++ 5.0 + // Does not accept assignment of ((Continuation *) NULL) + { + Continuation *temp = NULL; + c->action = temp; + } + c->tunnel_mutex = NULL; + cacheContAllocator.free(c); +} + +///////////////////////////////////////////////////////////////////////// +// callback_failure() +// Post error completion using a continuation. +///////////////////////////////////////////////////////////////////////// +Action * +CacheContinuation::callback_failure(Action * a, int result, int err, CacheContinuation * this_cc) +{ + CacheContinuation *cc; + if (!this_cc) { + cc = cacheContAllocator_alloc(); + cc->mutex = a->mutex; + cc->action = *a; + + } else { + cc = this_cc; + } + cc->result = result; + cc->result_error = err; + SET_CONTINUATION_HANDLER(cc, (CacheContHandler) + & CacheContinuation::callbackEvent); + eventProcessor.schedule_imm(cc, ET_CACHE_CONT_SM); + return &cc->action; +} + +/////////////////////////////////////////////////////////////////////// +// callbackEvent() +// Invoke callback and deallocate continuation. +/////////////////////////////////////////////////////////////////////// +int +CacheContinuation::callbackEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + if (!action.cancelled) + action.continuation->handleEvent(result, (void *)(intptr_t)result_error); + cacheContAllocator_free(this); + return EVENT_DONE; +} + +//------------------------------------------------------------------ +// File static functions +//------------------------------------------------------------------ + +//////////////////////////////////////////////////////////////////////// +// find_cache_continuation() +// Find a currently pending cache continuation expecting a response. +// Requires taking the lock on the remoteCacheContQueueMutex first. +//////////////////////////////////////////////////////////////////////// +static CacheContinuation * +find_cache_continuation(unsigned int seq_number, unsigned int from_ip) +{ + unsigned int hash = FOLDHASH(from_ip, seq_number); + CacheContinuation *c = NULL; + CacheContinuation *lastc = NULL; + for (c = (CacheContinuation *) remoteCacheContQueue[hash].head; c; c = (CacheContinuation *) c->link.next) { + if (seq_number == c->seq_number && from_ip == c->target_ip) { + if (lastc) { + ink_release_assert(c->link.prev == lastc); + } else { + ink_release_assert(!c->link.prev); + } + break; + } + + lastc = c; + } + return c; +} + +///////////////////////////////////////////////////////////////////////////// +// new_cache_sequence_number() +// Generate unique request sequence numbers +///////////////////////////////////////////////////////////////////////////// +static unsigned int +new_cache_sequence_number() +{ + unsigned int res = 0; + + do { + res = (unsigned int) ink_atomic_increment(&cluster_sequence_number, 1); + } while (!res); + + + + return res; +} + +/***************************************************************************/ +#ifdef OMIT +/***************************************************************************/ +///////////////////////////////////////////////////////////////////////////// +// forwardEvent() +// for migrate-on-demand, make a connection between the +// the node which has the object and the node which should have it. +// +// prepared for either OPEN_READ (from current owner) +// or OPEN_WRITE (from new owner) +///////////////////////////////////////////////////////////////////////////// +int +CacheContinuation::forwardEvent(int event, VConnection * c) +{ + int ret = EVENT_CONT; + cluster_vc = 0; + + cache_read = false; + switch (event) { + default: + ink_assert(!"bad case"); + case CACHE_EVENT_OPEN_WRITE_FAILED: + ret = EVENT_DONE; + break; + case CACHE_EVENT_OPEN_WRITE: + cluster_vc = c; + break; + case CACHE_EVENT_OPEN_READ_FAILED: + cache_read = true; + ret = EVENT_DONE; + break; + case CACHE_EVENT_OPEN_READ: + cache_read = true; + cluster_vc = c; + break; + } + SET_HANDLER((CacheContHandler) & CacheContinuation::forwardWaitEvent); + return ret; +} + +//////////////////////////////////////////////////////////////////////// +// forwardWaitEvent() +// For migrate-on-demand, make a connection as above (forwardEvent) +// second either OPEN_READ or OPEN_WRITE, +// the data for the first is stored in (cluster_vc,cache_read) +//////////////////////////////////////////////////////////////////////// +int +CacheContinuation::forwardWaitEvent(int event, VConnection * c) +{ + int ret = EVENT_CONT; + int res = CACHE_EVENT_OPEN_READ_FAILED; + void *res_data = NULL; + VConnection *vc = NULL; + + switch (event) { + default: + ink_assert(!"bad case"); + case CACHE_EVENT_OPEN_WRITE_FAILED: + case CACHE_EVENT_OPEN_READ_FAILED: + ret = EVENT_DONE; + break; + case CACHE_EVENT_OPEN_WRITE: + case CACHE_EVENT_OPEN_READ: + vc = c; + break; + + } + VConnection *read_vc = (cache_read ? cluster_vc : vc); + VConnection *write_vc = (!cache_read ? cluster_vc : vc); + + res = read_vc ? CACHE_EVENT_OPEN_READ : CACHE_EVENT_OPEN_READ_FAILED; + res_data = read_vc; + + // if the read and write are sucessful, tunnel the read to the write + if (read_vc && write_vc) { + res_data = NEW(new VCTee(read_vc, write_vc, vio)); + if (vio) { // CACHE_EVENT_OPEN_READ_VIO + res = event; + res_data = &((VCTee *) read_vc)->vio; + } + } + // if the read is sucessful return it to the user + // + c->handleEvent(res, res_data); + return ret; +} + +///////////////////////////////////////////////////////////////////// +// tunnelEvent() +// If the reply requires data, tunnel the data from the cache +// to the cluster. +///////////////////////////////////////////////////////////////////// +int +CacheContinuation::tunnelEvent(int event, VConnection * vc) +{ + int ret = EVENT_DONE; + int flen = CacheOpReplyMsg::sizeof_fixedlen_msg(); // include token + int len = 0; + bool read_buf = ((request_opcode == CACHE_OPEN_READ_BUFFER) + || (request_opcode == CACHE_OPEN_READ_BUFFER_LONG)); + ink_release_assert(!read_buf); + + CacheOpReplyMsg rmsg; + CacheOpReplyMsg *msg = &rmsg; + msg->result = result; + msg->seq_number = seq_number; + msg->token = token; + int expect_reply = 1; + + if (event == CLUSTER_EVENT_OPEN) { + if (cache_read) { + if (read_buf) { + ink_assert(have_all_data || (readahead_vio == &((CacheVConnection *) cluster_vc)->vio)); + write_cluster_vc = (ClusterVConnection *) vc; + + if (have_all_data) { + msg->token.clear(); // Tell sender no conn established + } else { + msg->token = token; // Tell sender conn established + setupReadBufTunnel(cluster_vc, vc); + } + + } else { + OneWayTunnel *pOWT = OneWayTunnel::OneWayTunnel_alloc(); + pOWT->init(cluster_vc, vc, NULL, nbytes, this->mutex); + --expect_reply; + } + + //////////////////////////////////////////////////////// + // cache_read requires CacheHTTPInfo in reply message. + //////////////////////////////////////////////////////// + int res; + CacheHTTPInfo *ci; + + if (!cache_vc_info) { + // OPEN_READ case + (void) getObjectSize(cluster_vc, request_opcode, &cache_vc_info); + } + ci = cache_vc_info; + + // Determine data length and allocate + len = ci->marshal_length(); + CacheOpReplyMsg *reply = (CacheOpReplyMsg *) ALLOCA_DOUBLE(flen + len); + + // Initialize reply message header + *reply = *msg; + + // Marshal response data into reply message + res = ci->marshal((char *) reply->moi, len); + ink_assert(res > 0); + + // Make reply message the current message + msg = reply; + + } else { + OneWayTunnel *pOWT = OneWayTunnelAllocator.alloc(); + pOWT->init(vc, cluster_vc, NULL, nbytes, this->mutex); + --expect_reply; + } + ret = EVENT_CONT; + } else { + ink_release_assert(event == CLUSTER_EVENT_OPEN_FAILED); + msg->result = CACHE_EVENT_SET_FAILED(result); + + if (read_buf) { + Debug("cluster_timeout", "unable to make cluster connection2"); + initial_buf = 0; // Do not send data + initial_bufsize = 0; + + if (!have_all_data) { + // Shutdown cache connection and free MIOBuffer + MIOBuffer *mbuf = readahead_vio->buffer.writer(); + cluster_vc->do_io(VIO::CLOSE); + free_MIOBuffer(mbuf); + } + } else { + Debug("cluster_timeout", "unable to make cluster connection2A"); + cluster_vc->do_io(VIO::CLOSE); + } + len = 0 - (int) sizeof(msg->token); + --expect_reply; + } + + int vers = CacheOpReplyMsg::protoToVersion(from->msg_proto_major); + if (vers == CacheOpReplyMsg::CACHE_OP_REPLY_MESSAGE_VERSION) { + if (read_buf) { + // Transmit reply message and object data in same cluster message + clusterProcessor.invoke_remote_data(from, + CACHE_OP_RESULT_CLUSTER_FUNCTION, + (void *) msg, (flen + len), + initial_buf, initial_bufsize, + cluster_vc_channel, &token, + &CacheContinuation::disposeOfDataBuffer, (void *) this, CLUSTER_OPT_STEAL); + + } else { + clusterProcessor.invoke_remote(from, CACHE_OP_RESULT_CLUSTER_FUNCTION, + (void *) msg, (flen + len), CLUSTER_OPT_STEAL); + } + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"tunnelEvent() bad msg version"); + } + if (expect_reply <= 0) + cacheContAllocator_free(this); + return ret; +} + +///////////////////////////////////////////////////////////////////// +// remoteConnectEvent() +// If this was an open, make a connection on this side before +// responding to the user. +///////////////////////////////////////////////////////////////////// +int +CacheContinuation::remoteConnectEvent(int event, VConnection * cvc) +{ + ClusterVConnection *vc = (ClusterVConnection *) cvc; + + if (event == CLUSTER_EVENT_OPEN) { + if (result == CACHE_EVENT_OPEN_READ) { + // Move CacheHTTPInfo reply data into VC + vc->alternate = this->ic_new_info; + this->ic_new_info.clear(); + } + callback_user(result, vc); + return EVENT_CONT; + } else { + Debug("cluster_cache", "unable to make cluster connection"); + callback_user(CACHE_EVENT_SET_FAILED(result), vc); + return EVENT_DONE; + } +} + +/***************************************************************************/ +#endif // OMIT +/***************************************************************************/ + +// End of ClusterCache.cc diff --git a/iocore/cluster/ClusterConfig.cc b/iocore/cluster/ClusterConfig.cc new file mode 100644 index 00000000..5baab1b8 --- /dev/null +++ b/iocore/cluster/ClusterConfig.cc @@ -0,0 +1,497 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterConfig.cc +****************************************************************************/ + +#include "P_Cluster.h" +// updated from the cluster port configuration variable +int cluster_port = DEFAULT_CLUSTER_PORT_NUMBER; + +ClusterAccept::ClusterAccept(int *port, int send_bufsize, int recv_bufsize) + : Continuation(0), + p_cluster_port(port), + socket_send_bufsize(send_bufsize), + socket_recv_bufsize(recv_bufsize), + socket_opt_flags(0), + current_cluster_port(-1), + accept_action(0), + periodic_event(0) +{ + mutex = new_ProxyMutex(); + SET_HANDLER(&ClusterAccept::ClusterAcceptEvent); +} + +ClusterAccept::~ClusterAccept() +{ + mutex = 0; +} + +void +ClusterAccept::Init() +{ + // Setup initial accept by simulating EVENT_INTERVAL + // where cluster accept port has changed. + + current_cluster_port = ~*p_cluster_port; + ClusterAcceptEvent(EVENT_INTERVAL, 0); + + // Setup periodic event to handle changing cluster accept port. + periodic_event = eventProcessor.schedule_every(this, HRTIME_SECONDS(60)); +} + +void +ClusterAccept::ShutdownDelete() +{ + MUTEX_TRY_LOCK(lock, this->mutex, this_ethread()); + if (!lock) { + eventProcessor.schedule_imm(this, ET_CALL); + return; + } + // Kill all events and delete. + if (accept_action) { + accept_action->cancel(); + accept_action = 0; + } + if (periodic_event) { + periodic_event->cancel(); + periodic_event = 0; + } + delete this; +} + +int +ClusterAccept::ClusterAcceptEvent(int event, void *data) +{ + switch (event) { + case EVENT_IMMEDIATE: + { + ShutdownDelete(); + return EVENT_DONE; + } + case EVENT_INTERVAL: + { + int cluster_port = *p_cluster_port; + + if (cluster_port != current_cluster_port) { + // Configuration changed cluster port, redo accept on new port. + if (accept_action) { + accept_action->cancel(); + accept_action = 0; + } + NetProcessor::AcceptOptions opt; + opt.recv_bufsize = socket_recv_bufsize; + opt.send_bufsize = socket_send_bufsize; + opt.etype = ET_CLUSTER; + opt.port = cluster_port; + opt.domain = AF_INET; + accept_action = netProcessor.main_accept(this, NO_FD, + NULL, NULL, + false, false, opt); + if (!accept_action) { + Warning("Unable to accept cluster connections on port: %d", cluster_port); + } else { + current_cluster_port = cluster_port; + } + } + return EVENT_CONT; + } + case NET_EVENT_ACCEPT: + { + ClusterAcceptMachine((NetVConnection *) data); + return EVENT_DONE; + } + default: + { + Warning("ClusterAcceptEvent: received unknown event %d", event); + return EVENT_DONE; + } + } // End of switch +} + +int +ClusterAccept::ClusterAcceptMachine(NetVConnection * NetVC) +{ + // Validate remote IP address. + unsigned int remote_ip = NetVC->get_remote_ip(); + MachineList *mc = the_cluster_machines_config(); + + if (mc && !mc->find(remote_ip)) { + Note("Illegal cluster connection from %u.%u.%u.%u", DOT_SEPARATED(remote_ip)); + NetVC->do_io(VIO::CLOSE); + return 0; + } + + Debug(CL_NOTE, "Accepting machine %u.%u.%u.%u", DOT_SEPARATED(remote_ip)); + ClusterHandler *ch = NEW(new ClusterHandler); + ch->machine = NEW(new ClusterMachine(NULL, remote_ip)); + ch->ip = remote_ip; + ch->net_vc = NetVC; + eventProcessor.schedule_imm(ch, ET_CLUSTER); + return 1; +} + +static void +make_cluster_connections(MachineList * l, MachineList * old) +{ + NOWARN_UNUSED(old); + // + // Connect to all new machines. + // + uint32_t ip = this_cluster_machine()->ip; + + if (l) { + for (int i = 0; i < l->n; i++) +#ifdef LOCAL_CLUSTER_TEST_MODE + if (ip < l->machine[i].ip || (ip == l->machine[i].ip && (cluster_port < l->machine[i].port))) +#else + if (ip < l->machine[i].ip) +#endif + clusterProcessor.connect(l->machine[i].ip, l->machine[i].port); + } +} + +int +machine_config_change(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data); + NOWARN_UNUSED(data_type); + // Handle changes to the cluster.config or machines.config + // file. cluster.config is the list of machines in the + // cluster proper ( in the cluster hash table ). machines.config + // is the list of machines which communicate with the cluster. + // This may include front-end load redirectors, machines going + // up or coming down etc. + // + char *filename = (char *) data.rec_string; + MachineList *l = read_MachineList(filename); + MachineList *old = NULL; +#ifdef USE_SEPARATE_MACHINE_CONFIG + switch ((int) cookie) { + case MACHINE_CONFIG: + old = machines_config; + machines_config = l; + break; + case CLUSTER_CONFIG: + old = cluster_config; + cluster_config = l; + make_cluster_connections(l, old); + break; + } +#else + (void) cookie; + old = cluster_config; + machines_config = l; + cluster_config = l; + make_cluster_connections(l, old); +#endif + if (old) + free_MachineList(old); + return 0; +} + +void +do_machine_config_change(void *d, const char *s) +{ + char cluster_config_filename[PATH_NAME_MAX] = ""; + IOCORE_ReadConfigString(cluster_config_filename, s, sizeof(cluster_config_filename) - 1); + RecData data; + data.rec_string = cluster_config_filename; + machine_config_change(s, RECD_STRING, data, d); +} + +/*************************************************************************/ +// ClusterConfiguration member functions (Public Class) +/*************************************************************************/ +ClusterConfiguration::ClusterConfiguration():n_machines(0), changed(0) +{ + memset(machines, 0, sizeof(machines)); + memset(hash_table, 0, sizeof(hash_table)); +} + +/*************************************************************************/ +// ConfigurationContinuation member functions (Internal Class) +/*************************************************************************/ +struct ConfigurationContinuation; +typedef int (ConfigurationContinuation::*CfgContHandler) (int, void *); +struct ConfigurationContinuation: public Continuation +{ + ClusterConfiguration *c; + ClusterConfiguration *prev; + + int + zombieEvent(int event, Event * e) + { + NOWARN_UNUSED(event); + prev->link.next = NULL; // remove that next pointer + SET_HANDLER((CfgContHandler) & ConfigurationContinuation::dieEvent); + e->schedule_in(CLUSTER_CONFIGURATION_ZOMBIE); + return EVENT_CONT; + } + + int + dieEvent(int event, Event * e) + { + (void) event; + (void) e; + delete c; + delete this; + return EVENT_DONE; + } + + ConfigurationContinuation(ClusterConfiguration * cc, ClusterConfiguration * aprev) + : Continuation(NULL), c(cc), prev(aprev) { + mutex = new_ProxyMutex(); + SET_HANDLER((CfgContHandler) & ConfigurationContinuation::zombieEvent); + } +}; + +static void +free_configuration(ClusterConfiguration * c, ClusterConfiguration * prev) +{ + // + // Delete the configuration after a time. + // The problem is that configurations change infrequently, and + // are used in different threads, so reference counts are + // relatively difficult and expensive. The solution I have + // chosen is to simply delete the object after some (very long) + // time after it has ceased to be accessable. + // + eventProcessor.schedule_in(NEW(new ConfigurationContinuation(c, prev)), CLUSTER_CONFIGURATION_TIMEOUT, ET_CALL); +} + +ClusterConfiguration * +configuration_add_machine(ClusterConfiguration * c, ClusterMachine * m) +{ + // Build a new cluster configuration with the new machine. + // Machines are stored in ip sorted order. + // + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + int i = 0; + ClusterConfiguration *cc = NEW(new ClusterConfiguration(*c)); + + // Find the place to insert this new machine + // + for (i = 0; i < cc->n_machines; i++) { + if (cc->machines[i]->ip > m->ip) + break; + } + + // Move the other machines out of the way + // + for (int j = cc->n_machines - 1; j >= i; j--) + cc->machines[j + 1] = cc->machines[j]; + + // Insert it + // + cc->machines[i] = m; + cc->n_machines++; + + cc->link.next = c; + cc->changed = ink_get_hrtime(); + ink_assert(cc->n_machines < CLUSTER_MAX_MACHINES); + + build_cluster_hash_table(cc); + INK_MEMORY_BARRIER; // commit writes before freeing old hash table + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONFIGURATION_CHANGES_STAT); + + free_configuration(c, cc); + return cc; +} + +ClusterConfiguration * +configuration_remove_machine(ClusterConfiguration * c, ClusterMachine * m) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + // + // Build a new cluster configuration without a machine + // + ClusterConfiguration *cc = NEW(new ClusterConfiguration(*c)); + // + // remove m and move others down + // + for (int i = 0; i < cc->n_machines - 1; i++) + if (m == cc->machines[i]) + m = cc->machines[i] = cc->machines[i + 1]; + cc->n_machines--; + + ink_assert(cc->n_machines > 0); + + cc->link.next = c; + cc->changed = ink_get_hrtime(); + + build_cluster_hash_table(cc); + INK_MEMORY_BARRIER; // commit writes before freeing old hash table + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONFIGURATION_CHANGES_STAT); + + free_configuration(c, cc); + return cc; +} + +/*************************************************************************/ +// Exported functions +/*************************************************************************/ + +// +// cluster_machine_depth_list() +// Return a machine list based on the given hash which is ordered from +// now to the past. Returned list contains no duplicates and depth_list[0] +// entry (current configuration) is always valid. Entries following +// depth_list[0] are considered online. +// Returns 0 on Success else non-zero on error. +// +int +cluster_machine_depth_list(unsigned int hash, ClusterMachine ** depth_list, int depth_list_size) +{ + NOWARN_UNUSED(depth_list_size); + int n = 0; + ClusterConfiguration *cc = this_cluster()->current_configuration(); + ClusterMachine *m = cc->machine_hash(hash); + + depth_list[n++] = m; + cc = cc->link.next; + + while (!cc && n < (CONFIGURATION_HISTORY_PROBE_DEPTH + 1)) { + m = cc->machine_hash(hash); + + if (m->dead || machine_in_vector(m, depth_list, n)) { + depth_list[n++] = (ClusterMachine *) 0; // duplicate or offline + } else { + depth_list[n++] = m; // unique valid online entry + } + cc = cc->link.next; + } + return 0; // Success +} + +// +// cluster_machine_at_depth() +// Find a machine at a particular depth into the past. +// We don't want to probe the current machine or machines +// we have probed before, so we store a list of "past_probes". +// If probe_depth and past_probes are NULL we only want the +// owner (machine now as opposed to in the past). +// +ClusterMachine * +cluster_machine_at_depth(unsigned int hash, int *pprobe_depth, ClusterMachine ** past_probes) +{ +#ifdef CLUSTER_TOMCAT + if (!cache_clustering_enabled) + return NULL; +#endif + ClusterConfiguration * + cc = this_cluster()->current_configuration(); + ClusterConfiguration * + next_cc = cc; + ink_hrtime now = ink_get_hrtime(); + int fake_probe_depth = 0; + int &probe_depth = pprobe_depth ? (*pprobe_depth) : fake_probe_depth; + int tprobe_depth = probe_depth; + +#ifdef CLUSTER_TEST + if (cc->n_machines > 1) { + for (int i = 0; i < cc->n_machines; ++i) { + if (cc->machines[i] != this_cluster_machine()) { + return cc->machines[i]; + } + } + } +#endif // CLUSTER_TEST + + while (1) { + // If we are out of our depth, fail + // + if (probe_depth > CONFIGURATION_HISTORY_PROBE_DEPTH) + break; + + // If there is no configuration, fail + // + if (!cc || !next_cc) + break; + + cc = next_cc; + next_cc = next_cc->link.next; + + // Find the correct configuration + // + if (tprobe_depth) { + if (cc->changed > (now + CLUSTER_CONFIGURATION_TIMEOUT)) + break; + tprobe_depth--; + continue; + } + + ClusterMachine * + m = cc->machine_hash(hash); + + // If it is not this machine, or a machine we have done before + // and one that is still up, try again + // + bool + ok = !(m == this_cluster_machine() || (past_probes && machine_in_vector(m, past_probes, probe_depth)) || m->dead); + + // Store the all but the last probe, so that we never return + // the same machine + // + if (past_probes && probe_depth < CONFIGURATION_HISTORY_PROBE_DEPTH) + past_probes[probe_depth] = m; + probe_depth++; + + if (!ok) { + if (!pprobe_depth) + break; // don't go down if we don't have a depth + continue; + } + + return m; + } + return NULL; +} + +// +// initialize_thread_for_cluster() +// This is not required since we have a separate handler +// for each machine-machine pair, the pointers to which are +// stored in the ClusterMachine structures +// +void +initialize_thread_for_cluster(EThread * e) +{ + (void) e; +} + +/*************************************************************************/ +// Cluster member functions (Public Class) +/*************************************************************************/ +Cluster::Cluster() +{ +} + +// End of ClusterConfig.cc diff --git a/iocore/cluster/ClusterHandler.cc b/iocore/cluster/ClusterHandler.cc new file mode 100644 index 00000000..d5aec228 --- /dev/null +++ b/iocore/cluster/ClusterHandler.cc @@ -0,0 +1,3111 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterHandler.cc +****************************************************************************/ + +#define DEFINE_CLUSTER_FUNCTIONS +#include "P_Cluster.h" + +/*************************************************************************/ +// Global Data +/*************************************************************************/ +// Initialize clusterFunction[] size +int SIZE_clusterFunction = SIZE(clusterFunction); + +// hook for testing +ClusterFunction *ptest_ClusterFunction = NULL; + +// global bit buckets for closed channels +static char channel_dummy_input[DEFAULT_MAX_BUFFER_SIZE]; +char channel_dummy_output[DEFAULT_MAX_BUFFER_SIZE]; + +// outgoing control continuations +ClassAllocator outControlAllocator("outControlAllocator"); + +// incoming control descriptors +ClassAllocator inControlAllocator("inControlAllocator"); + +static int dump_msgs = 0; + +///////////////////////////////////////// +// VERIFY_PETERS_DATA support code +///////////////////////////////////////// +#ifdef VERIFY_PETERS_DATA +#define DO_VERIFY_PETERS_DATA(_p,_l) verify_peters_data(_p,_l) +#else +#define DO_VERIFY_PETERS_DATA(_p,_l) +#endif + +void +verify_peters_data(char *ap, int l) +{ + unsigned char *p = (unsigned char *) ap; + for (int i = 0; i < l - 1; i++) { + unsigned char x1 = p[i]; + unsigned char x2 = p[i + 1]; + x1 += 1; + if (x1 != x2) { + fprintf(stderr, "verify peter's data failed at %d\n", i); + break; + } + } +} + +/*************************************************************************/ +// ClusterHandler member functions (Internal Class) +/*************************************************************************/ +// +// Overview: +// In a steady state cluster environment, all cluster nodes have an +// established TCP socket connection to each node in the cluster. +// An instance of the class ClusterHandler exists for each known node +// in the cluster. All specific node-node data/state is encapsulated +// by this class. +// +// ClusterHandler::mainClusterEvent() is the key periodic event which +// drives the read/write action over the node-node socket connection. +// A high level overview of ClusterHandler::mainClusterEvent() action is +// as follows: +// 1) Perform cluster interconnect load monitoring functions. +// If interconnect is overloaded, convert all remote cluster +// operations to proxy only. +// 2) Process delayed reads. Delayed read refers to data associated +// with a VC (Virtual Connection) which resides in an intermediate +// buffer and is unknown to the VC. This is required in cases +// where we are unable to acquire the VC mutex at the time of the +// read from the node-node socket. Delayed read processing +// consists of acquiring the VC mutex and moving the data into the +// VC and posting read completion. +// 3) Process pending read data on the node-node TCP socket. In the +// typical case, read processing is performed using three read +// operations. The actions are as follows: +// a) read the fixed size message header +// (struct ClusterMsgHeader) consisting of the +// number of data descriptors and the size of the inline +// control messages following the data descriptors. +// b) Setup buffer for data descriptors and inline control +// messages and issue read. +// c) Setup read buffers and acquire applicable locks for +// VC/Control data described by data descriptors and issue +// read. +// d) Perform read completion actions on control and VC data. +// e) Free VC locks +// 4) Process write bank data. Write bank data is outstanding data +// which we were unable to push out in the last write over the +// node-node TCP socket. Write bank data must be successfully pushed +// before performing any additional write processing. +// 5) Build a write message consisting of the following data: +// 1) Write data for a Virtual Connection in the current write data +// bucket (write_vcs) +// 2) Virtual Connection free space for VCs in the current read +// data bucket (read_vcs) +// 3) Control message data (outgoing_control) +// 6) Push write data +// +// Thread stealing refers to executing the control message processing +// portion of mainClusterEvent() by a thread not associated with the +// periodic event. This a mechanism to avoid the latency on control +// messages by allowing them to be pushed immediately. +// +/*************************************************************************/ + +ClusterHandler::ClusterHandler() + : net_vc(0), + thread(0), + ip(0), + port(0), + hostname(NULL), + machine(NULL), + ifd(-1), + active(false), + on_stolen_thread(false), + n_channels(0), + channels(NULL), + channel_data(NULL), + connector(false), + cluster_connect_state(ClusterHandler::CLCON_INITIAL), + needByteSwap(false), + configLookupFails(0), + cluster_periodic_event(0), + read(this, true), + write(this, false), + current_time(0), + last(0), + last_report(0), + n_since_last_report(0), + last_cluster_op_enable(0), + last_trace_dump(0), + clm(0), + disable_remote_cluster_ops(0), + pw_write_descriptors_built(0), + pw_freespace_descriptors_built(0), + pw_controldata_descriptors_built(0), pw_time_expired(0), started_on_stolen_thread(false), control_message_write(false) +#ifdef CLUSTER_STATS + , + _vc_writes(0), + _vc_write_bytes(0), + _control_write_bytes(0), + _dw_missed_lock(0), + _dw_not_enabled(0), + _dw_wait_remote_fill(0), + _dw_no_active_vio(0), + _dw_not_enabled_or_no_write(0), + _dw_set_data_pending(0), + _dw_no_free_space(0), + _fw_missed_lock(0), + _fw_not_enabled(0), + _fw_wait_remote_fill(0), + _fw_no_active_vio(0), + _fw_not_enabled_or_no_read(0), + _process_read_calls(0), + _n_read_start(0), + _n_read_header(0), + _n_read_await_header(0), + _n_read_setup_descriptor(0), + _n_read_descriptor(0), + _n_read_await_descriptor(0), + _n_read_setup_data(0), + _n_read_data(0), + _n_read_await_data(0), + _n_read_post_complete(0), + _n_read_complete(0), + _process_write_calls(0), + _n_write_start(0), + _n_write_setup(0), _n_write_initiate(0), _n_write_await_completion(0), _n_write_post_complete(0), _n_write_complete(0) +#endif +{ +#ifdef MSG_TRACE + t_fd = fopen("msgtrace.log", "w"); +#endif + // we need to lead by at least 1 + + min_priority = 1; + SET_HANDLER((ClusterContHandler) & ClusterHandler::startClusterEvent); + + mutex = new_ProxyMutex(); + OutgoingControl oc; + int n; + for (n = 0; n < CLUSTER_CMSG_QUEUES; ++n) { + ink_atomiclist_init(&outgoing_control_al[n], "OutGoingControlQueue", (char *) &oc.link.next - (char *) &oc); + } + + IncomingControl ic; + ink_atomiclist_init(&external_incoming_control, + "ExternalIncomingControlQueue", (char *) &ic.link.next - (char *) &ic); + + ClusterVConnection ivc; + ink_atomiclist_init(&external_incoming_open_local, + "ExternalIncomingOpenLocalQueue", (char *) &ivc.link.next - (char *) &ivc); + memset((char *) &callout_cont[0], 0, sizeof(callout_cont)); + memset((char *) &callout_events[0], 0, sizeof(callout_events)); +} + +ClusterHandler::~ClusterHandler() +{ + if (net_vc) { + net_vc->do_io(VIO::CLOSE); + net_vc = 0; + } + if (machine) + free_ClusterMachine(machine); + machine = NULL; + if (hostname) + xfree(hostname); + hostname = NULL; + if (channels) + xfree(channels); + channels = NULL; + if (channel_data) { + for (int i = 0; i < n_channels; ++i) { + if (channel_data[i]) { + xfree(channel_data[i]); + channel_data[i] = 0; + } + } + xfree(channel_data); + channel_data = NULL; + } + if (read_vcs) + delete[]read_vcs; + read_vcs = NULL; + + if (write_vcs) + delete[]write_vcs; + write_vcs = NULL; + + if (clm) { + delete clm; + clm = NULL; + } +#ifdef CLUSTER_STATS + message_blk = 0; +#endif +} + +void +ClusterHandler::close_ClusterVConnection(ClusterVConnection * vc) +{ + // + // Close down a ClusterVConnection + // + if (vc->inactivity_timeout) + vc->inactivity_timeout->cancel(vc); + if (vc->active_timeout) + vc->active_timeout->cancel(vc); + if (vc->read.queue) + ClusterVC_remove_read(vc); + if (vc->write.queue) + ClusterVC_remove_write(vc); + vc->read.vio.mutex = NULL; + vc->write.vio.mutex = NULL; + + ink_assert(!vc->read_locked); + ink_assert(!vc->write_locked); + int channel = vc->channel; + free_channel(vc); + + if (vc->byte_bank_q.head) { + delayed_reads.remove(vc); + + // Deallocate byte bank descriptors + ByteBankDescriptor *d; + while ((d = vc->byte_bank_q.dequeue())) { + ByteBankDescriptor::ByteBankDescriptor_free(d); + } + } + vc->read_block = 0; + + ink_assert(!vc->write_list); + ink_assert(!vc->write_list_tail); + ink_assert(!vc->write_list_bytes); + ink_assert(!vc->write_bytes_in_transit); + + if (((!vc->remote_closed && !vc->have_all_data) || (vc->remote_closed == FORCE_CLOSE_ON_OPEN_CHANNEL)) && vc->machine) { + + CloseMessage msg; + int vers = CloseMessage::protoToVersion(vc->machine->msg_proto_major); + void *data; + int len; + + if (vers == CloseMessage::CLOSE_CHAN_MESSAGE_VERSION) { + msg.channel = channel; + msg.status = (vc->remote_closed == FORCE_CLOSE_ON_OPEN_CHANNEL) ? FORCE_CLOSE_ON_OPEN_CHANNEL : vc->closed; + msg.lerrno = vc->lerrno; + msg.sequence_number = vc->token.sequence_number; + data = (void *) &msg; + len = sizeof(CloseMessage); + + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"close_ClusterVConnection() bad msg version"); + } + clusterProcessor.invoke_remote(vc->machine, CLOSE_CHANNEL_CLUSTER_FUNCTION, data, len); + } + ink_hrtime now = ink_get_hrtime(); + CLUSTER_DECREMENT_DYN_STAT(CLUSTER_CONNECTIONS_OPEN_STAT); + if (!local_channel(channel)) { + CLUSTER_SUM_DYN_STAT(CLUSTER_CON_TOTAL_TIME_STAT, now - vc->start_time); + CLUSTER_SUM_DYN_STAT(CLUSTER_REMOTE_CONNECTION_TIME_STAT, now - vc->start_time); + } + clusterVCAllocator_free(vc); +} + +inline bool +ClusterHandler::vc_ok_write(ClusterVConnection * vc) +{ + return (((vc->closed > 0) + && (vc->write_list || vc->write_bytes_in_transit)) || + (!vc->closed && vc->write.enabled && vc->write.vio.op == VIO::WRITE && vc->write.vio.buffer.mbuf)); +} + +inline bool +ClusterHandler::vc_ok_read(ClusterVConnection * vc) +{ + return (!vc->closed && vc->read.vio.op == VIO::READ && vc->read.vio.buffer.mbuf); +} + +void +ClusterHandler::close_free_lock(ClusterVConnection * vc, ClusterVConnState * s) +{ + Ptr m(s->vio.mutex); + if (s == &vc->read) { + if ((ProxyMutex *) vc->read_locked) + MUTEX_UNTAKE_LOCK(vc->read_locked, thread); + vc->read_locked = NULL; + } else { + if ((ProxyMutex *) vc->write_locked) + MUTEX_UNTAKE_LOCK(vc->write_locked, thread); + vc->write_locked = NULL; + } + close_ClusterVConnection(vc); +} + +bool ClusterHandler::build_data_vector(char *d, int len, bool read_flag) +{ + // Internal interface to general network i/o facility allowing + // single vector read/write to static data buffer. + + ClusterState & s = (read_flag ? read : write); + ink_assert(d); + ink_assert(len); + ink_assert(s.iov); + + s.msg.count = 1; + s.iov[0].iov_base = 0; + s.iov[0].iov_len = len; + s.block[0] = new_IOBufferBlock(); + s.block[0]->set(new_constant_IOBufferData(d, len)); + + if (read_flag) { + // Make block write_avail == len + s.block[0]->_buf_end = s.block[0]->end() + len; + } else { + // Make block read_avail == len + s.block[0]->fill(len); + } + + s.to_do = len; + s.did = 0; + s.n_iov = 1; + + return true; +} + +bool ClusterHandler::build_initial_vector(bool read_flag) +{ + // + // Build initial read/write struct iovec and corresponding IOBufferData + // structures from the given struct descriptor(s). + // Required vector adjustments for partial i/o conditions is handled + // by adjust_vector(). + // + /////////////////////////////////////////////////////////////////// + // Descriptor to struct iovec layout + /////////////////////////////////////////////////////////////////// + // Write iovec[] layout + // iov[0] ----> struct ClusterMsgHeader + // iov[1] ----> struct descriptor [count] + // char short_control_messages[control_bytes] + // + // iov[2] ----> struct descriptor data (element #1) + // ...... + // iov[2+count] ----> struct descriptor data (element #count) + // + /////////////////////////////////////////////////////////////////// + // Read iovec[] layout phase #1 read + // iov[0] ----> struct ClusterMsgHeader + /////////////////////////////////////////////////////////////////// + // Read iovec[] layout phase #2 read + // iov[0] ----> struct descriptor[count] + // char short_control_messages[control_bytes] + /////////////////////////////////////////////////////////////////// + // Read iovec[] layout phase #3 read + // iov[0] ----> struct descriptor data (element #1) + // ...... + // iov[count-1] ----> struct descriptor data (element #count) + /////////////////////////////////////////////////////////////////// + int i, n; + // This isn't used. + // MIOBuffer *w; + + ink_hrtime now = ink_get_hrtime(); + ClusterState & s = (read_flag ? read : write); + OutgoingControl *oc = s.msg.outgoing_control.head; + IncomingControl *ic = incoming_control.head; + int new_n_iov = 0; + int to_do = 0; + int len; + + ink_assert(s.iov); + + if (!read_flag) { + ////////////////////////////////////////////////////////////////////// + // Setup vector for write of header, descriptors and control data + ////////////////////////////////////////////////////////////////////// + len = sizeof(ClusterMsgHeader) + (s.msg.count * sizeof(Descriptor)) + s.msg.control_bytes; + s.iov[new_n_iov].iov_base = 0; + s.iov[new_n_iov].iov_len = len; + s.block[new_n_iov] = s.msg.get_block_header(); + + // Make read_avail == len + s.block[new_n_iov]->fill(len); + + to_do += len; + ++new_n_iov; + + } else { + if (s.msg.state == 0) { + //////////////////////////////////// + // Setup vector for read of header + //////////////////////////////////// + len = sizeof(ClusterMsgHeader); + s.iov[new_n_iov].iov_base = 0; + s.iov[new_n_iov].iov_len = len; + s.block[new_n_iov] = s.msg.get_block_header(); + + // Make write_avail == len + s.block[new_n_iov]->_buf_end = s.block[new_n_iov]->end() + len; + + to_do += len; + ++new_n_iov; + + } else if (s.msg.state == 1) { + ///////////////////////////////////////////////////////// + // Setup vector for read of Descriptors+control data + ///////////////////////////////////////////////////////// + len = (s.msg.count * sizeof(Descriptor)) + s.msg.control_bytes; + s.iov[new_n_iov].iov_base = 0; + s.iov[new_n_iov].iov_len = len; + s.block[new_n_iov] = s.msg.get_block_descriptor(); + + // Make write_avail == len + s.block[new_n_iov]->_buf_end = s.block[new_n_iov]->end() + len; + + to_do += s.iov[new_n_iov].iov_len; + ++new_n_iov; + } + } + + //////////////////////////////////////////////////////////// + // Build vector for data section of the cluster message. + // For read, we only do this if we are in data phase + // of the read (msg.state == 2) + ////////////////////////////////////////////////////////////// + // Note: We are assuming that free space descriptors follow + // the data descriptors. + ////////////////////////////////////////////////////////////// + for (i = 0; i<(read_flag ? ((s.msg.state>= 2) ? s.msg.count : 0) + : s.msg.count); i++) { + if (s.msg.descriptor[i].type == CLUSTER_SEND_DATA) { + /////////////////////////////////// + // Control channel data + /////////////////////////////////// + if (s.msg.descriptor[i].channel == CLUSTER_CONTROL_CHANNEL) { + if (read_flag) { + /////////////////////// + // Incoming Control + /////////////////////// + if (!ic) { + ic = IncomingControl::alloc(); + ic->recognized_time = now; + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CTRL_MSGS_RECVD_STAT); + ic->len = s.msg.descriptor[i].length; + ic->alloc_data(); + if (!ic->fast_data()) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_SLOW_CTRL_MSGS_RECVD_STAT); + } + // Mark message data as invalid + *((uint32_t *) ic->data) = UNDEFINED_CLUSTER_FUNCTION; + incoming_control.enqueue(ic); + } + s.iov[new_n_iov].iov_base = 0; + s.iov[new_n_iov].iov_len = ic->len; + s.block[new_n_iov] = ic->get_block(); + to_do += s.iov[new_n_iov].iov_len; + ++new_n_iov; + ic = (IncomingControl *) ic->link.next; + } else { + /////////////////////// + // Outgoing Control + /////////////////////// + ink_assert(oc); + s.iov[new_n_iov].iov_base = 0; + s.iov[new_n_iov].iov_len = oc->len; + s.block[new_n_iov] = oc->get_block(); + to_do += s.iov[new_n_iov].iov_len; + ++new_n_iov; + oc = (OutgoingControl *) oc->link.next; + } + } else { + /////////////////////////////// + // User channel data + /////////////////////////////// + ClusterVConnection * + vc = channels[s.msg.descriptor[i].channel]; + + if (VALID_CHANNEL(vc) && + (s.msg.descriptor[i].sequence_number) == CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) { + if (read_flag) { + ink_release_assert(!vc->initial_data_bytes); + ///////////////////////////////////// + // Try to get the read VIO mutex + ///////////////////////////////////// + ink_release_assert(!(ProxyMutex *) vc->read_locked); +#ifdef CLUSTER_TOMCAT + if (!vc->read.vio.mutex || + !MUTEX_TAKE_TRY_LOCK_FOR_SPIN(vc->read.vio.mutex, thread, vc->read.vio._cont, READ_LOCK_SPIN_COUNT)) +#else + if (!MUTEX_TAKE_TRY_LOCK_FOR_SPIN(vc->read.vio.mutex, thread, vc->read.vio._cont, READ_LOCK_SPIN_COUNT)) +#endif + { + vc->read_locked = 0; + } else { + vc->read_locked = vc->read.vio.mutex; + } + + /////////////////////////////////////// + // Allocate read data block + /////////////////////////////////////// + if (s.msg.descriptor[i].length) { + vc->iov_map = new_n_iov; + } else { + vc->iov_map = CLUSTER_IOV_NONE; + } + if (vc->pending_remote_fill || vc_ok_read(vc)) { + ////////////////////////////////////////////////////////// + // Initial and subsequent data on open read channel. + // Allocate IOBufferBlock. + ////////////////////////////////////////////////////////// + ink_release_assert(s.msg.descriptor[i].length <= DEFAULT_MAX_BUFFER_SIZE); + vc->read_block = new_IOBufferBlock(); + int64_t index = buffer_size_to_index(s.msg.descriptor[i].length, MAX_BUFFER_SIZE_INDEX); + vc->read_block->alloc(index); + + s.iov[new_n_iov].iov_base = 0; + s.block[new_n_iov] = vc->read_block->clone(); + + } else { + Debug(CL_NOTE, "dumping cluster read data"); + s.iov[new_n_iov].iov_base = 0; + s.block[new_n_iov] = new_IOBufferBlock(); + s.block[new_n_iov]->set(new_constant_IOBufferData(channel_dummy_input, DEFAULT_MAX_BUFFER_SIZE)); + } + + // Make block write_avail == descriptor[].length + s.block[new_n_iov]->_buf_end = s.block[new_n_iov]->end() + s.msg.descriptor[i].length; + + } else { + bool remote_write_fill = (vc->pending_remote_fill && vc->remote_write_block); + // Sanity check, assert we have the lock + if (!remote_write_fill) { + ink_assert((ProxyMutex *) vc->write_locked); + } + if (vc_ok_write(vc) || remote_write_fill) { + if (remote_write_fill) { + s.iov[new_n_iov].iov_base = 0; + ink_release_assert((int) s.msg.descriptor[i].length == bytes_IOBufferBlockList(vc->remote_write_block, 1)); + s.block[new_n_iov] = vc->remote_write_block; + + } else { + s.iov[new_n_iov].iov_base = 0; + ink_release_assert((int) s.msg.descriptor[i].length <= vc->write_list_bytes); + s.block[new_n_iov] = vc->write_list; + vc->write_list = consume_IOBufferBlockList(vc->write_list, (int) s.msg.descriptor[i].length); + vc->write_list_bytes -= (int) s.msg.descriptor[i].length; + vc->write_bytes_in_transit += (int) s.msg.descriptor[i].length; + + vc->write_list_tail = vc->write_list; + while (vc->write_list_tail && vc->write_list_tail->next) + vc->write_list_tail = vc->write_list_tail->next; + } + } else { + Debug(CL_NOTE, "faking cluster write data"); + s.iov[new_n_iov].iov_base = 0; + s.block[new_n_iov] = new_IOBufferBlock(); + s.block[new_n_iov]->set(new_constant_IOBufferData(channel_dummy_output, DEFAULT_MAX_BUFFER_SIZE)); + // Make block read_avail == descriptor[].length + s.block[new_n_iov]->fill(s.msg.descriptor[i].length); + } + } + } else { + // VC has been deleted, need to dump the bits... + s.iov[new_n_iov].iov_base = 0; + s.block[new_n_iov] = new_IOBufferBlock(); + + if (read_flag) { + s.block[new_n_iov]->set(new_constant_IOBufferData(channel_dummy_input, DEFAULT_MAX_BUFFER_SIZE)); + + // Make block write_avail == descriptor[].length + s.block[new_n_iov]->_buf_end = s.block[new_n_iov]->end() + s.msg.descriptor[i].length; + + } else { + s.block[new_n_iov]->set(new_constant_IOBufferData(channel_dummy_output, DEFAULT_MAX_BUFFER_SIZE)); + + // Make block read_avail == descriptor[].length + s.block[new_n_iov]->fill(s.msg.descriptor[i].length); + } + } + s.iov[new_n_iov].iov_len = s.msg.descriptor[i].length; + to_do += s.iov[new_n_iov].iov_len; + ++new_n_iov; + } + } + } + // Release IOBufferBlock references used in previous i/o operation + for (n = new_n_iov; n < MAX_TCOUNT; ++n) { + s.block[n] = 0; + } + + // Initialize i/o state variables + s.to_do = to_do; + s.did = 0; + s.n_iov = new_n_iov; + return true; + + // TODO: This is apparently dead code, I added the #if 0 to avoid compiler + // warnings, but is this really intentional?? +#if 0 + // Release all IOBufferBlock references. + for (n = 0; n < MAX_TCOUNT; ++n) { + s.block[n] = 0; + } + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_OP_DELAYED_FOR_LOCK_STAT); + Debug(CL_WARN, "%s delayed for locks", read_flag ? "read" : "write"); + free_locks(read_flag, i); + return false; +#endif +} + +bool ClusterHandler::get_read_locks() +{ + /////////////////////////////////////////////////////////////////////// + // Reacquire locks for the request setup by build_initial_vector(). + // We are called after each read completion prior to posting completion + /////////////////////////////////////////////////////////////////////// + ClusterState & s = read; + int i, n; + int bytes_processed; + int vec_bytes_remainder; + int iov_done[MAX_TCOUNT]; + + memset((char *) iov_done, 0, sizeof(int) * MAX_TCOUNT); + + // Compute bytes transferred on a per vector basis + bytes_processed = s.did - s.bytes_xfered; // not including bytes in this xfer + + i = -1; + for (n = 0; n < s.n_iov; ++n) { + bytes_processed -= s.iov[n].iov_len; + if (bytes_processed >= 0) { + iov_done[n] = s.iov[n].iov_len; + } else { + iov_done[n] = s.iov[n].iov_len + bytes_processed; + if (i < 0) { + i = n; // note i/o start vector + + // Now at vector where last transfer started, + // make considerations for the last transfer on this vector. + + vec_bytes_remainder = (s.iov[n].iov_len - iov_done[n]); + bytes_processed = s.bytes_xfered; + + bytes_processed -= vec_bytes_remainder; + if (bytes_processed >= 0) { + iov_done[n] = vec_bytes_remainder; + } else { + iov_done[n] = vec_bytes_remainder + bytes_processed; + break; + } + } else { + break; + } + } + } + ink_release_assert(i >= 0); + + // Start lock acquisition at the first vector where we started + // the last read. + // + // Note: We are assuming that free space descriptors follow + // the data descriptors. + + for (; i < s.n_iov; ++i) { + if ((s.msg.descriptor[i].type == CLUSTER_SEND_DATA) + && (s.msg.descriptor[i].channel != CLUSTER_CONTROL_CHANNEL)) { + + // Only user channels require locks + + ClusterVConnection * + vc = channels[s.msg.descriptor[i].channel]; + if (!VALID_CHANNEL(vc) || + ((s.msg.descriptor[i].sequence_number) != + CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) || !vc_ok_read(vc)) { + // Channel no longer valid, lock not needed since we + // already have a reference to the buffer + continue; + } + + ink_assert(!(ProxyMutex *) vc->read_locked); + vc->read_locked = vc->read.vio.mutex; + if (vc->byte_bank_q.head + || !MUTEX_TAKE_TRY_LOCK_FOR_SPIN(vc->read.vio.mutex, thread, vc->read.vio._cont, READ_LOCK_SPIN_COUNT)) { + // Pending byte bank completions or lock acquire failure. + + vc->read_locked = NULL; + continue; + } + // Since we now have the mutex, really see if reads are allowed. + + if (!vc_ok_read(vc)) { + vc->read_locked = NULL; + continue; + } + // Lock acquire success, move read bytes into VC + + int64_t read_avail = vc->read_block->read_avail(); + + if (!vc->pending_remote_fill && read_avail) { + Debug("cluster_vc_xfer", "Deferred fill ch %d 0x%x %d bytes", vc->channel, vc, read_avail); + + vc->read.vio.buffer.writer()->append_block(vc->read_block->clone()); + if (complete_channel_read(read_avail, vc)) { + vc->read_block->consume(read_avail); + } + } + } + } + return true; // success +} + +bool ClusterHandler::get_write_locks() +{ + /////////////////////////////////////////////////////////////////////// + // Reacquire locks for the request setup by build_initial_vector(). + // We are called after the entire write completes prior to + // posting completion. + /////////////////////////////////////////////////////////////////////// + ClusterState & s = write; + int i; + + for (i = 0; i < s.msg.count; ++i) { + if ((s.msg.descriptor[i].type == CLUSTER_SEND_DATA) + && (s.msg.descriptor[i].channel != CLUSTER_CONTROL_CHANNEL)) { + + // Only user channels require locks + + ClusterVConnection * + vc = channels[s.msg.descriptor[i].channel]; + if (!VALID_CHANNEL(vc) || + (s.msg.descriptor[i].sequence_number) != CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) { + // Channel no longer valid, lock not needed since we + // already have a reference to the buffer + continue; + } + ink_assert(!(ProxyMutex *) vc->write_locked); + vc->write_locked = vc->write.vio.mutex; +#ifdef CLUSTER_TOMCAT + if (vc->write_locked && + !MUTEX_TAKE_TRY_LOCK_FOR_SPIN(vc->write.vio.mutex, thread, vc->write.vio._cont, WRITE_LOCK_SPIN_COUNT)) { +#else + if (!MUTEX_TAKE_TRY_LOCK_FOR_SPIN(vc->write.vio.mutex, thread, vc->write.vio._cont, WRITE_LOCK_SPIN_COUNT)) { +#endif + // write lock acquire failed, free all acquired locks and retry later + vc->write_locked = 0; + free_locks(CLUSTER_WRITE, i); + return false; + } + } + } + return true; +} + +void +ClusterHandler::swap_descriptor_bytes() +{ + for (int i = 0; i < read.msg.count; i++) { + read.msg.descriptor[i].SwapBytes(); + } +} + +void +ClusterHandler::process_set_data_msgs() +{ + uint32_t cluster_function_index; + // + // Cluster set_data messages must always be processed ahead of all + // messages and data. By convention, set_data messages (highest priority + // messages) always reside in the beginning of the descriptor + // and small control message structures. + // + + ///////////////////////////////////////////// + // Process small control set_data messages. + ///////////////////////////////////////////// + if (!read.msg.did_small_control_set_data) { + char *p = (char *) &read.msg.descriptor[read.msg.count]; + char *endp = p + read.msg.control_bytes; + while (p < endp) { + if (needByteSwap) { + swap32((uint32_t *) p); // length + swap32((uint32_t *) (p + sizeof(int32_t))); // function code + } + int len = *(int32_t *) p; + cluster_function_index = *(uint32_t *) (p + sizeof(int32_t)); + + if ((cluster_function_index < (uint32_t) SIZE_clusterFunction) + && (cluster_function_index == SET_CHANNEL_DATA_CLUSTER_FUNCTION)) { + clusterFunction[SET_CHANNEL_DATA_CLUSTER_FUNCTION].pfn(machine, p + (2 * sizeof(uint32_t)), len - sizeof(uint32_t)); + // Mark message as processed. + *((uint32_t *) (p + sizeof(uint32_t))) = ~*((uint32_t *) (p + sizeof(uint32_t))); + p += (2 * sizeof(uint32_t)) + (len - sizeof(uint32_t)); + p = (char *) DOUBLE_ALIGN(p); + } else { + // Reverse swap since this message will be reprocessed. + + if (needByteSwap) { + swap32((uint32_t *) p); // length + swap32((uint32_t *) (p + sizeof(int32_t))); // function code + } + break; // End of set_data messages + } + } + read.msg.control_data_offset = p - (char *) &read.msg.descriptor[read.msg.count]; + read.msg.did_small_control_set_data = 1; + } + ///////////////////////////////////////////// + // Process large control set_data messages. + ///////////////////////////////////////////// + if (!read.msg.did_large_control_set_data) { + IncomingControl *ic = incoming_control.head; + + while (ic) { + if (needByteSwap) { + swap32((uint32_t *) ic->data); // function code + } + cluster_function_index = *((uint32_t *) ic->data); + + if ((cluster_function_index < (uint32_t) SIZE_clusterFunction) + && (cluster_function_index == SET_CHANNEL_DATA_CLUSTER_FUNCTION)) { + + char *p = ic->data; + clusterFunction[SET_CHANNEL_DATA_CLUSTER_FUNCTION].pfn(machine, + (void *) (p + sizeof(int32_t)), ic->len - sizeof(int32_t)); + + // Reverse swap since this will be processed again for deallocation. + if (needByteSwap) { + swap32((uint32_t *) p); // length + swap32((uint32_t *) (p + sizeof(int32_t))); // function code + } + // Mark message as processed. + // Defer dellocation until entire read is complete. + *((uint32_t *) p) = ~*((uint32_t *) p); + + ic = (IncomingControl *) ic->link.next; + } else { + // Reverse swap action this message will be reprocessed. + if (needByteSwap) { + swap32((uint32_t *) ic->data); // function code + } + break; + } + } + read.msg.did_large_control_set_data = 1; + } +} + +void +ClusterHandler::process_small_control_msgs() +{ + if (read.msg.did_small_control_msgs) { + return; + } else { + read.msg.did_small_control_msgs = 1; + } + + ink_hrtime now = ink_get_hrtime(); + char *p = (char *) &read.msg.descriptor[read.msg.count] + read.msg.control_data_offset; + char *endp = (char *) &read.msg.descriptor[read.msg.count] + read.msg.control_bytes; + + while (p < endp) { + ///////////////////////////////////////////////////////////////// + // Place non cluster small incoming messages on external + // incoming queue for processing by callout threads. + ///////////////////////////////////////////////////////////////// + if (needByteSwap) { + swap32((uint32_t *) p); // length + swap32((uint32_t *) (p + sizeof(int32_t))); // function code + } + int len = *(int32_t *) p; + p += sizeof(int32_t); + uint32_t cluster_function_index = *(uint32_t *) p; + ink_release_assert(cluster_function_index != SET_CHANNEL_DATA_CLUSTER_FUNCTION); + + if (cluster_function_index >= (uint32_t) SIZE_clusterFunction) { + Warning("1Bad cluster function index (small control)"); + p += len; + + } else if (clusterFunction[cluster_function_index].ClusterFunc) { + ////////////////////////////////////////////////////////////////////// + // Cluster function, can only be processed in ET_CLUSTER thread + ////////////////////////////////////////////////////////////////////// + p += sizeof(uint32_t); + clusterFunction[cluster_function_index].pfn(machine, p, len - sizeof(int32_t)); + p += (len - sizeof(int32_t)); + + } else { + /////////////////////////////////////////////////////// + // Non Cluster function, defer to callout threads + /////////////////////////////////////////////////////// + IncomingControl *ic = IncomingControl::alloc(); + ic->recognized_time = now; + ic->len = len; + ic->alloc_data(); + memcpy(ic->data, p, ic->len); + SetHighBit(&ic->len); // mark as small cntl + ink_atomiclist_push(&external_incoming_control, (void *) ic); + p += len; + } + p = (char *) DOUBLE_ALIGN(p); + } +} + +void +ClusterHandler::process_large_control_msgs() +{ + if (read.msg.did_large_control_msgs) { + return; + } else { + read.msg.did_large_control_msgs = 1; + } + + //////////////////////////////////////////////////////////////// + // Place non cluster large incoming messages on external + // incoming queue for processing by callout threads. + //////////////////////////////////////////////////////////////// + IncomingControl *ic = NULL; + uint32_t cluster_function_index; + + while ((ic = incoming_control.dequeue())) { + if (needByteSwap) { + swap32((uint32_t *) ic->data); // function code + } + cluster_function_index = *((uint32_t *) ic->data); + ink_release_assert(cluster_function_index != SET_CHANNEL_DATA_CLUSTER_FUNCTION); + + if (cluster_function_index == (uint32_t) ~ SET_CHANNEL_DATA_CLUSTER_FUNCTION) { + // SET_CHANNEL_DATA_CLUSTER_FUNCTION already processed. + // Just do memory deallocation. + + if (!clusterFunction[SET_CHANNEL_DATA_CLUSTER_FUNCTION].fMalloced) + ic->freeall(); + continue; + } + + if (cluster_function_index >= (uint32_t) SIZE_clusterFunction) { + Warning("Bad cluster function index (large control)"); + ic->freeall(); + + } else if (clusterFunction[cluster_function_index].ClusterFunc) { + // Cluster message, process in ET_CLUSTER thread + clusterFunction[cluster_function_index].pfn(machine, (void *) (ic->data + sizeof(int32_t)), + ic->len - sizeof(int32_t)); + + // Deallocate memory + if (!clusterFunction[cluster_function_index].fMalloced) + ic->freeall(); + + } else { + // Non Cluster message, process in non ET_CLUSTER thread + ink_atomiclist_push(&external_incoming_control, (void *) ic); + } + } +} + +void +ClusterHandler::process_freespace_msgs() +{ + if (read.msg.did_freespace_msgs) { + return; + } else { + read.msg.did_freespace_msgs = 1; + } + + int i; + // + // unpack CLUSTER_SEND_FREE (VC free space) messages and update + // the free space in the target VC(s). + // + for (i = 0; i < read.msg.count; i++) { + if (read.msg.descriptor[i].type == CLUSTER_SEND_FREE && read.msg.descriptor[i].channel != CLUSTER_CONTROL_CHANNEL) { + int c = read.msg.descriptor[i].channel; + if (c < n_channels && VALID_CHANNEL(channels[c]) && + (CLUSTER_SEQUENCE_NUMBER(channels[c]->token.sequence_number) == read.msg.descriptor[i].sequence_number)) { + // + // VC received freespace message, move it to the + // current bucket, since it may have data to + // write (WRITE_VC_PRIORITY). + // + channels[c]->remote_free = read.msg.descriptor[i].length; + ClusterVConnState *ns = &channels[c]->write; + if (ns->queue) { + ClusterVConnection *vc = channels[c]; + ClusterVC_remove_write(vc); + cluster_set_priority(this, ns, 1); + Debug(CL_PROTO, "(%d) upping write priority %d read %d free %d", + c, ns->priority, channels[c]->read.priority, channels[c]->remote_free); + ClusterVC_enqueue_write(write_vcs[cur_vcs], vc); + } + } + } + } +} + +void +ClusterHandler::add_to_byte_bank(ClusterVConnection * vc) +{ + ByteBankDescriptor *bb_desc = ByteBankDescriptor::ByteBankDescriptor_alloc(vc->read_block); + bool pending_byte_bank_completion = vc->byte_bank_q.head ? true : false; + + // Put current byte bank descriptor on completion list + vc->byte_bank_q.enqueue(bb_desc); + + // Start byte bank completion action if not active + if (!pending_byte_bank_completion) { + ClusterVC_remove_read(vc); + delayed_reads.push(vc); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_LEVEL1_BANK_STAT); + } else { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_MULTILEVEL_BANK_STAT); + } + vc->read_block = 0; +} + +void +ClusterHandler::update_channels_read() +{ + // + // Update channels from which data has been read. + // + int i; + int len; + // This isn't used. + // int nread = read.bytes_xfered; + + process_set_data_msgs(); + + // + // update the ClusterVConnections + // + for (i = 0; i < read.msg.count; i++) { + if (read.msg.descriptor[i].type == CLUSTER_SEND_DATA && read.msg.descriptor[i].channel != CLUSTER_CONTROL_CHANNEL) { + ClusterVConnection *vc = channels[read.msg.descriptor[i].channel]; + if (VALID_CHANNEL(vc) && + (read.msg.descriptor[i].sequence_number) == CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) { + vc->last_activity_time = current_time; // note activity time + + len = read.msg.descriptor[i].length; + if (!len) { + continue; + } + + if (!vc->pending_remote_fill && vc_ok_read(vc) + && (!((ProxyMutex *) vc->read_locked) || vc->byte_bank_q.head)) { + // + // Byte bank active or unable to acquire lock on VC. + // Move data into the byte bank and attempt delivery + // at the next periodic event. + // + vc->read_block->fill(len); // note bytes received + add_to_byte_bank(vc); + + } else { + if (vc->pending_remote_fill || ((ProxyMutex *) vc->read_locked && vc_ok_read(vc))) { + vc->read_block->fill(len); // note bytes received + if (!vc->pending_remote_fill) { + vc->read.vio.buffer.writer()->append_block(vc->read_block->clone()); + vc->read_block->consume(len); // note bytes moved to user + } + complete_channel_read(len, vc); + } else { + if (vc->read.queue) { + cluster_reschedule(this, vc, &vc->read); + } + } + } + } + } + } + + // Processs control and freespace messages + process_small_control_msgs(); + process_large_control_msgs(); + process_freespace_msgs(); +} + +// +// This member function is run in a non ET_CLUSTER thread, which +// performs the input message processing on behalf of ET_CLUSTER. +// Primary motivation is to allow blocking and unbounded runtime +// for message processing which cannot be done with a ET_CLUSTER thread. +// +int +ClusterHandler::process_incoming_callouts(ProxyMutex * m) +{ + ProxyMutex *mutex = m; + ink_hrtime now; + // + // Atomically dequeue all active requests from the external queue and + // move them to the local working queue. Insertion queue order is + // maintained. + // + Queue local_incoming_control; + IncomingControl *ic_ext_next; + IncomingControl *ic_ext; + + while (true) { + ic_ext = (IncomingControl *) + ink_atomiclist_popall(&external_incoming_control); + if (!ic_ext) + break; + + while (ic_ext) { + ic_ext_next = (IncomingControl *) ic_ext->link.next; + ic_ext->link.next = NULL; + local_incoming_control.push(ic_ext); + ic_ext = ic_ext_next; + } + + // Perform callout actions for each message. + int small_control_msg; + IncomingControl *ic = NULL; + + while ((ic = local_incoming_control.pop())) { + LOG_EVENT_TIME(ic->recognized_time, inmsg_time_dist, inmsg_events); + + // Determine if this a small control message + small_control_msg = IsHighBitSet(&ic->len); + ClearHighBit(&ic->len); // Clear small msg flag bit + + if (small_control_msg) { + int len = ic->len; + char *p = ic->data; + uint32_t cluster_function_index = *(uint32_t *) p; + p += sizeof(uint32_t); + + if (cluster_function_index < (uint32_t) SIZE_clusterFunction) { + //////////////////////////////// + // Invoke processing function + //////////////////////////////// + ink_assert(!clusterFunction[cluster_function_index].ClusterFunc); + clusterFunction[cluster_function_index].pfn(machine, p, len - sizeof(int32_t)); + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CTRL_MSGS_RECV_TIME_STAT, now - ic->recognized_time); + } else { + Warning("2Bad cluster function index (small control)"); + } + // Deallocate memory + if (!clusterFunction[cluster_function_index].fMalloced) + ic->freeall(); + + } else { + ink_assert(ic->len > 4); + uint32_t cluster_function_index = *(uint32_t *) ic->data; + bool valid_index; + + if (cluster_function_index < (uint32_t) SIZE_clusterFunction) { + valid_index = true; + //////////////////////////////// + // Invoke processing function + //////////////////////////////// + ink_assert(!clusterFunction[cluster_function_index].ClusterFunc); + clusterFunction[cluster_function_index].pfn(machine, (void *) (ic->data + sizeof(int32_t)), + ic->len - sizeof(int32_t)); + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CTRL_MSGS_RECV_TIME_STAT, now - ic->recognized_time); + } else { + valid_index = false; + Warning("2Bad cluster function index (large control)"); + } + if (valid_index && !clusterFunction[cluster_function_index].fMalloced) + ic->freeall(); + } + } + } + return EVENT_CONT; +} + +void +ClusterHandler::update_channels_partial_read() +{ + // + // We were unable to read the computed amount. Reflect the partial + // amount read in the associated VC read buffer data structures. + // + int i; + int64_t res = read.bytes_xfered; + + if (!res) { + return; + } + ink_assert(res <= read.did); + + // how much of the iov was done + + int64_t iov_done[MAX_TCOUNT]; + int64_t total = 0; + int64_t already_read = read.did - read.bytes_xfered; + + for (i = 0; i < read.n_iov; i++) { + ink_release_assert(already_read >= 0); + iov_done[i] = read.iov[i].iov_len; + + // Skip over bytes already processed + if (already_read) { + already_read -= iov_done[i]; + if (already_read < 0) { + iov_done[i] = -already_read; // bytes remaining + already_read = 0; + } else { + iov_done[i] = 0; + continue; + } + } + // Adjustments for partial read for the current transfer + res -= iov_done[i]; + if (res < 0) { + iov_done[i] += res; + res = 0; + } else { + total += iov_done[i]; + } + } + ink_assert(total <= read.did); + + int read_all_large_control_msgs = 0; + // + // update the ClusterVConnections buffer pointers + // + for (i = 0; i < read.msg.count; i++) { + if (read.msg.descriptor[i].type == CLUSTER_SEND_DATA && read.msg.descriptor[i].channel != CLUSTER_CONTROL_CHANNEL) { + ClusterVConnection *vc = channels[read.msg.descriptor[i].channel]; + if (VALID_CHANNEL(vc) && + (read.msg.descriptor[i].sequence_number) == CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) { + if (vc->pending_remote_fill || (vc_ok_read(vc) && (vc->iov_map != CLUSTER_IOV_NONE))) { + vc->last_activity_time = current_time; // note activity time + ClusterVConnState *s = &vc->read; + ink_assert(vc->iov_map < read.n_iov); + int len = iov_done[vc->iov_map]; + + if (len) { + if (!read_all_large_control_msgs) { + // + // Since all large set_data control messages reside at the + // beginning, all have been read if the first non-control + // descriptor contains > 0 bytes. + // Process them ahead of any VC data completion actions + // followed by small control and freespace message processing. + // + process_set_data_msgs(); + process_small_control_msgs(); + process_freespace_msgs(); + read_all_large_control_msgs = 1; + } + iov_done[vc->iov_map] = 0; + vc->read_block->fill(len); // note bytes received + + if (!vc->pending_remote_fill) { + if ((ProxyMutex *) vc->read_locked) { + Debug("cluster_vc_xfer", "Partial read, credit ch %d 0x%x %d bytes", vc->channel, vc, len); + s->vio.buffer.writer()->append_block(vc->read_block->clone()); + if (complete_channel_read(len, vc)) { + vc->read_block->consume(len); // note bytes moved to user + } + + } else { + // If we have all the data for the VC, move it + // into the byte bank. Otherwise, do nothing since + // we will resume the read at this VC. + + if (len == (int) read.msg.descriptor[i].length) { + Debug("cluster_vc_xfer", "Partial read, byte bank move ch %d 0x%x %d bytes", vc->channel, vc, len); + add_to_byte_bank(vc); + } + } + } else { + Debug("cluster_vc_xfer", "Partial remote fill read, credit ch %d 0x%x %d bytes", vc->channel, vc, len); + complete_channel_read(len, vc); + } + read.msg.descriptor[i].length -= len; + ink_assert(((int) read.msg.descriptor[i].length) >= 0); + } + Debug(CL_TRACE, "partial_channel_read chan=%d len=%d", vc->channel, len); + } + } + } + } +} + +bool ClusterHandler::complete_channel_read(int len, ClusterVConnection * vc) +{ + // + // We have processed a complete VC read request message for a channel, + // perform completion actions. + // + ClusterVConnState *s = &vc->read; + + if (vc->pending_remote_fill) { + Debug(CL_TRACE, "complete_channel_read chan=%d len=%d", vc->channel, len); + vc->initial_data_bytes += len; + ++vc->pending_remote_fill; // Note completion + return (vc->closed ? false : true); + } + + if (vc->closed) + return false; // No action if already closed + + ink_assert((ProxyMutex *) s->vio.mutex == (ProxyMutex *) s->vio._cont->mutex); + + Debug("cluster_vc_xfer", "Complete read, credit ch %d 0x%x %d bytes", vc->channel, vc, len); + s->vio.ndone += len; + + if (s->vio.ntodo() <= 0) { + s->enabled = 0; + if (cluster_signal_and_update_locked(VC_EVENT_READ_COMPLETE, vc, s) + == EVENT_DONE) + return false; + } else { + if (cluster_signal_and_update_locked(VC_EVENT_READ_READY, vc, s) == EVENT_DONE) + return false; + if (s->vio.ntodo() <= 0) + s->enabled = 0; + } + + if (!s->queue) { + cluster_set_priority(this, s, s->priority); + cluster_schedule(this, vc, s); + + } else { + // + // VC received data, move VC to current bucket since + // it may have freespace data to send (READ_VC_PRIORITY). + // + ClusterVC_remove_read(vc); + cluster_set_priority(this, s, 1); + Debug(CL_PROTO, "(%d) upping read priority %d", vc->channel, s->priority); + ClusterVC_enqueue_read(read_vcs[cur_vcs], vc); + } + return true; +} + +void +ClusterHandler::finish_delayed_reads() +{ + // + // Process pending VC delayed reads generated in the last read from + // the node to node connection. For explanation of "delayed read" see + // comments at the beginning of the member functions for ClusterHandler. + // + ClusterVConnection *vc = NULL; + DLL l; + while ((vc = (ClusterVConnection *) delayed_reads.pop())) { + MUTEX_TRY_LOCK_SPIN(lock, vc->read.vio.mutex, thread, READ_LOCK_SPIN_COUNT); + if (lock) { + if (vc_ok_read(vc)) { + ink_assert(!vc->read.queue); + ByteBankDescriptor *d; + + while ((d = vc->byte_bank_q.dequeue())) { + if (vc->read.queue) { + // Previous complete_channel_read() put us back on the list, + // remove our self to process another byte bank completion + ClusterVC_remove_read(vc); + } + Debug("cluster_vc_xfer", + "Delayed read, credit ch %d 0x%x %d bytes", vc->channel, vc, d->get_block()->read_avail()); + vc->read.vio.buffer.writer()->append_block(d->get_block()); + + if (complete_channel_read(d->get_block()->read_avail(), vc)) { + ByteBankDescriptor::ByteBankDescriptor_free(d); + } else { + ByteBankDescriptor::ByteBankDescriptor_free(d); + break; + } + } + } + } else + l.push(vc); + } + delayed_reads = l; +} + +void +ClusterHandler::update_channels_written(bool bump_unhandled_channels) +{ + // + // We have sucessfully pushed the write data for the VC(s) described + // by the descriptors. + // Move the channels in this bucket to a new bucket. + // Lower the priority of those with too little data and raise that of + // those with too much data. + // + ink_hrtime now; + for (int i = 0; i < write.msg.count; i++) { + if (write.msg.descriptor[i].type == CLUSTER_SEND_DATA) { + if (write.msg.descriptor[i].channel != CLUSTER_CONTROL_CHANNEL) { + ClusterVConnection *vc = channels[write.msg.descriptor[i].channel]; + if (VALID_CHANNEL(vc) && + (write.msg.descriptor[i].sequence_number) == CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) { + + if (vc->pending_remote_fill) { + Debug(CL_TRACE, + "update_channels_written chan=%d seqno=%d len=%d", + write.msg.descriptor[i].channel, + write.msg.descriptor[i].sequence_number, write.msg.descriptor[i].length); + vc->pending_remote_fill = 0; + vc->remote_write_block = 0; // free data block + continue; // ignore remote write fill VC(s) + } + + ClusterVConnState *s = &vc->write; + int len = write.msg.descriptor[i].length; + vc->write_bytes_in_transit -= len; + ink_release_assert(vc->write_bytes_in_transit >= 0); + Debug(CL_PROTO, "(%d) data sent %d %d", write.msg.descriptor[i].channel, len, s->vio.ndone); + + if (vc_ok_write(vc)) { + vc->last_activity_time = current_time; // note activity time + int64_t n = vc->was_closed()? 0 : s->vio.buffer.reader()->block_read_avail(); + int64_t nb = vc->was_closed()? 0 : s->vio.nbytes; + int64_t ndone = vc->was_closed()? 0 : s->vio.ndone; + + if (ndone < vc->remote_free) { + cluster_set_priority(this, s, 1); // next bucket + } else { + cluster_update_priority(this, vc, s, n, nb); + } + } + cluster_reschedule(this, vc, s); + } + } else { + // + // Free up outgoing control message space + // + OutgoingControl *oc = write.msg.outgoing_control.dequeue(); + oc->free_data(); + oc->mutex = NULL; + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CTRL_MSGS_SEND_TIME_STAT, now - oc->submit_time); + LOG_EVENT_TIME(oc->submit_time, cluster_send_time_dist, cluster_send_events); + oc->freeall(); + } + } else { + ink_assert(write.msg.descriptor[i].type == CLUSTER_SEND_FREE); + ClusterVConnection *vc = channels[write.msg.descriptor[i].channel]; + + if (VALID_CHANNEL(vc) && + (write.msg.descriptor[i].sequence_number) == CLUSTER_SEQUENCE_NUMBER(vc->token.sequence_number)) { + if (!vc->byte_bank_q.head) { + cluster_reschedule(this, vc, &vc->read); + } + } + } + } + // + // If requested, process unhandled VC(s) in the current write_vcs bucket. + // Unhandled VC(s) result in cases where we are unable to acquire the + // lock or due to maximum size restrictions on the struct iovec. + // + if (bump_unhandled_channels) { + int n; + ClusterVConnection *vc; + while ((vc = (ClusterVConnection *) write_vcs[cur_vcs].head)) { + ClusterVC_remove_write(vc); + + ink_assert(!((ProxyMutex *) vc->write_locked)); + MUTEX_TRY_LOCK_SPIN(lock, vc->write.vio.mutex, thread, WRITE_LOCK_SPIN_COUNT); + if (lock) { + n = vc->write.vio.buffer.mbuf ? vc->write.vio.buffer.reader()->block_read_avail() : 0; + } else { + n = 0; + } + if (n) { + cluster_bump(this, vc, &vc->write, CLUSTER_BUMP_NO_REMOVE); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_BUMPED_STAT); + } else { + cluster_schedule(this, vc, &vc->write); + } + } + } + // + // For compound messages, deallocate the data and header descriptors. + // The deallocation of the data descriptor will indirectly invoke + // the free memory proc described in set_data. + // + invoke_remote_data_args *args; + OutgoingControl *hdr_oc; + while ((hdr_oc = write.msg.outgoing_callout.dequeue())) { + args = (invoke_remote_data_args *) (hdr_oc->data + sizeof(int32_t)); + ink_assert(args->magicno == invoke_remote_data_args::MagicNo); + + // Free data descriptor + args->data_oc->free_data(); // invoke memory free callback + args->data_oc->mutex = NULL; + args->data_oc->freeall(); + + // Free descriptor + hdr_oc->free_data(); + hdr_oc->mutex = NULL; + now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CTRL_MSGS_SEND_TIME_STAT, now - hdr_oc->submit_time); + LOG_EVENT_TIME(hdr_oc->submit_time, cluster_send_time_dist, cluster_send_events); + hdr_oc->freeall(); + } +} + +int +ClusterHandler::build_write_descriptors() +{ + // + // Construct the write descriptors for VC write data in the current + // write_vcs bucket with considerations for maximum elements per + // write (struct iovec system maximum). + // + int count_bucket = cur_vcs; + int tcount = write.msg.count + 2; // count + descriptor + int write_descriptors_built = 0; + + // + // Build descriptors for connections with stuff to send. + // + ClusterVConnection *vc_next = (ClusterVConnection *) write_vcs[count_bucket].head; + while (vc_next) { + enter_exit(&cls_build_writes_entered, &cls_writes_exited); + if (tcount >= MAX_TCOUNT) + break; + ClusterVConnection *vc = vc_next; + vc_next = (ClusterVConnection *) vc->write.link.next; + if (valid_for_data_write(vc)) { + ink_assert(vc->write_locked); // Acquired in valid_for_data_write() + if ((vc->remote_free > (vc->write.vio.ndone - vc->write_list_bytes)) + && channels[vc->channel] == vc) { + + ink_assert(vc->write_list && vc->write_list_bytes); + + int d = write.msg.count; + write.msg.descriptor[d].type = CLUSTER_SEND_DATA; + write.msg.descriptor[d].channel = vc->channel; + write.msg.descriptor[d].sequence_number = vc->token.sequence_number; + int s = vc->write_list_bytes; + ink_release_assert(s <= MAX_CLUSTER_SEND_LENGTH); + + // Transfer no more than nbytes + if ((vc->write.vio.ndone - s) > vc->write.vio.nbytes) + s = vc->write.vio.nbytes - (vc->write.vio.ndone - s); + + if ((vc->write.vio.ndone - s) > vc->remote_free) + s = vc->remote_free - (vc->write.vio.ndone - s); + write.msg.descriptor[d].length = s; + write.msg.count++; + tcount++; + write_descriptors_built++; + +#ifdef CLUSTER_STATS + _vc_writes++; + _vc_write_bytes += s; +#endif + + } else { + cluster_lower_priority(this, &vc->write); + cluster_reschedule(this, vc, &vc->write); + + MUTEX_UNTAKE_LOCK(vc->write_locked, thread); + vc->write_locked = NULL; + + if (channels[vc->channel] == vc) + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_NO_REMOTE_SPACE_STAT); + } + } + } + return (write_descriptors_built); +} + +int +ClusterHandler::build_freespace_descriptors() +{ + // + // Construct the write descriptors for VC freespace data in the current + // read_vcs bucket with considerations for maximum elements per + // write (struct iovec system maximum) and for pending elements already + // in the list. + // + int count_bucket = cur_vcs; + int tcount = write.msg.count + 2; // count + descriptor require 2 iovec(s) + int freespace_descriptors_built = 0; + + // + // Build descriptors for available space + // + ClusterVConnection *vc_next = (ClusterVConnection *) read_vcs[count_bucket].head; + while (vc_next) { + enter_exit(&cls_build_reads_entered, &cls_reads_exited); + if (tcount >= MAX_TCOUNT) + break; + ClusterVConnection *vc = vc_next; + vc_next = (ClusterVConnection *) vc->read.link.next; + int s = 0; + if ((s = valid_for_freespace_write(vc))) { + if (vc_ok_read(vc) && channels[vc->channel] == vc) { + // Send free space only if changed + int d = write.msg.count; + write.msg.descriptor[d].type = CLUSTER_SEND_FREE; + write.msg.descriptor[d].channel = vc->channel; + write.msg.descriptor[d].sequence_number = vc->token.sequence_number; + + ink_assert(s > 0); + write.msg.descriptor[d].length = s; + vc->last_local_free = s; + Debug(CL_PROTO, "(%d) free space priority %d", vc->channel, vc->read.priority); + write.msg.count++; + tcount++; + freespace_descriptors_built++; + } else { + cluster_lower_priority(this, &vc->read); + cluster_reschedule(this, vc, &vc->read); + } + } + } + return (freespace_descriptors_built); +} + +int +ClusterHandler::build_controlmsg_descriptors() +{ + // + // Construct the write descriptors for control message data in the + // outgoing_control queue with considerations for maximum elements per + // write (struct iovec system maximum) and for elements already + // in the list. + // + int tcount = write.msg.count + 2; // count + descriptor require 2 iovec(s) + int control_msgs_built = 0; + bool compound_msg; // msg + chan data + // + // Build descriptors for control messages + // + OutgoingControl *c = NULL; + int control_bytes = 0; + int q = 0; + + while (tcount < (MAX_TCOUNT - 1)) { // -1 to allow for compound messages + c = outgoing_control[q].pop(); + if (!c) { + // Move elements from global outgoing_control to local queue + OutgoingControl *c_next; + c = (OutgoingControl *) ink_atomiclist_popall(&outgoing_control_al[q]); + if (c == 0) { + if (++q >= CLUSTER_CMSG_QUEUES) { + break; + } else { + continue; + } + } + while (c) { + c_next = (OutgoingControl *) c->link.next; + c->link.next = NULL; + outgoing_control[q].push(c); + c = c_next; + } + continue; + + } else { + compound_msg = (*((int32_t *) c->data) == -1); // (msg+chan data)? + } + if (!compound_msg && c->len <= SMALL_CONTROL_MESSAGE && + // check if the receiving cluster function will want to malloc'ed data + !clusterFunction[*(int32_t *) c->data].fMalloced && control_bytes + c->len + sizeof(int32_t) * 2 + 7 < CONTROL_DATA) { + write.msg.outgoing_small_control.enqueue(c); + control_bytes += c->len + sizeof(int32_t) * 2 + 7; // safe approximation + control_msgs_built++; + + if (clusterFunction[*(int32_t *) c->data].post_pfn) { + clusterFunction[*(int32_t *) c->data].post_pfn(machine, c->data + sizeof(int32_t), c->len); + } + continue; + } + // + // Build large control message descriptor + // + if (compound_msg) { + // Extract out components of compound message. + invoke_remote_data_args *cmhdr = (invoke_remote_data_args *) (c->data + sizeof(int32_t)); + OutgoingControl *oc_header = c; + OutgoingControl *oc_msg = cmhdr->msg_oc; + OutgoingControl *oc_data = cmhdr->data_oc; + + ink_assert(cmhdr->magicno == invoke_remote_data_args::MagicNo); + // + // Build descriptors and order the data before the reply message. + // Reply message processing assumes data completion action performed + // prior to processing completion message. + // Not an issue today since channel data is always processed first. + // + int d; + d = write.msg.count; + write.msg.descriptor[d].type = CLUSTER_SEND_DATA; + write.msg.descriptor[d].channel = cmhdr->dest_channel; + write.msg.descriptor[d].length = oc_data->len; + write.msg.descriptor[d].sequence_number = cmhdr->token.sequence_number; + +#ifdef CLUSTER_STATS + _vc_write_bytes += oc_data->len; +#endif + + // Setup remote write fill iovec. Remote write fills have no VIO. + ClusterVConnection *vc = channels[cmhdr->dest_channel]; + + if (VALID_CHANNEL(vc) && vc->pending_remote_fill) { + ink_release_assert(!vc->remote_write_block); + vc->remote_write_block = oc_data->get_block(); + + // Note: No array overrun since we are bounded by (MAX_TCOUNT-1). + write.msg.count++; + tcount++; + control_msgs_built++; + d = write.msg.count; + write.msg.outgoing_control.enqueue(oc_msg); + write.msg.descriptor[d].type = CLUSTER_SEND_DATA; + write.msg.descriptor[d].channel = CLUSTER_CONTROL_CHANNEL; + write.msg.descriptor[d].length = oc_msg->len; + +#ifdef CLUSTER_STATS + _control_write_bytes += oc_msg->len; +#endif + + write.msg.count++; + tcount++; + control_msgs_built++; + + // Queue header to process buffer free memory callbacks after send. + write.msg.outgoing_callout.enqueue(oc_header); + + } else { + // Operation cancelled free memory. + Warning("Pending remote read fill aborted chan=%d len=%d", cmhdr->dest_channel, oc_data->len); + + // Free compound message + oc_header->free_data(); + oc_header->mutex = NULL; + oc_header->freeall(); + + // Free response message + oc_msg->free_data(); + oc_msg->mutex = 0; + oc_msg->freeall(); + + // Free data descriptor + oc_data->free_data(); // invoke memory free callback + oc_data->mutex = 0; + oc_data->freeall(); + } + + } else { + write.msg.outgoing_control.enqueue(c); + + int d = write.msg.count; + write.msg.descriptor[d].type = CLUSTER_SEND_DATA; + write.msg.descriptor[d].channel = CLUSTER_CONTROL_CHANNEL; + write.msg.descriptor[d].length = c->len; + +#ifdef CLUSTER_STATS + _control_write_bytes += c->len; +#endif + + write.msg.count++; + tcount++; + control_msgs_built++; + + if (clusterFunction[*(int32_t *) c->data].post_pfn) { + clusterFunction[*(int32_t *) c->data].post_pfn(machine, c->data + sizeof(int32_t), c->len); + } + } + } + return control_msgs_built; +} + +int +ClusterHandler::add_small_controlmsg_descriptors() +{ + // + // Move small control message data to free space after descriptors + // + char *p = (char *) &write.msg.descriptor[write.msg.count]; + OutgoingControl *c = NULL; + + while ((c = write.msg.outgoing_small_control.dequeue())) { + *(int32_t *) p = c->len; + p += sizeof(int32_t); + memcpy(p, c->data, c->len); + c->free_data(); + c->mutex = NULL; + p += c->len; +#ifdef PURIFY + char *endp = p; +#endif + ink_hrtime now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CTRL_MSGS_SEND_TIME_STAT, now - c->submit_time); + LOG_EVENT_TIME(c->submit_time, cluster_send_time_dist, cluster_send_events); + c->freeall(); + p = (char *) DOUBLE_ALIGN(p); +#ifdef PURIFY + if (endp < p) + memset(endp, 0, (p - endp)); +#endif + } + write.msg.control_bytes = p - (char *) &write.msg.descriptor[write.msg.count]; + +#ifdef CLUSTER_STATS + _control_write_bytes += write.msg.control_bytes; +#endif + + return 1; +} + +struct DestructorLock +{ + DestructorLock(EThread * thread) + { + have_lock = false; + t = thread; + } + ~DestructorLock() + { + if (have_lock && m) { + Mutex_unlock(m, t); + } + m = 0; + } + EThread *t; + Ptr m; + bool have_lock; +}; + +int +ClusterHandler::valid_for_data_write(ClusterVConnection * vc) +{ + // + // Determine if writes are allowed on this VC + // + int count_bucket = cur_vcs; + ClusterVConnState *s = &vc->write; + + ink_assert(!on_stolen_thread); + ink_assert((ProxyMutex *) ! vc->write_locked); + + // + // Attempt to get the lock, if we miss, push vc into the future + // + DestructorLock lock(thread); + +retry: + if ((lock.m = s->vio.mutex)) { + lock.have_lock = MUTEX_TAKE_TRY_LOCK_FOR_SPIN(lock.m, thread, s->vio._cont, WRITE_LOCK_SPIN_COUNT); + if (!lock.have_lock) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_LOCKED_STAT); + cluster_bump(this, vc, s, count_bucket); + +#ifdef CLUSTER_STATS + _dw_missed_lock++; +#endif + return 0; + } + } + + if (vc->was_closed()) { + if (vc->schedule_write()) { +#ifdef CLUSTER_TOMCAT + ink_assert(lock.m); +#endif + vc->write_locked = lock.m; + lock.m = 0; + lock.have_lock = false; + return 1; + } else { + if (!vc->write_bytes_in_transit) { + close_ClusterVConnection(vc); + } + return 0; + } + } + + if (!s->enabled && !vc->was_remote_closed()) { + cluster_lower_priority(this, s); + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _dw_not_enabled++; +#endif + return 0; + } + + if (vc->pending_remote_fill) { + if (vc->was_remote_closed()) + close_ClusterVConnection(vc); + +#ifdef CLUSTER_STATS + _dw_wait_remote_fill++; +#endif + return 0; + } + + if (!lock.have_lock || !s->vio.mutex || !s->vio._cont) { + if (!lock.have_lock && s->vio.mutex && s->vio._cont) { + goto retry; + } else { + // No active VIO + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _dw_no_active_vio++; +#endif + return 0; + } + } + // + // If this connection has been closed remotely, send EOS + // + if (vc->was_remote_closed()) { + if (!vc->write_bytes_in_transit && !vc->schedule_write()) { + if (remote_close(vc, s) == EVENT_DONE) + return 0; + } + cluster_reschedule(this, vc, s); + return 0; + } + // + // If not enabled or not WRITE + // + if (!s->enabled || s->vio.op != VIO::WRITE) { + s->enabled = 0; + cluster_lower_priority(this, s); + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _dw_not_enabled_or_no_write++; +#endif + return 0; + } + // + // If no room on the remote side or set_data() messages pending + // + int set_data_msgs_pending = vc->n_set_data_msgs; + if (set_data_msgs_pending || (vc->remote_free <= (s->vio.ndone - vc->write_list_bytes))) { + if (set_data_msgs_pending) { + cluster_bump(this, vc, s, cur_vcs); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_VC_WRITE_STALL_STAT); + +#ifdef CLUSTER_STATS + _dw_set_data_pending++; +#endif + + } else { + cluster_lower_priority(this, s); + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _dw_no_free_space++; +#endif + } + return 0; + } + // + // Calculate amount writable + // + MIOBufferAccessor & buf = s->vio.buffer; + + int64_t towrite = buf.reader()->read_avail(); + int64_t ntodo = s->vio.ntodo(); + + if (towrite > ntodo) + towrite = ntodo; + + ink_assert(ntodo >= 0); + if (ntodo <= 0) { + if (cluster_signal_and_update(VC_EVENT_WRITE_COMPLETE, vc, s) == EVENT_DONE) + return 0; + cluster_reschedule(this, vc, s); + return 0; + } + if (buf.writer()->write_avail() && towrite != ntodo) { + if (cluster_signal_and_update(VC_EVENT_WRITE_READY, vc, s) == EVENT_DONE) + return 0; + ink_assert(s->vio.ntodo() >= 0); + if (s->vio.ntodo() <= 0) { + if (cluster_signal_and_update(VC_EVENT_WRITE_COMPLETE, vc, s) == EVENT_DONE) + return 0; + cluster_reschedule(this, vc, s); + return 0; + } + } + // Clone nbytes of vio.buffer.reader IOBufferBlock list allowing + // write_list to contain no more than DEFAULT_MAX_BUFFER_SIZE bytes. + + Ptr b_list; + IOBufferBlock *b_tail; + int bytes_to_fill; + int consume_bytes; + + bytes_to_fill = DEFAULT_MAX_BUFFER_SIZE - vc->write_list_bytes; + + if (towrite && bytes_to_fill) { + consume_bytes = (towrite > bytes_to_fill) ? bytes_to_fill : towrite; + b_list = clone_IOBufferBlockList(s->vio.buffer.reader()->block, + s->vio.buffer.reader()->start_offset, consume_bytes, &b_tail); + ink_assert(b_tail); + + // Append cloned IOBufferBlock list to VC write_list. + + if (vc->write_list_tail) { + vc->write_list_tail->next = b_list; + } else { + vc->write_list = b_list; + } + vc->write_list_tail = b_tail; + vc->write_list_bytes += consume_bytes; + ink_assert(bytes_IOBufferBlockList(vc->write_list, 1) == vc->write_list_bytes); + + // We may defer the write, but tell the user we have consumed the data. + + (s->vio.buffer.reader())->consume(consume_bytes); + s->vio.ndone += consume_bytes; + if (s->vio.ntodo() <= 0) { + if (cluster_signal_and_update_locked(VC_EVENT_WRITE_COMPLETE, vc, s) != EVENT_DONE) { + cluster_reschedule(this, vc, s); + } + } + } + + if (vc->schedule_write()) { +#ifdef CLUSTER_TOMCAT + ink_assert(s->vio.mutex); +#endif + vc->write_locked = lock.m; + lock.m = 0; + lock.have_lock = false; + return 1; + } else { + return 0; + } +} + +int +ClusterHandler::valid_for_freespace_write(ClusterVConnection * vc) +{ + // + // Determine if freespace messages are allowed on this VC + // + int count_bucket = cur_vcs; + ClusterVConnState *s = &vc->read; + + ink_assert(!on_stolen_thread); + + // + // Attempt to get the lock, if we miss, push vc into the future + // + DestructorLock lock(thread); + +retry: + if ((lock.m = s->vio.mutex)) { + lock.have_lock = MUTEX_TAKE_TRY_LOCK_FOR_SPIN(lock.m, thread, s->vio._cont, READ_LOCK_SPIN_COUNT); + + if (!lock.have_lock) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_LOCKED_STAT); + cluster_bump(this, vc, s, count_bucket); + +#ifdef CLUSTER_STATS + _fw_missed_lock++; +#endif + return 0; + } + } + if (vc->was_closed()) { + if (!vc->write_bytes_in_transit && !vc->schedule_write()) { + close_ClusterVConnection(vc); + return 0; + } else { + // Defer close until write data is pushed + return 0; + } + } + + if (!s->enabled && !vc->was_remote_closed()) { + cluster_lower_priority(this, s); + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _fw_not_enabled++; +#endif + return 0; + } + + if (vc->pending_remote_fill) { + if (vc->was_remote_closed()) + close_ClusterVConnection(vc); + +#ifdef CLUSTER_STATS + _fw_wait_remote_fill++; +#endif + return 0; + } + + if (!lock.have_lock || !s->vio.mutex || !s->vio._cont) { + if (!lock.have_lock && s->vio.mutex && s->vio._cont) { + goto retry; + } else { + // No active VIO + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _fw_no_active_vio++; +#endif + return 0; + } + } + // + // If this connection has been closed remotely, send EOS + // + if (vc->was_remote_closed()) { + if (vc->write_bytes_in_transit || vc->schedule_write()) { + // Defer close until write data is pushed + return 0; + } + if (remote_close(vc, s) == EVENT_DONE) + return 0; + cluster_reschedule(this, vc, s); + return 0; + } + // + // If not enabled or not WRITE + // + if (!s->enabled || s->vio.op != VIO::READ) { + cluster_lower_priority(this, s); + cluster_reschedule(this, vc, s); + +#ifdef CLUSTER_STATS + _fw_not_enabled_or_no_read++; +#endif + return 0; + } + + int64_t nb = s->vio.nbytes; + int64_t ntodo = s->vio.ntodo(); + ink_assert(ntodo >= 0); + + if (ntodo <= 0) { + if (cluster_signal_and_update(VC_EVENT_READ_COMPLETE, vc, s) == EVENT_DONE) + return 0; + cluster_reschedule(this, vc, s); + return 0; + } + + int64_t bytes_to_move = vc->initial_data_bytes; + if (vc->read_block && bytes_to_move) { + + // Push initial read data into VC + + if (ntodo >= bytes_to_move) { + Debug("cluster_vc_xfer", "finish initial data push ch %d bytes %d", vc->channel, vc->read_block->read_avail()); + + s->vio.buffer.writer()->append_block(vc->read_block->clone()); + vc->read_block = 0; + + } else { + bytes_to_move = ntodo; + + Debug("cluster_vc_xfer", "initial data push ch %d bytes %d", vc->channel, bytes_to_move); + + // Clone a portion of the data + + IOBufferBlock *b, *btail; + b = clone_IOBufferBlockList(vc->read_block, 0, bytes_to_move, &btail); + s->vio.buffer.writer()->append_block(b); + vc->read_block->consume(bytes_to_move); + } + s->vio.ndone += bytes_to_move; + vc->initial_data_bytes -= bytes_to_move; + + if (s->vio.ntodo() <= 0) { + s->enabled = 0; + if (cluster_signal_and_update_locked(VC_EVENT_READ_COMPLETE, vc, s) + != EVENT_DONE) { + cluster_reschedule(this, vc, s); + } + return 0; + + } else { + if (vc->have_all_data) { + if (!vc->read_block) { + s->enabled = 0; + if (cluster_signal_and_update(VC_EVENT_EOS, vc, s) != EVENT_DONE) { + cluster_reschedule(this, vc, s); + } + return 0; + } + } + if (cluster_signal_and_update_locked(VC_EVENT_READ_READY, vc, s) + == EVENT_DONE) + return false; + + if (s->vio.ntodo() <= 0) + s->enabled = 0; + + if (vc->initial_data_bytes) + return 0; + } + } + // At this point, all initial read data passed in the open_read reply + // has been moved into the user VC. + // Now allow send of freespace to receive additional data. + + int64_t nextfree = vc->read.vio.ndone; + + nextfree = (nextfree + DEFAULT_MAX_BUFFER_SIZE - 1) / DEFAULT_MAX_BUFFER_SIZE; + nextfree *= DEFAULT_MAX_BUFFER_SIZE; + + if (nextfree >= (vc->last_local_free / 2)) { + nextfree = vc->last_local_free + (8 * DEFAULT_MAX_BUFFER_SIZE); + } + + if ((vc->last_local_free == 0) || (nextfree >= vc->last_local_free)) { + Debug(CL_PROTO, "(%d) update freespace %d", vc->channel, nextfree); + cluster_update_priority(this, vc, s, nextfree - vc->last_local_free, nb); + cluster_reschedule(this, vc, s); + // + // Have good VC candidate locked for freespace write + // + return nextfree; + + } else { + // No free space update required + return 0; + } +} + +int +ClusterHandler::remote_close(ClusterVConnection * vc, ClusterVConnState * ns) +{ + if (ns->vio.op != VIO::NONE && !vc->closed) { + ns->enabled = 0; + if (vc->remote_closed > 0) { + if (ns->vio.op == VIO::READ) { + if (ns->vio.nbytes == ns->vio.ndone) { + return cluster_signal_and_update(VC_EVENT_READ_COMPLETE, vc, ns); + } else { + return cluster_signal_and_update(VC_EVENT_EOS, vc, ns); + } + } else { + return cluster_signal_and_update(VC_EVENT_EOS, vc, ns); + } + } else { + return cluster_signal_error_and_update(vc, ns, vc->remote_lerrno); + } + } + return EVENT_CONT; +} + +void +ClusterHandler::steal_thread(EThread * t) +{ + // + // Attempt to push the control message now instead of waiting + // for the periodic event to process it. + // + if (t != thread && // different thread to steal + write.to_do <= 0 && // currently not trying to send data + // nothing big outstanding + !write.msg.count) { + mainClusterEvent(CLUSTER_EVENT_STEAL_THREAD, (Event *) t); + } +} + +void +ClusterHandler::free_locks(bool read_flag, int i) +{ + // + // Free VC locks. Handle partial acquires up to i + // + if (i == CLUSTER_FREE_ALL_LOCKS) { + if (read_flag) { + i = (read.msg.state >= 2 ? read.msg.count : 0); + } else { + i = write.msg.count; + } + } + ClusterState & s = (read_flag ? read : write); + for (int j = 0; j < i; j++) { + if (s.msg.descriptor[j].type == CLUSTER_SEND_DATA && s.msg.descriptor[j].channel != CLUSTER_CONTROL_CHANNEL) { + ClusterVConnection *vc = channels[s.msg.descriptor[j].channel]; + if (VALID_CHANNEL(vc)) { + if (read_flag) { + if ((ProxyMutex *) vc->read_locked) { + MUTEX_UNTAKE_LOCK(vc->read.vio.mutex, thread); + vc->read_locked = NULL; + } + } else { + if ((ProxyMutex *) vc->write_locked) { + MUTEX_UNTAKE_LOCK(vc->write_locked, thread); + vc->write_locked = NULL; + } + } + } + } else if (!read_flag && + s.msg.descriptor[j].type == CLUSTER_SEND_FREE && + s.msg.descriptor[j].channel != CLUSTER_CONTROL_CHANNEL) { + ClusterVConnection *vc = channels[s.msg.descriptor[j].channel]; + if (VALID_CHANNEL(vc)) { + if ((ProxyMutex *) vc->read_locked) { + MUTEX_UNTAKE_LOCK(vc->read_locked, thread); + vc->read_locked = NULL; + } + } + } + } +} + +#ifdef CLUSTER_IMMEDIATE_NETIO +void +ClusterHandler::build_poll(bool next) +{ + Pollfd *pfd; + if (next) { + pfd = thread->nextPollDescriptor->alloc(); + pfd->fd = net_vc->get_socket(); + ifd = pfd - thread->nextPollDescriptor->pfd; + } else { + pfd = thread->pollDescriptor->alloc(); + pfd->fd = net_vc->get_socket(); + ifd = pfd - thread->pollDescriptor->pfd; + } + pfd->events = POLLHUP; + if (next) { + if (read.to_do) + pfd->events |= POLLIN; + if (write.to_do) + pfd->events |= POLLOUT; + } else { + // we have to lie since we are in the same cycle + pfd->events = POLLIN | POLLOUT; + // reads/writes are non-blocking anyway + pfd->revents = POLLIN | POLLOUT; + } +} +#endif // CLUSTER_IMMEDIATE_NETIO + +extern int CacheClusterMonitorEnabled; +extern int CacheClusterMonitorIntervalSecs; + + +// +// The main event for machine-machine link +// +int +ClusterHandler::mainClusterEvent(int event, Event * e) +{ + // Set global time + current_time = ink_get_hrtime(); + + if (CacheClusterMonitorEnabled) { + if ((current_time - last_trace_dump) > HRTIME_SECONDS(CacheClusterMonitorIntervalSecs)) { + last_trace_dump = current_time; + dump_internal_data(); + } + } + // + // Note: The caller always acquires the ClusterHandler mutex prior + // to the call. This guarantees single threaded access in + // mainClusterEvent() + // + + ///////////////////////////////////////////////////////////////////////// + // If cluster interconnect is overloaded, disable remote cluster ops. + ///////////////////////////////////////////////////////////////////////// +#ifndef DEBUG + if (clm && ClusterLoadMonitor::cf_monitor_enabled > 0) { +#else + if (0) { +#endif + bool last_state = disable_remote_cluster_ops; + if (clm->is_cluster_overloaded()) { + disable_remote_cluster_ops = true; + } else { + disable_remote_cluster_ops = false; + } + if (last_state != disable_remote_cluster_ops) { + if (disable_remote_cluster_ops) { + Note("Network congestion to [%u.%u.%u.%u] encountered, reverting to proxy only mode", DOT_SEPARATED(ip)); + } else { + Note("Network congestion to [%u.%u.%u.%u] cleared, reverting to cache mode", DOT_SEPARATED(ip)); + last_cluster_op_enable = current_time; + } + } + } + + on_stolen_thread = (event == CLUSTER_EVENT_STEAL_THREAD); + bool io_callback = (event == EVENT_IMMEDIATE); + + if (on_stolen_thread) { + thread = (EThread *) e; + } else { + if (io_callback) { + thread = this_ethread(); + } else { + thread = e->ethread; + } + } + + int io_activity = 1; + bool only_write_control_msgs; + int res; + + while (io_activity) { + io_activity = 0; + only_write_control_msgs = 0; + ////////////////////////// + // Read Processing + ////////////////////////// + if (!on_stolen_thread) { + if (delayed_reads.head) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_DELAYED_READS_STAT); + finish_delayed_reads(); + } + if ((res = process_read(current_time)) < 0) { + break; + } + io_activity += res; + + if (delayed_reads.head) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_DELAYED_READS_STAT); + finish_delayed_reads(); + } + } + ///////////////////////// + // Write Processing + ///////////////////////// + if ((res = process_write(current_time, only_write_control_msgs)) < 0) { + break; + } + io_activity += res; + + ///////////////////////////////////////// + // Process deferred open_local requests + ///////////////////////////////////////// + if (!on_stolen_thread) { + do_open_local_requests(); + } + } + +#ifdef CLUSTER_IMMEDIATE_NETIO + if (!machine->dead && ((event == EVENT_POLL) || (event == EVENT_INTERVAL))) { + if (res >= 0) { + build_poll(true); + } + } +#endif + return EVENT_CONT; +} + +int +ClusterHandler::process_read(ink_hrtime now) +{ + NOWARN_UNUSED(now); +#ifdef CLUSTER_STATS + _process_read_calls++; +#endif + if (machine->dead) { + // Node is down + return 0; + } + /////////////////////////////// + // Cluster read state machine + /////////////////////////////// + + for (;;) { + + switch (read.state) { + /////////////////////////////////////////////// + case ClusterState::READ_START: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_start++; +#endif + read.msg.clear(); + read.start_time = ink_get_hrtime(); + if (build_initial_vector(CLUSTER_READ)) { + read.state = ClusterState::READ_HEADER; + } else { + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_HEADER: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_header++; +#endif + read.state = ClusterState::READ_AWAIT_HEADER; + if (!read.doIO()) { + // i/o not initiated, retry later + read.state = ClusterState::READ_HEADER; + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_AWAIT_HEADER: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_await_header++; +#endif + if (!read.io_complete) { + return 0; + } else { + if (read.io_complete < 0) { + // read error, declare node down + machine_down(); + return -1; + } + } + if (read.to_do) { + if (read.bytes_xfered) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_PARTIAL_READS_STAT); + read.state = ClusterState::READ_HEADER; + break; + } else { + // Zero byte read + read.state = ClusterState::READ_HEADER; + return 0; + } + } else { +#ifdef MSG_TRACE + fprintf(t_fd, + "[R] seqno=%d count=%d control_bytes=%d count_check=%d dsum=%d csum=%d\n", + read.sequence_number, + read.msg.hdr()->count, read.msg.hdr()->control_bytes, + read.msg.hdr()->count_check, read.msg.hdr()->descriptor_cksum, read.msg.hdr()->control_bytes_cksum); + fflush(t_fd); +#endif + CLUSTER_SUM_DYN_STAT(CLUSTER_READ_BYTES_STAT, read.did); + if (needByteSwap) { + read.msg.hdr()->SwapBytes(); + } + read.msg.count = read.msg.hdr()->count; + read.msg.control_bytes = read.msg.hdr()->control_bytes; + read.msg.descriptor_cksum = read.msg.hdr()->descriptor_cksum; + read.msg.control_bytes_cksum = read.msg.hdr()->control_bytes_cksum; + read.msg.unused = read.msg.hdr()->unused; + + if (MAGIC_COUNT(read) != read.msg.hdr()->count_check) { + ink_assert(!"Read bad ClusterMsgHeader data"); + Warning("Bad ClusterMsgHeader read on [%d.%d.%d.%d], restarting", DOT_SEPARATED(ip)); + Note("Cluster read from [%u.%u.%u.%u] failed, declaring down", DOT_SEPARATED(ip)); + machine_down(); + return -1; + } + + if (read.msg.count || read.msg.control_bytes) { + read.msg.state++; + read.state = ClusterState::READ_SETUP_DESCRIPTOR; + } else { + read.state = ClusterState::READ_COMPLETE; + } + break; + } + } + /////////////////////////////////////////////// + case ClusterState::READ_SETUP_DESCRIPTOR: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_setup_descriptor++; +#endif + if (build_initial_vector(CLUSTER_READ)) { + read.state = ClusterState::READ_DESCRIPTOR; + } else { + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_DESCRIPTOR: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_descriptor++; +#endif + read.state = ClusterState::READ_AWAIT_DESCRIPTOR; + if (!read.doIO()) { + // i/o not initiated, retry later + read.state = ClusterState::READ_DESCRIPTOR; + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_AWAIT_DESCRIPTOR: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_await_descriptor++; +#endif + if (!read.io_complete) { + return 0; + } else { + if (read.io_complete < 0) { + // read error, declare node down + machine_down(); + return -1; + } + } + if (read.to_do) { + if (read.bytes_xfered) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_PARTIAL_READS_STAT); + read.state = ClusterState::READ_DESCRIPTOR; + break; + } else { + // Zero byte read + read.state = ClusterState::READ_DESCRIPTOR; + return 0; + } + } else { +#ifdef CLUSTER_MESSAGE_CKSUM + ink_release_assert(read.msg.calc_descriptor_cksum() == read.msg.descriptor_cksum); + ink_release_assert(read.msg.calc_control_bytes_cksum() == read.msg.control_bytes_cksum); +#endif + CLUSTER_SUM_DYN_STAT(CLUSTER_READ_BYTES_STAT, read.did); + if (needByteSwap) { + // Descriptors need byte swap + swap_descriptor_bytes(); + } + if (read.msg.count == 0) { + read.bytes_xfered = 0; + read.state = ClusterState::READ_COMPLETE; + } else { + read.msg.state++; + read.state = ClusterState::READ_SETUP_DATA; + } + break; + } + } + /////////////////////////////////////////////// + case ClusterState::READ_SETUP_DATA: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_setup_data++; +#endif + if (build_initial_vector(CLUSTER_READ)) { + free_locks(CLUSTER_READ); + if (read.to_do) { + read.state = ClusterState::READ_DATA; + } else { + // Descriptor contains no VC data + read.state = ClusterState::READ_COMPLETE; + } + } else { + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_DATA: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_data++; +#endif + ink_release_assert(read.to_do); + read.state = ClusterState::READ_AWAIT_DATA; + if (!read.doIO()) { + // i/o not initiated, retry later + read.state = ClusterState::READ_DATA; + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_AWAIT_DATA: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_await_data++; +#endif + if (!read.io_complete) { + return 0; // awaiting i/o complete + } else { + if (read.io_complete > 0) { + read.state = ClusterState::READ_POST_COMPLETE; + } else { + // read error, declare node down + machine_down(); + return -1; + } + } + break; + } + /////////////////////////////////////////////// + case ClusterState::READ_POST_COMPLETE: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_post_complete++; +#endif + if (!get_read_locks()) { + return 0; + } + if (read.to_do) { + if (read.bytes_xfered) { + update_channels_partial_read(); + free_locks(CLUSTER_READ); + CLUSTER_SUM_DYN_STAT(CLUSTER_READ_BYTES_STAT, read.bytes_xfered); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_PARTIAL_READS_STAT); + read.state = ClusterState::READ_DATA; + return 1; + } else { + // Zero byte read + free_locks(CLUSTER_READ); + read.state = ClusterState::READ_DATA; + return 0; + } + } else { + CLUSTER_SUM_DYN_STAT(CLUSTER_READ_BYTES_STAT, read.bytes_xfered); + read.state = ClusterState::READ_COMPLETE; + break; + } + } + /////////////////////////////////////////////// + case ClusterState::READ_COMPLETE: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_read_complete++; +#endif + ink_hrtime rdmsg_end_time = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_RDMSG_ASSEMBLE_TIME_STAT, rdmsg_end_time - read.start_time); + read.start_time = HRTIME_MSECONDS(0); + if (dump_msgs) + dump_read_msg(); + read.sequence_number++; + update_channels_read(); + free_locks(CLUSTER_READ); + + read.state = ClusterState::READ_START; + break; // setup next read + } + ////////////////// + default: + ////////////////// + { + ink_release_assert(!"ClusterHandler::process_read invalid state"); + } + + } // end of switch + } // end of for +} + +int +ClusterHandler::process_write(ink_hrtime now, bool only_write_control_msgs) +{ +#ifdef CLUSTER_STATS + _process_write_calls++; +#endif + ///////////////////////////////// + // Cluster write state machine + ///////////////////////////////// + for (;;) { + + switch (write.state) { + /////////////////////////////////////////////// + case ClusterState::WRITE_START: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_write_start++; +#endif + write.msg.clear(); + write.last_time = ink_get_hrtime(); + pw_write_descriptors_built = -1; + pw_freespace_descriptors_built = -1; + pw_controldata_descriptors_built = -1; + pw_time_expired = 0; + write.state = ClusterState::WRITE_SETUP; + break; + } + /////////////////////////////////////////////// + case ClusterState::WRITE_SETUP: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_write_setup++; +#endif + if (!on_stolen_thread && !only_write_control_msgs) { + ///////////////////////////////////////////////////////////// + // Build a complete write descriptor containing control, + // data and freespace message data. + ///////////////////////////////////////////////////////////// + + // Control message descriptors + if (pw_controldata_descriptors_built) { + pw_controldata_descriptors_built = build_controlmsg_descriptors(); + } + // Write data descriptors + if (pw_write_descriptors_built) { + pw_write_descriptors_built = build_write_descriptors(); + } + // Free space descriptors + if (pw_freespace_descriptors_built) { + pw_freespace_descriptors_built = build_freespace_descriptors(); + } + add_small_controlmsg_descriptors(); // always last + } else { + ///////////////////////////////////////////////////////////// + // Build a write descriptor only containing control data. + ///////////////////////////////////////////////////////////// + pw_write_descriptors_built = 0; + pw_freespace_descriptors_built = 0; + pw_controldata_descriptors_built = build_controlmsg_descriptors(); + add_small_controlmsg_descriptors(); // always last + } + + // If nothing to write, post write completion + if (!pw_controldata_descriptors_built && !pw_write_descriptors_built && !pw_freespace_descriptors_built) { + write.state = ClusterState::WRITE_COMPLETE; + break; + } else { + started_on_stolen_thread = on_stolen_thread; + control_message_write = only_write_control_msgs; + } + + // Move required data into the message header +#ifdef CLUSTER_MESSAGE_CKSUM + write.msg.descriptor_cksum = write.msg.calc_descriptor_cksum(); + write.msg.hdr()->descriptor_cksum = write.msg.descriptor_cksum; + + write.msg.control_bytes_cksum = write.msg.calc_control_bytes_cksum(); + write.msg.hdr()->control_bytes_cksum = write.msg.control_bytes_cksum; + write.msg.unused = 0; +#endif + write.msg.hdr()->count = write.msg.count; + write.msg.hdr()->control_bytes = write.msg.control_bytes; + write.msg.hdr()->count_check = MAGIC_COUNT(write); + + ink_release_assert(build_initial_vector(CLUSTER_WRITE)); + free_locks(CLUSTER_WRITE); + write.state = ClusterState::WRITE_INITIATE; + break; + } + /////////////////////////////////////////////// + case ClusterState::WRITE_INITIATE: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_write_initiate++; +#endif + write.state = ClusterState::WRITE_AWAIT_COMPLETION; + if (!write.doIO()) { + // i/o not initiated, retry later + write.state = ClusterState::WRITE_INITIATE; + return 0; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::WRITE_AWAIT_COMPLETION: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_write_await_completion++; +#endif + if (!write.io_complete) { + // Still waiting for write i/o completion + return 0; + } else { + if (write.io_complete < 0) { + // write error, declare node down + machine_down(); + write.state = ClusterState::WRITE_INITIATE; + break; + } + if (write.to_do) { + if (write.bytes_xfered) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_PARTIAL_WRITES_STAT); + write.state = ClusterState::WRITE_INITIATE; + break; + } else { + // Zero byte write + write.state = ClusterState::WRITE_INITIATE; + return 0; + } + } + CLUSTER_SUM_DYN_STAT(CLUSTER_WRITE_BYTES_STAT, write.bytes_xfered); + write.sequence_number++; + write.state = ClusterState::WRITE_POST_COMPLETE; + } + break; + } + /////////////////////////////////////////////// + case ClusterState::WRITE_POST_COMPLETE: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_write_post_complete++; +#endif + if (!get_write_locks()) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_WRITE_LOCK_MISSES_STAT); + return 0; + } + // + // Move the channels into their new buckets based on how much + // was written + // + if (!control_message_write && !started_on_stolen_thread + && !pw_write_descriptors_built && !pw_freespace_descriptors_built && !pw_controldata_descriptors_built) { + update_channels_written(true); // bump unprocessed VC(s) + } else { + update_channels_written(false); // do not bump unprocessed VC(s) + } + free_locks(CLUSTER_WRITE); + write.state = ClusterState::WRITE_COMPLETE; + break; + } + /////////////////////////////////////////////// + case ClusterState::WRITE_COMPLETE: + /////////////////////////////////////////////// + { +#ifdef CLUSTER_STATS + _n_write_complete++; +#endif + write.state = ClusterState::WRITE_START; + ink_hrtime curtime = ink_get_hrtime(); + + if (!on_stolen_thread) { + // + // Complete all work in the current bucket before moving to next + // + pw_time_expired = (curtime - now) > CLUSTER_MAX_RUN_TIME; + + if (!control_message_write && !pw_write_descriptors_built + && !pw_freespace_descriptors_built && !pw_controldata_descriptors_built) { + // skip to the next bucket + cur_vcs = (cur_vcs + 1) % CLUSTER_BUCKETS; + } + } else { + // + // Place an upper bound on thread stealing + // + pw_time_expired = (curtime - now) > CLUSTER_MAX_THREAD_STEAL_TIME; + if (pw_time_expired) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_THREAD_STEAL_EXPIRES_STAT); + } + } + // + // periodic activities + // + if (!on_stolen_thread && !cur_vcs && !machine->dead) { + // + // check if this machine is supposed to be in the cluster + // + MachineList *mc = the_cluster_machines_config(); + if (mc && !mc->find(ip, port)) { + Note("Cluster [%u.%u.%u.%u:%d] not in config, declaring down", DOT_SEPARATED(ip), port); + machine_down(); + } + } + if (pw_time_expired) { + return -1; // thread run time expired + } else { + if (pw_write_descriptors_built || pw_freespace_descriptors_built || pw_controldata_descriptors_built) { + break; // start another write + } else { + return 0; // no more data to write + } + } + } + ////////////////// + default: + ////////////////// + { + ink_release_assert(!"ClusterHandler::process_write invalid state"); + } + + } // End of switch + } // End of for +} + +int +ClusterHandler::do_open_local_requests() +{ + // + // open_local requests which are unable to obtain the ClusterHandler + // mutex are deferred and placed onto external_incoming_open_local queue. + // It is here where we process the open_local requests within the + // ET_CLUSTER thread. + // + int pending_request = 0; + ClusterVConnection *cvc; + ClusterVConnection *cvc_ext; + ClusterVConnection *cvc_ext_next; + EThread *tt = this_ethread(); + Queue local_incoming_open_local; + + // + // Atomically dequeue all requests from the external queue and + // move them to the local working queue while maintaining insertion order. + // + while (true) { + cvc_ext = (ClusterVConnection *) + ink_atomiclist_popall(&external_incoming_open_local); + if (cvc_ext == 0) + break; + + while (cvc_ext) { + cvc_ext_next = (ClusterVConnection *) cvc_ext->link.next; + cvc_ext->link.next = NULL; + local_incoming_open_local.push(cvc_ext); + cvc_ext = cvc_ext_next; + } + + // Process deferred open_local requests. + + while ((cvc = local_incoming_open_local.pop())) { + MUTEX_TRY_LOCK(lock, cvc->action_.mutex, tt); + if (lock) { + if (cvc->start(tt) < 0) { + cvc->token.clear(); + if (cvc->action_.continuation) { + cvc->action_.continuation->handleEvent(CLUSTER_EVENT_OPEN_FAILED, 0); + clusterVCAllocator.free(cvc); + } + } + MUTEX_RELEASE(lock); + + } else { + // unable to get mutex, insert request back onto global queue. + Debug(CL_TRACE, "do_open_local_requests() unable to acquire mutex (cvc=0x%x)", cvc); + pending_request = 1; + ink_atomiclist_push(&external_incoming_open_local, (void *) cvc); + } + } + } + return pending_request; +} + +// End of ClusterHandler.cc diff --git a/iocore/cluster/ClusterHandlerBase.cc b/iocore/cluster/ClusterHandlerBase.cc new file mode 100644 index 00000000..a6ee3dd2 --- /dev/null +++ b/iocore/cluster/ClusterHandlerBase.cc @@ -0,0 +1,1418 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ClusterHandlerBase.cc +****************************************************************************/ + +#include "P_Cluster.h" + +extern int cluster_receive_buffer_size; +extern int cluster_send_buffer_size; +extern uint32_t cluster_sockopt_flags; + +/////////////////////////////////////////////////////////////// +// Incoming message continuation for periodic callout threads +/////////////////////////////////////////////////////////////// + +ClusterCalloutContinuation::ClusterCalloutContinuation(struct ClusterHandler *ch) + : +Continuation(0), +_ch(ch) +{ + mutex = new_ProxyMutex(); + SET_HANDLER((ClstCoutContHandler) + & ClusterCalloutContinuation::CalloutHandler); +} + +ClusterCalloutContinuation::~ClusterCalloutContinuation() +{ + mutex = 0; +} + +int +ClusterCalloutContinuation::CalloutHandler(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + return _ch->process_incoming_callouts(this->mutex); +} + +/*************************************************************************/ +// ClusterControl member functions (Internal Class) +/*************************************************************************/ +ClusterControl::ClusterControl(): +Continuation(NULL), len(0), size_index(-1), real_data(0), data(0), free_proc(0), free_proc_arg(0), iob_block(0) +{ +} + +void +ClusterControl::real_alloc_data(int read_access, bool align_int32_on_non_int64_boundary) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + ink_assert(!data); + if ((len + DATA_HDR + sizeof(int32_t)) <= DEFAULT_MAX_BUFFER_SIZE) { + size_index = buffer_size_to_index(len + DATA_HDR + sizeof(int32_t), MAX_BUFFER_SIZE_INDEX); + iob_block = new_IOBufferBlock(); + iob_block->alloc(size_index); // aligns on 8 byte boundary + real_data = (int64_t *) iob_block->buf(); + + if (align_int32_on_non_int64_boundary) { + data = ((char *) real_data) + sizeof(int32_t) + DATA_HDR; + } else { + data = ((char *) real_data) + DATA_HDR; + } +#ifdef PURIFY + memset((char *) real_data, 0, BUFFER_SIZE_FOR_INDEX(size_index)); +#endif + } else { + int size = sizeof(int64_t) * (((len + DATA_HDR + sizeof(int32_t) + sizeof(int64_t) - 1) / sizeof(int64_t)) + 1); + size_index = -1; + iob_block = new_IOBufferBlock(); + iob_block->alloc(BUFFER_SIZE_FOR_XMALLOC(size)); + real_data = (int64_t *) iob_block->buf(); + + if (align_int32_on_non_int64_boundary) { + data = (char *) DOUBLE_ALIGN(real_data) + sizeof(int32_t) + DATA_HDR; + } else { + data = (char *) DOUBLE_ALIGN(real_data) + DATA_HDR; + } + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_ALLOC_DATA_NEWS_STAT); +#ifdef PURIFY + memset((char *) real_data, 0, size); +#endif + } + + // IOBufferBlock adjustments + if (read_access) { + // Make iob_block->read_avail() == len + iob_block->fill((char *) data - (char *) real_data); // skip header + iob_block->consume((char *) data - (char *) real_data); // skip header + iob_block->fill(len); + } else { + // Make iob_block->write_avail() == len + iob_block->fill((char *) data - (char *) real_data); // skip header + iob_block->consume((char *) data - (char *) real_data); // skip header + iob_block->_buf_end = iob_block->end() + len; + } + + // Write size_index, magic number and 'this' in leading bytes + char *size_index_ptr = (char *) data - DATA_HDR; + *size_index_ptr = size_index; + ++size_index_ptr; + + *size_index_ptr = (char) ALLOC_DATA_MAGIC; + ++size_index_ptr; + + void *val = (void *) this; + memcpy(size_index_ptr, (char *) &val, sizeof(void *)); +} + +void +ClusterControl::free_data() +{ + if (data && iob_block) { + if (free_proc) { + // Free memory via callback proc + (*free_proc) (free_proc_arg); + iob_block = 0; // really free memory + return; + } + if (real_data) { + ink_release_assert(*(((uint8_t *) data) - DATA_HDR + 1) == (uint8_t) ALLOC_DATA_MAGIC); + *(((uint8_t *) data) - DATA_HDR + 1) = (uint8_t) ~ ALLOC_DATA_MAGIC; + + ink_release_assert(*(((char *) data) - DATA_HDR) == size_index); + } else { + // malloc'ed memory, not alloced via real_alloc_data(). + // Data will be xfree()'ed when IOBufferBlock is freed + } + iob_block = 0; // free memory + } +} + +/*************************************************************************/ +// IncomingControl member functions (Internal Class) +/*************************************************************************/ +IncomingControl * +IncomingControl::alloc() +{ + return inControlAllocator.alloc(); +} + +IncomingControl::IncomingControl() +:recognized_time(0) +{ +} + +void +IncomingControl::freeall() +{ + free_data(); + inControlAllocator.free(this); +} + +/*************************************************************************/ +// OutgoingControl member functions (Internal Class) +/*************************************************************************/ +OutgoingControl * +OutgoingControl::alloc() +{ + return outControlAllocator.alloc(); +} + +OutgoingControl::OutgoingControl() +:m(NULL), submit_time(0) +{ +} + +int +OutgoingControl::startEvent(int event, Event * e) +{ + // + // This event handler is used by ClusterProcessor::invoke_remote() + // to delay (CLUSTER_OPT_DELAY) the enqueuing of the control message. + // + (void) event; + (void) e; + ClusterHandler *ch = m->clusterHandler; + // verify that the machine has not gone down + if (!ch || !ch->thread) + return EVENT_DONE; + + int32_t cluster_fn = *(int32_t *) this->data; + int32_t pri = ClusterFuncToQpri(cluster_fn); + ink_atomiclist_push(&ch->outgoing_control_al[pri], (void *) this); + + return EVENT_DONE; +} + +void +OutgoingControl::freeall() +{ + free_data(); + outControlAllocator.free(this); +} + +/*************************************************************************/ +// ClusterState member functions (Internal Class) +/*************************************************************************/ +ClusterState::ClusterState(ClusterHandler * c, bool read_chan): +Continuation(0), +ch(c), +read_channel(read_chan), +do_iodone_event(false), +n_descriptors(0), +sequence_number(0), +to_do(0), +did(0), +n_iov(0), +io_complete(1), +io_complete_event(0), +v(0), +bytes_xfered(0), +last_ndone(0), +total_bytes_xfered(0), +iov(NULL), +iob_iov(NULL), +byte_bank(NULL), +n_byte_bank(0), byte_bank_size(0), missed(0), missed_msg(false), read_state_t(READ_START), write_state_t(WRITE_START) +{ + mutex = new_ProxyMutex(); + if (read_channel) { + state = ClusterState::READ_START; + SET_HANDLER(&ClusterState::doIO_read_event); + } else { + state = ClusterState::WRITE_START; + SET_HANDLER(&ClusterState::doIO_write_event); + } + last_time = HRTIME_SECONDS(0); + start_time = HRTIME_SECONDS(0); + int size; + // + // Note: we allocate space for maximum iovec(s), descriptor(s) + // and small control message data. + // + + ////////////////////////////////////////////////// + // Place an invalid page in front of iovec data. + ////////////////////////////////////////////////// + size_t pagesize = (size_t) getpagesize(); + size = ((MAX_TCOUNT + 1) * sizeof(IOVec)) + (2 * pagesize); + iob_iov = new_IOBufferData(BUFFER_SIZE_FOR_XMALLOC(size)); + char *addr = (char *) align_pointer_forward(iob_iov->data(), pagesize); + +#if defined(__sparc) + if (mprotect(addr, pagesize, PROT_NONE)) + perror("ClusterState mprotect0 failed"); +#endif + iov = (IOVec *) (addr + pagesize); + + /////////////////////////////////////////////////// + // Place an invalid page in front of message data. + /////////////////////////////////////////////////// + size = sizeof(ClusterMsgHeader) + (MAX_TCOUNT + 1) * sizeof(Descriptor) + + CONTROL_DATA + (2 * pagesize); + msg.iob_descriptor_block = new_IOBufferBlock(); + msg.iob_descriptor_block->alloc(BUFFER_SIZE_FOR_XMALLOC(size)); + + addr = (char *) align_pointer_forward(msg.iob_descriptor_block->data->data(), pagesize); + +#if defined(__sparc) + if (mprotect(addr, pagesize, PROT_NONE)) + perror("ClusterState mprotect failed"); +#endif + addr = addr + pagesize; + memset(addr, 0, size - (2 * pagesize)); + msg.descriptor = (Descriptor *) (addr + sizeof(ClusterMsgHeader)); + + mbuf = new_empty_MIOBuffer(); +} + +ClusterState::~ClusterState() +{ + mutex = 0; +#if defined(__sparc) + int pagesize = getpagesize(); +#endif + if (iov) { +#if defined(__sparc) + iov = (IOVec *) ((char *) iov - pagesize); + if (mprotect((char *) iov, pagesize, (PROT_READ | PROT_WRITE))) + perror("~ClusterState mprotect0 failed"); +#endif + iob_iov = 0; // Free memory + } + + if (msg.descriptor) { +#if defined(__sparc) + char *a = (char *) msg.descriptor - (sizeof(ClusterMsgHeader) + pagesize); + if (mprotect(a, pagesize, (PROT_READ | PROT_WRITE))) + perror("~ClusterState mprotect failed"); +#endif + msg.iob_descriptor_block = 0; // Free memory + } + // Deallocate IO Core structures + int n; + for (n = 0; n < MAX_TCOUNT; ++n) { + block[n] = 0; + } + free_empty_MIOBuffer(mbuf); + mbuf = 0; +} + +void +ClusterState::build_do_io_vector() +{ + // + // Construct the do_io_xxx data structures allowing transfer + // of the data described by the iovec structure. + // + int bytes_to_xfer = 0; + int n; + IOBufferBlock *last_block = 0; + + mbuf->clear(); + + // Build the IOBufferBlock chain. + + for (n = 0; n < n_iov; ++n) { + bytes_to_xfer += iov[n].iov_len; + + if (last_block) { + last_block->next = block[n]; + } + last_block = block[n]; + while (last_block->next) { + last_block = last_block->next; + } + } + mbuf->_writer = block[0]; + ink_release_assert(bytes_to_xfer == to_do); + ink_assert(bytes_to_xfer == bytes_IOBufferBlockList(mbuf->_writer, !read_channel)); +} + +#ifdef CLUSTER_TOMCAT +#define REENABLE_IO() \ + if (!ch->on_stolen_thread && !io_complete) { \ + v->reenable_re(); \ + } + +#else // !CLUSTER_TOMCAT + +#ifdef CLUSTER_IMMEDIATE_NETIO +#define REENABLE_IO() \ + if (!io_complete) { \ + ((NetVConnection *) v->vc_server)->reenable_re_now(v); \ + } + +#else // !CLUSTER_IMMEDIATE_NETIO + +#define REENABLE_IO() \ + if (!io_complete) { \ + v->reenable_re(); \ + } +#endif // !CLUSTER_IMMEDIATE_NETIO + +#endif // !CLUSTER_TOMCAT + +int +ClusterState::doIO() +{ + ink_release_assert(io_complete); +#if !defined(CLUSTER_IMMEDIATE_NETIO) + MUTEX_TRY_LOCK(lock, this->mutex, this_ethread()); + if (!lock) { + return 0; // unable to initiate operation + } +#endif + + if (!ch->net_vc) { + // Node has gone down, simulate successful transfer + io_complete = 1; + bytes_xfered += to_do; + to_do = 0; + return 1; + } + // + // Setup and initiate or resume Cluster i/o request to the NetProcessor. + // + if ((to_do && (io_complete_event == VC_EVENT_READ_READY)) || (io_complete_event == VC_EVENT_WRITE_READY)) { + + if (read_channel) { + // Partial read case + ink_assert(v->buffer.writer()->current_write_avail() == to_do); + + } else { + // Partial write case + ink_assert(v->buffer.reader()->read_avail() == to_do); + } + + // Resume operation + v->nbytes = to_do + did; + ink_release_assert(v->nbytes > v->ndone); + + io_complete = false; + io_complete_event = 0; + REENABLE_IO(); + + } else { + // Start new do_io_xxx operation. + // Initialize globals + + io_complete = false; + io_complete_event = 0; + bytes_xfered = 0; + last_ndone = 0; + + build_do_io_vector(); + + if (read_channel) { + ink_assert(mbuf->current_write_avail() == to_do); +#ifdef CLUSTER_IMMEDIATE_NETIO + v = ch->net_vc->do_io_read_now(this, to_do, mbuf); +#else + v = ch->net_vc->do_io_read(this, to_do, mbuf); +#endif + REENABLE_IO(); + + } else { + IOBufferReader *r = mbuf->alloc_reader(); + r->block = mbuf->_writer; + ink_assert(r->read_avail() == to_do); +#ifdef CLUSTER_IMMEDIATE_NETIO + v = ch->net_vc->do_io_write_now(this, to_do, r); +#else + v = ch->net_vc->do_io_write(this, to_do, r); +#endif + REENABLE_IO(); + } + } + return 1; // operation initiated +} + +int +ClusterState::doIO_read_event(int event, void *d) +{ + ink_release_assert(!io_complete); + if (!v) { + v = (VIO *) d; // Immediate callback on first NetVC read + } + ink_assert((VIO *) d == v); + + switch (event) { + case VC_EVENT_READ_READY: + { + // Disable read processing + v->nbytes = v->ndone; + // fall through + } + case VC_EVENT_READ_COMPLETE: + { + bytes_xfered = v->ndone - last_ndone; + if (bytes_xfered) { + total_bytes_xfered += bytes_xfered; + did += bytes_xfered; + to_do -= bytes_xfered; + } + last_ndone = v->ndone; + io_complete_event = event; + INK_WRITE_MEMORY_BARRIER; + + io_complete = 1; + IOComplete(); + + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + default: + { + io_complete_event = event; + INK_WRITE_MEMORY_BARRIER; + + io_complete = -1; + IOComplete(); + break; + } + } // End of switch + + return EVENT_DONE; +} + +int +ClusterState::doIO_write_event(int event, void *d) +{ + ink_release_assert(!io_complete); + if (!v) { + v = (VIO *) d; // Immediate callback on first NetVC write + } + ink_assert((VIO *) d == v); + + switch (event) { + case VC_EVENT_WRITE_READY: +#ifdef CLUSTER_IMMEDIATE_NETIO + { + // Disable write processing + v->nbytes = v->ndone; + // fall through + } +#endif + case VC_EVENT_WRITE_COMPLETE: + { + bytes_xfered = v->ndone - last_ndone; + if (bytes_xfered) { + total_bytes_xfered += bytes_xfered; + did += bytes_xfered; + to_do -= bytes_xfered; + } + last_ndone = v->ndone; +#ifdef CLUSTER_IMMEDIATE_NETIO + io_complete_event = event; + INK_WRITE_MEMORY_BARRIER; + + io_complete = 1; + IOComplete(); +#else + if (event == VC_EVENT_WRITE_COMPLETE) { + io_complete_event = event; + INK_WRITE_MEMORY_BARRIER; + + io_complete = 1; + IOComplete(); + } else { + if (bytes_xfered) { + v->reenable_re(); // Immediate action + } else { + v->reenable(); + } + return EVENT_DONE; + } +#endif + break; + } + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + default: + { + io_complete_event = event; + INK_WRITE_MEMORY_BARRIER; + + io_complete = -1; + IOComplete(); + break; + } + } // End of switch + + return EVENT_DONE; +} + +void +ClusterState::IOComplete() +{ + // If no thread appears (approximate check) to be holding + // the ClusterHandler mutex (no cluster processing in progress) + // and immediate i/o completion events are allowed, + // start i/o completion processing. + + if (do_iodone_event && !ch->mutex->thread_holding) { + MUTEX_TRY_LOCK(lock, ch->mutex, this_ethread()); + if (lock) { + ch->handleEvent(EVENT_IMMEDIATE, (void *) 0); + } else { + eventProcessor.schedule_imm(ch, ET_CLUSTER); + } + } +} + +int +ClusterHandler::cluster_signal_and_update(int event, ClusterVConnection * vc, ClusterVConnState * s) +{ + s->vio._cont->handleEvent(event, &s->vio); + + if (vc->closed) { + if (!vc->write_list && !vc->write_bytes_in_transit) { + close_ClusterVConnection(vc); + } + return EVENT_DONE; + } else { + ink_assert((event != VC_EVENT_ERROR) || ((event == VC_EVENT_ERROR) && vc->closed)); + return EVENT_CONT; + } +} + +int +ClusterHandler::cluster_signal_and_update_locked(int event, ClusterVConnection * vc, ClusterVConnState * s) +{ + // should assert we have s->vio.mutex + s->vio._cont->handleEvent(event, &s->vio); + + if (vc->closed) { + if (!vc->write_list && !vc->write_bytes_in_transit) { + close_free_lock(vc, s); + } + return EVENT_DONE; + } else + return EVENT_CONT; +} + +int +ClusterHandler::cluster_signal_error_and_update(ClusterVConnection * vc, ClusterVConnState * s, int lerrno) +{ + s->enabled = 0; + vc->lerrno = lerrno; + return cluster_signal_and_update(VC_EVENT_ERROR, vc, s); +} + +bool ClusterHandler::check_channel(int c) +{ + // + // Check to see that there is enough room to store channel c + // + while (n_channels <= c) { + int + old_channels = n_channels; + if (!n_channels) { + n_channels = MIN_CHANNELS; + } else { + if ((n_channels * 2) <= MAX_CHANNELS) { + n_channels = n_channels * 2; + } else { + return false; // Limit exceeded + } + } + // Allocate ClusterVConnection table entries + channels = (ClusterVConnection **) + xrealloc(channels, n_channels * sizeof(ClusterVConnection *)); + + // Allocate ChannelData table entries + channel_data = (struct ChannelData **) + xrealloc(channel_data, n_channels * sizeof(struct ChannelData *)); + + for (int i = old_channels; i < n_channels; i++) { + if (local_channel(i)) { + if (i > LAST_DEDICATED_CHANNEL) { + channels[i] = (ClusterVConnection *) 1; // mark as invalid + channel_data[i] = (struct ChannelData *) + xmalloc(sizeof(struct ChannelData)); + memset(channel_data[i], 0, sizeof(struct ChannelData)); + channel_data[i]->channel_number = i; + free_local_channels.enqueue(channel_data[i]); + } else { + channels[i] = NULL; + channel_data[i] = NULL; + } + } else { + channels[i] = NULL; + channel_data[i] = NULL; + } + } + } + return true; // OK +} + +int +ClusterHandler::alloc_channel(ClusterVConnection * vc, int requested) +{ + // + // Allocate a channel + // + struct ChannelData *cdp = 0; + int i = requested; + + if (!i) { + int loops = 1; + do { + cdp = free_local_channels.dequeue(); + if (!cdp) { + if (!check_channel(n_channels)) { + return -2; // Limit exceeded + } + } else { + ink_assert(cdp == channel_data[cdp->channel_number]); + i = cdp->channel_number; + break; + } + } while (loops--); + + ink_release_assert(i != 0); // required + ink_release_assert(channels[i] == (ClusterVConnection *) 1); // required + Debug(CL_TRACE, "alloc_channel local chan=%d VC=0x%x", i, vc); + + } else { + if (!check_channel(i)) { + return -2; // Limit exceeded + } + if (channels[i]) { + Debug(CL_TRACE, "alloc_channel remote inuse chan=%d VC=0x%x", i, vc); + return -1; // channel in use + } else { + Debug(CL_TRACE, "alloc_channel remote chan=%d VC=0x%x", i, vc); + } + } + channels[i] = vc; + vc->channel = i; + return i; +} + +void +ClusterHandler::free_channel(ClusterVConnection * vc) +{ + // + // Free a channel + // + int i = vc->channel; + if (i > LAST_DEDICATED_CHANNEL && channels[i] == vc) { + if (local_channel(i)) { + channels[i] = (ClusterVConnection *) 1; + free_local_channels.enqueue(channel_data[i]); + Debug(CL_TRACE, "free_channel local chan=%d VC=0x%x", i, vc); + } else { + channels[i] = 0; + Debug(CL_TRACE, "free_channel remote chan=%d VC=0x%x", i, vc); + } + } + vc->channel = 0; +} + +int +ClusterHandler::machine_down() +{ + char textbuf[sizeof("255.255.255.255:65535")]; + + if (machine->dead) { + return EVENT_DONE; + } + // + // Looks like this machine dropped out of the cluster. + // Deal with it. + // Fatal read/write errors on the node to node connection along + // with failure of the cluster membership check in the periodic event + // result in machine_down(). + // +#ifdef LOCAL_CLUSTER_TEST_MODE + Note("machine down %u.%u.%u.%u:%d", DOT_SEPARATED(ip), port); +#else + Note("machine down %u.%u.%u.%u", DOT_SEPARATED(ip)); +#endif +#ifdef NON_MODULAR + machine_offline_APIcallout(ip); +#endif + snprintf(textbuf, sizeof(textbuf), "%hhu.%hhu.%hhu.%hhu:%d", DOT_SEPARATED(ip), port); + REC_SignalManager(REC_SIGNAL_MACHINE_DOWN, textbuf); + if (net_vc) { + net_vc->do_io(VIO::CLOSE); + net_vc = 0; + } + // Cancel pending cluster reads and writes + read.io_complete = -1; + write.io_complete = -1; + + MUTEX_TAKE_LOCK(the_cluster_config_mutex, this_ethread()); + ClusterConfiguration *c = this_cluster()->current_configuration(); + if (c->find(ip, port)) { + ClusterConfiguration *cc = configuration_remove_machine(c, machine); + CLUSTER_DECREMENT_DYN_STAT(CLUSTER_NODES_STAT); + this_cluster()->configurations.push(cc); + } + MUTEX_UNTAKE_LOCK(the_cluster_config_mutex, this_ethread()); + MachineList *cc = the_cluster_config(); + if (cc && cc->find(ip, port) && connector) { + Debug(CL_NOTE, "cluster connect retry for %hhu.%hhu.%hhu.%hhu", DOT_SEPARATED(ip)); + clusterProcessor.connect(ip, port); + } + return zombify(); // defer deletion of *this +} + +int +ClusterHandler::zombify(Event * e) +{ + NOWARN_UNUSED(e); + // + // Node associated with *this is declared down, setup the event to cleanup + // and defer deletion of *this + // + machine->clusterHandler = NULL; + machine->dead = true; + if (cluster_periodic_event) { + cluster_periodic_event->cancel(this); + cluster_periodic_event = NULL; + } + clm->cancel_monitor(); + + SET_HANDLER((ClusterContHandler) & ClusterHandler::protoZombieEvent); + // + // At this point, allow the caller (either process_read/write to complete) + // prior to performing node down actions. + // + eventProcessor.schedule_in(this, HRTIME_SECONDS(1), ET_CLUSTER); + return EVENT_DONE; +} + +int +ClusterHandler::connectClusterEvent(int event, Event * e) +{ + + if ((event == EVENT_IMMEDIATE) || (event == EVENT_INTERVAL)) { + // + // Attempt connect to target node and if successful, setup the event + // to initiate the node to node connection protocol. + // Initiated via ClusterProcessor::connect(). + // + MachineList *cc = the_cluster_config(); + if (!machine) + machine = NEW(new ClusterMachine(hostname, ip, port)); +#ifdef LOCAL_CLUSTER_TEST_MODE + if (!(cc && cc->find(ip, port))) { +#else + if (this_cluster_machine()->ip == machine->ip || !(cc && cc->find(ip, port))) { +#endif + if (this_cluster_machine()->ip != machine->ip) + Debug(CL_NOTE, "cluster connect aborted, machine %u.%u.%u.%u not in cluster", DOT_SEPARATED(machine->ip)); + delete machine; + machine = NULL; + delete this; + return EVENT_DONE; + } + // Connect to cluster member + Debug(CL_NOTE, "connect_re from %u.%u.%u.%u to %u.%u.%u.%u", + DOT_SEPARATED(this_cluster_machine()->ip), DOT_SEPARATED(machine->ip)); + ip = machine->ip; + + NetVCOptions opt; + opt.socket_send_bufsize = cluster_send_buffer_size; + opt.socket_recv_bufsize = cluster_receive_buffer_size; + opt.sockopt_flags = cluster_sockopt_flags; + opt.etype = ET_CLUSTER; + opt.addr_binding = NetVCOptions::INTF_ADDR; + opt.local_addr = this_cluster_machine()->ip; + + // TODO: Should we check the Action* returned here? + netProcessor.connect_re(this, machine->ip, + machine->cluster_port + ? machine->cluster_port + : cluster_port, + &opt); + return EVENT_DONE; + } else { + if (event == NET_EVENT_OPEN) { + net_vc = (NetVConnection *) e; + SET_HANDLER((ClusterContHandler) & ClusterHandler::startClusterEvent); + eventProcessor.schedule_imm(this, ET_CLUSTER); + return EVENT_DONE; + + } else { + eventProcessor.schedule_in(this, CLUSTER_MEMBER_DELAY); + return EVENT_CONT; + } + } +} + +int +ClusterHandler::startClusterEvent(int event, Event * e) +{ + char textbuf[sizeof("255.255.255.255:65535")]; + + // Perform the node to node connection establish protocol. + + (void) event; + ink_assert(!read_vcs); + ink_assert(!write_vcs); + + if (event == EVENT_IMMEDIATE) { + if (cluster_connect_state == ClusterHandler::CLCON_INITIAL) { + cluster_connect_state = ClusterHandler::CLCON_SEND_MSG; + } else { + ink_release_assert(!"startClusterEvent, EVENT_IMMEDIATE not expected"); + } + } else { + ink_release_assert(event == EVENT_INTERVAL); + } + + for (;;) { + + switch (cluster_connect_state) { + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_INITIAL: + //////////////////////////////////////////////////////////////////////////// + { + ink_release_assert(!"Invalid state [CLCON_INITIAL]"); + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_SEND_MSG: + //////////////////////////////////////////////////////////////////////////// + { + // Send initial message. +#ifdef LOCAL_CLUSTER_TEST_MODE + nodeClusteringVersion._port = cluster_port; +#endif + cluster_connect_state = ClusterHandler::CLCON_SEND_MSG_COMPLETE; + build_data_vector((char *) &nodeClusteringVersion, sizeof(nodeClusteringVersion), false); + if (!write.doIO()) { + // i/o not initiated, delay and retry + cluster_connect_state = ClusterHandler::CLCON_SEND_MSG; + eventProcessor.schedule_in(this, CLUSTER_PERIOD, ET_CLUSTER); + return EVENT_DONE; + } + break; + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_SEND_MSG_COMPLETE: + //////////////////////////////////////////////////////////////////////////// + { + if (write.io_complete) { + if ((write.io_complete < 0) + || ((size_t) write.did < sizeof(nodeClusteringVersion))) { + Debug(CL_NOTE, "unable to write to cluster node %u.%u.%u.%u: %d", + DOT_SEPARATED(ip), write.io_complete_event); + cluster_connect_state = ClusterHandler::CLCON_ABORT_CONNECT; + break; // goto next state + } + // Write OK, await message from peer node. + build_data_vector((char *) &clusteringVersion, sizeof(clusteringVersion), true); + cluster_connect_state = ClusterHandler::CLCON_READ_MSG; + break; + } else { + // Delay and check for i/o completion + eventProcessor.schedule_in(this, CLUSTER_PERIOD, ET_CLUSTER); + return EVENT_DONE; + } + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_READ_MSG: + //////////////////////////////////////////////////////////////////////////// + { + cluster_connect_state = ClusterHandler::CLCON_READ_MSG_COMPLETE; + if (!read.doIO()) { + // i/o not initiated, delay and retry + cluster_connect_state = ClusterHandler::CLCON_READ_MSG; + eventProcessor.schedule_in(this, CLUSTER_PERIOD, ET_CLUSTER); + return EVENT_DONE; + } + break; + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_READ_MSG_COMPLETE: + //////////////////////////////////////////////////////////////////////////// + { + if (read.io_complete) { + if (read.io_complete < 0) { + // Read error, abort connect + cluster_connect_state = ClusterHandler::CLCON_ABORT_CONNECT; + break; // goto next state + } + if ((size_t) read.did < sizeof(clusteringVersion)) { + // Partial read, resume read. + cluster_connect_state = ClusterHandler::CLCON_READ_MSG; + break; + } + cluster_connect_state = ClusterHandler::CLCON_VALIDATE_MSG; + break; + } else { + // Delay and check for i/o completion + eventProcessor.schedule_in(this, CLUSTER_PERIOD, ET_CLUSTER); + return EVENT_DONE; + } + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_VALIDATE_MSG: + //////////////////////////////////////////////////////////////////////////// + { + int proto_major = -1; + int proto_minor = -1; + int failed = 0; + + clusteringVersion.AdjustByteOrder(); + ///////////////////////////////////////////////////////////////////////// + // Determine the message protocol major version to use, by stepping down + // from current to the minimium level until a match is found. + // Derive the minor number as follows, if the current (major, minor) + // is the current node (major, minor) use the given minor number. + // Otherwise, minor number is zero. + ///////////////////////////////////////////////////////////////////////// + for (int major = clusteringVersion._major; major >= clusteringVersion._min_major; --major) { + if ((major >= nodeClusteringVersion._min_major) && (major <= nodeClusteringVersion._major)) { + proto_major = major; + } + } + if (proto_major > 0) { + /////////////////////////// + // Compute minor version + /////////////////////////// + if (proto_major == clusteringVersion._major) { + proto_minor = clusteringVersion._minor; + + if (proto_minor != nodeClusteringVersion._minor) + Warning("Different clustering minor versions (%d,%d) for node %u.%u.%u.%u, continuing", + proto_minor, nodeClusteringVersion._minor, DOT_SEPARATED(ip)); + } else { + proto_minor = 0; + } + + } else { + Warning("Bad cluster major version range (%d-%d) for node %u.%u.%u.%u connect failed", + clusteringVersion._min_major, clusteringVersion._major, DOT_SEPARATED(ip)); + cluster_connect_state = ClusterHandler::CLCON_ABORT_CONNECT; + break; // goto next state + } + + // include this node into the cluster configuration + MUTEX_TAKE_LOCK(the_cluster_config_mutex, this_ethread()); + MachineList *cc = the_cluster_config(); +#ifdef LOCAL_CLUSTER_TEST_MODE + port = clusteringVersion._port & 0xffff; +#endif + if (cc && cc->find(ip, port)) { + ClusterConfiguration *c = this_cluster()->current_configuration(); + if (!c->find(ip, port)) { + ClusterConfiguration *cconf = configuration_add_machine(c, machine); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_NODES_STAT); + this_cluster()->configurations.push(cconf); + } else { + // duplicate cluster connect, ignore + failed = -2; + Debug(CL_NOTE, "duplicate cluster connect %u.%u.%u.%u", DOT_SEPARATED(ip)); + } + } else { + Debug(CL_NOTE, "cluster connect aborted, machine %u.%u.%u.%u:%d not in cluster", DOT_SEPARATED(ip), port); + failed = -1; + } + MUTEX_UNTAKE_LOCK(the_cluster_config_mutex, this_ethread()); + + if (failed) { + if (failed == -1) { + if (++configLookupFails <= CONFIG_LOOKUP_RETRIES) { + eventProcessor.schedule_in(this, HRTIME_SECONDS(1), ET_CLUSTER); + return EVENT_DONE; + } + } + cluster_connect_state = ClusterHandler::CLCON_DELETE_CONNECT; + break; // goto next state + } + + this->needByteSwap = !clusteringVersion.NativeByteOrder(); + machine->clusterHandler = this; + machine->msg_proto_major = proto_major; + machine->msg_proto_minor = proto_minor; +#ifdef NON_MODULAR + machine_online_APIcallout(ip); +#endif + // Signal the manager + snprintf(textbuf, sizeof(textbuf), "%hhu.%hhu.%hhu.%hhu:%d", DOT_SEPARATED(ip), port); + REC_SignalManager(REC_SIGNAL_MACHINE_UP, textbuf); +#ifdef LOCAL_CLUSTER_TEST_MODE + Note("machine up %hhu.%hhu.%hhu.%hhu:%d, protocol version=%d.%d", + DOT_SEPARATED(ip), port, clusteringVersion._major, clusteringVersion._minor); +#else + Note("machine up %hhu.%hhu.%hhu.%hhu, protocol version=%d.%d", + DOT_SEPARATED(ip), clusteringVersion._major, clusteringVersion._minor); +#endif + thread = e->ethread; + read_vcs = NEW((new Queue[CLUSTER_BUCKETS])); + write_vcs = NEW((new Queue[CLUSTER_BUCKETS])); + SET_HANDLER((ClusterContHandler) & ClusterHandler::beginClusterEvent); + + // enable schedule_imm() on i/o completion (optimization) + read.do_iodone_event = true; + write.do_iodone_event = true; + +#ifdef CLUSTER_IMMEDIATE_NETIO + e->schedule_every(-CLUSTER_PERIOD); // Negative event +#else + e->schedule_every(CLUSTER_PERIOD); +#endif + cluster_periodic_event = e; + + // Startup the periodic events to process entries in + // external_incoming_control. + +#if defined(freebsd) + int procs_online = 1; +#else + int procs_online = sysconf(_SC_NPROCESSORS_ONLN); +#endif + int total_callbacks = min(procs_online, MAX_COMPLETION_CALLBACK_EVENTS); + for (int n = 0; n < total_callbacks; ++n) { + callout_cont[n] = NEW(new ClusterCalloutContinuation(this)); + callout_events[n] = eventProcessor.schedule_every(callout_cont[n], COMPLETION_CALLBACK_PERIOD, ET_NET); + } + + // Start cluster interconnect load monitoring + + if (!clm) { + clm = new ClusterLoadMonitor(machine); + clm->init(); + } + return EVENT_DONE; + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_ABORT_CONNECT: + //////////////////////////////////////////////////////////////////////////// + { + if (connector) { + Debug(CL_NOTE, "cluster connect retry for %u.%u.%u.%u", DOT_SEPARATED(ip)); + ClusterConfiguration *cc = this_cluster()->current_configuration(); + // check for duplicate cluster connect + if (!cc->find(ip)) + clusterProcessor.connect(ip, port, true); + } + cluster_connect_state = ClusterHandler::CLCON_DELETE_CONNECT; + break; // goto next state + } + //////////////////////////////////////////////////////////////////////////// + case ClusterHandler::CLCON_DELETE_CONNECT: + //////////////////////////////////////////////////////////////////////////// + { + // No references possible, so just delete it. + delete machine; + machine = NULL; + delete this; + Debug(CL_NOTE, "Failed cluster connect, deleting"); + return EVENT_DONE; + } + //////////////////////////////////////////////////////////////////////////// + default: + //////////////////////////////////////////////////////////////////////////// + { + Warning("startClusterEvent invalid state %d", cluster_connect_state); + ink_release_assert(!"ClusterHandler::startClusterEvent invalid state"); + return EVENT_DONE; + } + + } // End of switch + } // End of for + return EVENT_DONE; +} + +int +ClusterHandler::beginClusterEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + // Establish the main periodic Cluster event +#ifdef CLUSTER_IMMEDIATE_NETIO + build_poll(false); +#endif + SET_HANDLER((ClusterContHandler) & ClusterHandler::mainClusterEvent); + return handleEvent(EVENT_INTERVAL, e); +} + +int +ClusterHandler::zombieClusterEvent(int event, Event * e) +{ + // + // The ZOMBIE state is entered when the handler may still be referenced + // by short running tasks (one scheduling quanta). The object is delayed + // after some unreasonably long (in comparison) time. + // + (void) event; + (void) e; + delete this; // I am out of here + return EVENT_DONE; +} + +int +ClusterHandler::protoZombieEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + // + // Node associated with *this is declared down. + // After cleanup is complete, setup handler to delete *this + // after NO_RACE_DELAY + // + bool failed = false; + ink_hrtime delay = CLUSTER_RETRY; + EThread *t = e ? e->ethread : this_ethread(); + head_p item; + + ///////////////////////////////////////////////////////////////// + // Complete pending i/o operations + ///////////////////////////////////////////////////////////////// + mainClusterEvent(EVENT_INTERVAL, e); + + item.data = external_incoming_open_local.head.data; + if (TO_PTR(FREELIST_POINTER(item)) || + delayed_reads.head || pw_write_descriptors_built + || pw_freespace_descriptors_built || pw_controldata_descriptors_built) { + // Operations still pending, retry later + if (e) { + e->schedule_in(delay); + return EVENT_CONT; + } else { + eventProcessor.schedule_in(this, delay, ET_CLUSTER); + return EVENT_DONE; + } + } + /////////////////////////////////////////////////////////////// + // Deallocate current read control data + /////////////////////////////////////////////////////////////// + IncomingControl *ic; + while ((ic = incoming_control.dequeue())) { + failed = true; + ic->mutex = NULL; + ic->freeall(); + } + + ///////////////////////////////////////////////////////////////// + // Post error completion on all active read/write VC(s) and + // deallocate closed VC(s). + ///////////////////////////////////////////////////////////////// + for (int i = 0; i < n_channels; i++) { + ClusterVConnection *vc = channels[i]; + if (VALID_CHANNEL(vc)) { + if (!vc->closed && vc->read.vio.op == VIO::READ) { + MUTEX_TRY_LOCK(lock, vc->read.vio.mutex, t); + if (lock) { + cluster_signal_error_and_update(vc, &vc->read, 0); + } else { + failed = true; + } + } + vc = channels[i]; + if (VALID_CHANNEL(vc) + && !vc->closed && vc->write.vio.op == VIO::WRITE) { + MUTEX_TRY_LOCK(lock, vc->write.vio.mutex, t); + if (lock) { + cluster_signal_error_and_update(vc, &vc->write, 0); + } else { + failed = true; + } + } + vc = channels[i]; + if (VALID_CHANNEL(vc)) { + if (vc->closed) { + vc->machine = 0; + vc->write_list = 0; + vc->write_list_tail = 0; + vc->write_list_bytes = 0; + vc->write_bytes_in_transit = 0; + close_ClusterVConnection(vc); + } else { + failed = true; + } + } + } + } + + /////////////////////////////////////////////////////////////// + // Empty the external_incoming_control queue before aborting + // the completion callbacks. + /////////////////////////////////////////////////////////////// + item.data = external_incoming_control.head.data; + if (TO_PTR(FREELIST_POINTER(item)) == NULL) { + for (int n = 0; n < MAX_COMPLETION_CALLBACK_EVENTS; ++n) { + if (callout_cont[n]) { + MUTEX_TRY_LOCK(lock, callout_cont[n]->mutex, t); + if (lock) { + callout_events[n]->cancel(callout_cont[n]); + callout_events[n] = 0; + delete callout_cont[n]; + callout_cont[n] = 0; + } else { + failed = true; + } + } + } + } else { + failed = true; + } + + if (!failed) { + Debug("cluster_down", "ClusterHandler zombie [%u.%u.%u.%u]", DOT_SEPARATED(ip)); + SET_HANDLER((ClusterContHandler) & ClusterHandler::zombieClusterEvent); + delay = NO_RACE_DELAY; + } + if (e) { + e->schedule_in(delay); + return EVENT_CONT; + } else { + eventProcessor.schedule_in(this, delay, ET_CLUSTER); + return EVENT_DONE; + } +} + +int dump_verbose = 0; + +int +ClusterHandler::compute_active_channels() +{ + ClusterHandler *ch = this; + int active_chans = 0; + + for (int i = LAST_DEDICATED_CHANNEL + 1; i < ch->n_channels; i++) { + ClusterVConnection *vc = ch->channels[i]; + if (VALID_CHANNEL(vc) && (vc->iov_map != CLUSTER_IOV_NOT_OPEN)) { + ++active_chans; + if (dump_verbose) { + printf("ch[%d] vc=0x%p remote_free=%d last_local_free=%d\n", i, vc, + vc->remote_free, vc->last_local_free); + printf(" r_bytes=%d r_done=%d w_bytes=%d w_done=%d\n", + (int)vc->read.vio.nbytes, (int)vc->read.vio.ndone, + (int)vc->write.vio.nbytes, (int)vc->write.vio.ndone); + } + } + } + return active_chans; +} + +void +ClusterHandler::dump_internal_data() +{ + if (!message_blk) { + message_blk = new_IOBufferBlock(); + message_blk->alloc(MAX_IOBUFFER_SIZE); + } + int r; + int n = 0; + char *b = message_blk->data->data(); + unsigned int b_size = message_blk->data->block_size(); + + r = snprintf(&b[n], b_size - n, "Host: %hhu.%hhu.%hhu.%hhu\n", DOT_SEPARATED(ip)); + n += r; + + r = snprintf(&b[n], b_size - n, + "chans: %d vc_writes: %" PRId64 " write_bytes: %" PRId64 "(d)+%" PRId64 "(c)=%" PRId64 "\n", + compute_active_channels(), + _vc_writes, _vc_write_bytes, _control_write_bytes, _vc_write_bytes + _control_write_bytes); + + n += r; + r = snprintf(&b[n], b_size - n, + "dw: missed_lock: %d not_enabled: %d wait_remote_fill: %d no_active_vio: %d\n", + _dw_missed_lock, _dw_not_enabled, _dw_wait_remote_fill, _dw_no_active_vio); + + n += r; + r = snprintf(&b[n], b_size - n, + "dw: not_enabled_or_no_write: %d set_data_pending: %d no_free_space: %d\n", + _dw_not_enabled_or_no_write, _dw_set_data_pending, _dw_no_free_space); + + n += r; + r = snprintf(&b[n], b_size - n, + "fw: missed_lock: %d not_enabled: %d wait_remote_fill: %d no_active_vio: %d\n", + _fw_missed_lock, _fw_not_enabled, _fw_wait_remote_fill, _fw_no_active_vio); + + n += r; + r = snprintf(&b[n], b_size - n, "fw: not_enabled_or_no_read: %d\n", _fw_not_enabled_or_no_read); + + n += r; + r = snprintf(&b[n], b_size - n, + "rd(%d): st:%d rh:%d ahd:%d sd:%d rd:%d ad:%d sda:%d rda:%d awd:%d p:%d c:%d\n", + _process_read_calls, _n_read_start, _n_read_header, _n_read_await_header, + _n_read_setup_descriptor, _n_read_descriptor, _n_read_await_descriptor, + _n_read_setup_data, _n_read_data, _n_read_await_data, _n_read_post_complete, _n_read_complete); + + n += r; + r = snprintf(&b[n], b_size - n, + "wr(%d): st:%d set:%d ini:%d wait:%d post:%d comp:%d\n", + _process_write_calls, _n_write_start, _n_write_setup, _n_write_initiate, + _n_write_await_completion, _n_write_post_complete, _n_write_complete); + + n += r; + ink_release_assert((n + 1) <= BUFFER_SIZE_FOR_INDEX(MAX_IOBUFFER_SIZE)); + Note("%s", b); + clear_cluster_stats(); +} + +void +ClusterHandler::dump_write_msg(int res) +{ + // Debug support for inter cluster message trace + unsigned char x[4]; + memset(x, 0, sizeof(x)); + *(uint32_t *) & x = (uint32_t) ((struct sockaddr_in *)(net_vc->get_remote_addr()))->sin_addr.s_addr; + + fprintf(stderr, + "[W] %hhu.%hhu.%hhu.%hhu SeqNo=%u, Cnt=%d, CntlCnt=%d Todo=%d, Res=%d\n", + x[0], x[1], x[2], x[3], write.sequence_number, write.msg.count, write.msg.control_bytes, write.to_do, res); + for (int i = 0; i < write.msg.count; ++i) { + fprintf(stderr, " d[%i] Type=%d, Chan=%d, SeqNo=%d, Len=%u\n", + i, (write.msg.descriptor[i].type ? 1 : 0), + (int) write.msg.descriptor[i].channel, + (int) write.msg.descriptor[i].sequence_number, write.msg.descriptor[i].length); + } +} + +void +ClusterHandler::dump_read_msg() +{ + // Debug support for inter cluster message trace + unsigned char x[4]; + memset(x, 0, sizeof(x)); + *(uint32_t *) & x = (uint32_t) ((struct sockaddr_in *)(net_vc->get_remote_addr()))->sin_addr.s_addr; + + fprintf(stderr, "[R] %hhu.%hhu.%hhu.%hhu SeqNo=%u, Cnt=%d, CntlCnt=%d\n", + x[0], x[1], x[2], x[3], read.sequence_number, read.msg.count, read.msg.control_bytes); + for (int i = 0; i < read.msg.count; ++i) { + fprintf(stderr, " d[%i] Type=%d, Chan=%d, SeqNo=%d, Len=%u\n", + i, (read.msg.descriptor[i].type ? 1 : 0), + (int) read.msg.descriptor[i].channel, + (int) read.msg.descriptor[i].sequence_number, read.msg.descriptor[i].length); + } +} + +// End of ClusterHandlerBase.cc diff --git a/iocore/cluster/ClusterHash.cc b/iocore/cluster/ClusterHash.cc new file mode 100644 index 00000000..29ea198d --- /dev/null +++ b/iocore/cluster/ClusterHash.cc @@ -0,0 +1,177 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" +/**************************************************************************** + + ClusterHash.cc + ****************************************************************************/ + +#include "P_Cluster.h" + +// +// Configuration of the cluster hash function +// +// machineClusterHash - whether or not the random number generators +// are based on the machines or on the buckets +// boundClusterHash - whether or not we force a fixed number of buckets +// to map to each machine +// randClusterHash - whether or not to use system rand(3C) +// or a simple linear congruence random number +// generator +// +// This produces very stable results (computation time ~.6 seconds) on +// a UltraSparc at 143Mz. +// These are only global for testing purposes. +// +bool machineClusterHash = true; +bool boundClusterHash = false; +bool randClusterHash = false; + +// This produces better speed for large numbers of machines > 18 +// +// bool machineClusterHash = false; +// bool boundClusterHash = true; +// bool randClusterHash = true; + + + +// +// Cluster Hash Table +// +// see Memo.ClusterHash for details +// + + +// +// Linear Congruence Random number generator + +// Not very random, but it generates all the numbers +// within 1 period which is all we need. +// +inline unsigned short +next_rnd15(unsigned int *p) +{ + unsigned int seed = *p; + seed = 1103515145 * seed + 12345; + seed = seed & 0x7FFF; + *p = seed; + return seed; +} + +// +// Build the hash table +// This function is relatively expensive. +// It costs: (g++ at -02) +// ~.04 CPU seconds on a 143MHz Ultra 1 at 1 node +// ~.3 CPU seconds on a 143MHz Ultra 1 at 31 nodes +// Overall it is roughly linear in the number of nodes. +// +void +build_hash_table_machine(ClusterConfiguration * c) +{ + int left = CLUSTER_HASH_TABLE_SIZE; + int m = 0; + int i = 0; + unsigned int rnd[CLUSTER_MAX_MACHINES]; + unsigned int mach[CLUSTER_MAX_MACHINES]; + int total = CLUSTER_HASH_TABLE_SIZE; + + for (i = 0; i < c->n_machines; i++) { + int mine = total / (c->n_machines - i); + mach[i] = mine; + total -= mine; + } + + // seed the random number generator with the ip address + // do a little xor folding to get it into 15 bits + // + for (m = 0; m < c->n_machines; m++) + rnd[m] = (((c->machines[m]->ip >> 15) & 0x7FFF) ^ (c->machines[m]->ip & 0x7FFF)) + ^ (c->machines[m]->ip >> 30); + + // Initialize the table to "empty" + // + for (i = 0; i < CLUSTER_HASH_TABLE_SIZE; i++) + c->hash_table[i] = 255; + + // Until we have hit every element of the table, give each + // machine a chance to select it's favorites. + // + m = 0; + while (left) { + if (!mach[m] && boundClusterHash) { + m = (m + 1) % c->n_machines; + continue; + } + do { + if (randClusterHash) { + i = ink_rand_r(&rnd[m]) % CLUSTER_HASH_TABLE_SIZE; + } else + i = next_rand(&rnd[m]) % CLUSTER_HASH_TABLE_SIZE; + } while (c->hash_table[i] != 255); + mach[m]--; + c->hash_table[i] = m; + left--; + m = (m + 1) % c->n_machines; + } +} + +static void +build_hash_table_bucket(ClusterConfiguration * c) +{ + int i = 0; + unsigned int rnd[CLUSTER_HASH_TABLE_SIZE]; + unsigned int mach[CLUSTER_MAX_MACHINES]; + int total = CLUSTER_HASH_TABLE_SIZE; + + for (i = 0; i < c->n_machines; i++) { + int mine = total / (c->n_machines - i); + mach[i] = mine; + total -= mine; + } + + for (i = 0; i < CLUSTER_HASH_TABLE_SIZE; i++) + rnd[i] = i; + + for (i = 0; i < CLUSTER_HASH_TABLE_SIZE; i++) { + unsigned char x = 0; + do { + if (randClusterHash) { + x = ink_rand_r(&rnd[i]) % CLUSTER_MAX_MACHINES; + } else + x = next_rand(&rnd[i]) % CLUSTER_MAX_MACHINES; + } while (x >= c->n_machines || (!mach[x] && boundClusterHash)); + mach[x]--; + c->hash_table[i] = x; + } +} + +void +build_cluster_hash_table(ClusterConfiguration * c) +{ + if (machineClusterHash) + build_hash_table_machine(c); + else + build_hash_table_bucket(c); +} diff --git a/iocore/cluster/ClusterLib.cc b/iocore/cluster/ClusterLib.cc new file mode 100644 index 00000000..4968971c --- /dev/null +++ b/iocore/cluster/ClusterLib.cc @@ -0,0 +1,488 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ClusterLib.cc +****************************************************************************/ + +#include "P_Cluster.h" +// +// cluster_xxx() functions dealing with scheduling of Virtual Connections +// in the read and write data buckets (read_vcs, write_vcs). +// +// In contrast to the net versions, these versions simply change the priority +// scheduling only occurs after they move into the data_bucket. +// +void +cluster_set_priority(ClusterHandler * nh, ClusterVConnState * ns, int new_priority) +{ + // + // Note: Only sets priority. No scheduling action. + // + if (new_priority >= CLUSTER_BUCKETS) + ns->priority = CLUSTER_BUCKETS - 1; + else + ns->priority = new_priority; + + if (ns->priority < nh->min_priority) + ns->priority = nh->min_priority; +} + +void +cluster_lower_priority(ClusterHandler * ch, ClusterVConnState * ns) +{ + // + // Note: Only computes priority. No scheduling action. + // + int offset = ns->priority / 8; + if (!offset) + offset = 1; + cluster_set_priority(ch, ns, ns->priority + offset); +} + +void +cluster_raise_priority(ClusterHandler * ch, ClusterVConnState * ns) +{ + // + // Note: Only computes priority. No scheduling action. + // + int offset = ns->priority / 2; + if (!offset) + offset = 1; + cluster_set_priority(ch, ns, ns->priority - offset); +} + +void +cluster_schedule(ClusterHandler * ch, ClusterVConnection * vc, ClusterVConnState * ns) +{ + // + // actually schedule into new bucket + // + int new_bucket = ch->cur_vcs + ns->priority; + new_bucket %= CLUSTER_BUCKETS; + if (ns == &vc->read) { + ClusterVC_enqueue_read(ch->read_vcs[new_bucket], vc); + } else { + ClusterVC_enqueue_write(ch->write_vcs[new_bucket], vc); + } +} + +void +cluster_reschedule(ClusterHandler * ch, ClusterVConnection * vc, ClusterVConnState * ns) +{ + // + // Remove from bucket, computer priority and schedule into target bucket + // + if (ns == &vc->read) + ClusterVC_remove_read(vc); + else + ClusterVC_remove_write(vc); + cluster_set_priority(ch, ns, ns->priority); + cluster_schedule(ch, vc, ns); +} + +void +cluster_disable(ClusterHandler * ch, ClusterVConnection * vc, ClusterVConnState * ns) +{ + // + // disable inactivity timeout, recompute priority, remove from current + // bucket and reschedule into new bucket based on new priority. + // + ns->enabled = 0; + if (vc->inactivity_timeout) { + bool disable_timeout = false; + if (ns == &vc->read) { + disable_timeout = !vc->write.enabled; + } else { + disable_timeout = !vc->read.enabled; + } + if (disable_timeout) { + vc->inactivity_timeout->cancel(); + vc->inactivity_timeout = NULL; + } + } + cluster_lower_priority(ch, ns); + if (ns == &vc->read) + ClusterVC_remove_read(vc); + else + ClusterVC_remove_write(vc); + cluster_schedule(ch, vc, ns); +} + +void +cluster_update_priority(ClusterHandler * ch, ClusterVConnection * vc, ClusterVConnState * ns, int64_t ndone, int64_t ntodo) +{ + // + // Enable inactivity timeout, recompute priority based on latest transfer. + // + if (!ns->enabled) { + cluster_lower_priority(ch, ns); + return; + } + if (vc->inactivity_timeout) { + vc->inactivity_timeout->schedule_every(vc->inactivity_timeout->period); + } else { + if (vc->inactivity_timeout_in) + vc->inactivity_timeout = vc->thread->schedule_in(vc, vc->inactivity_timeout_in); + } + + int64_t tsize = ns->vio.buffer.total_size(); + + if (tsize > ntodo) { + tsize = ntodo; + } + if (ndone > tsize / 2) { + cluster_raise_priority(ch, ns); + } else { + if (ndone < tsize / 4) + cluster_lower_priority(ch, ns); + } + // + // Otherwise, do not change priority + // +} + +void +cluster_bump(ClusterHandler * ch, ClusterVConnectionBase * vc, ClusterVConnState * ns, int this_bucket) +{ + // + // Remove from current bucket and place in + // current bucket + CLUSTER_BUMP_LENGTH + // + int new_bucket = (ch->cur_vcs + CLUSTER_BUMP_LENGTH) % CLUSTER_BUCKETS; + + if (ns == &vc->read) { + if (this_bucket != CLUSTER_BUMP_NO_REMOVE) { + ClusterVC_remove_read(vc); + } + ClusterVC_enqueue_read(ch->read_vcs[new_bucket], vc); + } else { + if (this_bucket != CLUSTER_BUMP_NO_REMOVE) { + ClusterVC_remove_write(vc); + } + ClusterVC_enqueue_write(ch->write_vcs[new_bucket], vc); + } +} + +// +// iov_memcpy() -- struct iov based memcpy() +// +int +iov_memcpy(IOVec * iov, int n_iov, int did, char *bb_arg) +{ + char *bb = bb_arg; + for (int i = 0; i < n_iov; i++) { + int len = iov[i].iov_len; + did -= len; + if (did < 0) { + // fprintf(stderr,"iov_memcpy %X %d\n",iov[i].iov_base+(len+did),-did); + memcpy(bb, (char *) iov[i].iov_base + (len + did), -did); + bb += -did; + did = 0; + } + } + return bb - bb_arg; +} + +/*************************************************************************/ +// ClusterVCToken member functions (Public Class) +/*************************************************************************/ + +// global sequence number for building tokens +unsigned int cluster_sequence_number = 0; + +void +ClusterVCToken::alloc() +{ +#ifdef LOCAL_CLUSTER_TEST_MODE + ip_created = this_cluster_machine()->cluster_port; +#else + ip_created = this_cluster_machine()->ip; +#endif + sequence_number = ink_atomic_increment((int *) &cluster_sequence_number, 1); +} + +/////////////////////////////////////////// +// IOBufferBlock manipulation routines +/////////////////////////////////////////// + +IOBufferBlock * +clone_IOBufferBlockList(IOBufferBlock * b, int start_off, int n, IOBufferBlock ** b_tail) +{ + //////////////////////////////////////////////////////////////// + // Create a clone list of IOBufferBlock(s) where the sum + // of all block read_avail is 'n'. The given source list + // must contain at least 'n' read avail bytes. + //////////////////////////////////////////////////////////////// + int64_t nbytes = n; + int64_t block_read_avail; + int64_t bytes_to_skip = start_off; + IOBufferBlock *bsrc = b; + IOBufferBlock *bclone = 0; + IOBufferBlock *bclone_head = 0; + + while (bsrc && nbytes) { + // Skip zero length blocks + if (!bsrc->read_avail()) { + bsrc = bsrc->next; + continue; + } + + if (bclone_head) { + bclone->next = bsrc->clone(); + bclone = bclone->next; + } else { + + // Skip bytes already processed + if (bytes_to_skip) { + bytes_to_skip -= bsrc->read_avail(); + + if (bytes_to_skip < 0) { + // Skip bytes in current block + bclone_head = bsrc->clone(); + bclone_head->consume(bsrc->read_avail() + bytes_to_skip); + bclone = bclone_head; + bytes_to_skip = 0; + + } else { + // Skip entire block + bsrc = bsrc->next; + continue; + } + } else { + bclone_head = bsrc->clone(); + bclone = bclone_head; + } + } + block_read_avail = bclone->read_avail(); + nbytes -= block_read_avail; + if (nbytes < 0) { + // Adjust read_avail in clone to match nbytes + bclone->fill(nbytes); + nbytes = 0; + } + bsrc = bsrc->next; + } + ink_release_assert(!nbytes); + *b_tail = bclone; + return bclone_head; +} + +IOBufferBlock * +consume_IOBufferBlockList(IOBufferBlock * b, int64_t n) +{ + IOBufferBlock *b_remainder = 0; + int64_t nbytes = n; + + while (b) { + nbytes -= b->read_avail(); + if (nbytes <= 0) { + if (nbytes < 0) { + // Consumed a partial block, clone remainder + b_remainder = b->clone(); + b->fill(nbytes); // make read_avail match nbytes + b_remainder->consume(b->read_avail()); // clone for remaining bytes + b_remainder->next = b->next; + b->next = 0; + nbytes = 0; + + } else { + // Consumed entire block + b_remainder = b->next; + } + break; + + } else { + b = b->next; + } + } + ink_release_assert(nbytes == 0); + return b_remainder; // return remaining blocks +} + +int64_t +bytes_IOBufferBlockList(IOBufferBlock * b, int64_t read_avail_bytes) +{ + int64_t n = 0;; + + while (b) { + if (read_avail_bytes) { + n += b->read_avail(); + } else { + n += b->write_avail(); + } + b = b->next; + } + return n; +} + + +////////////////////////////////////////////////////// +// Miscellaneous test code +////////////////////////////////////////////////////// +#if TEST_PARTIAL_READS +// +// Test code which mimic the network slowdown +// +int +partial_readv(int fd, IOVec * iov, int n_iov, int seq) +{ + IOVec tiov[16]; + for (int i = 0; i < n_iov; i++) + tiov[i] = iov[i]; + int tn_iov = n_iov; + int rnd = seq; + int element = rand_r((unsigned int *) &rnd); + element = element % n_iov; + int byte = rand_r((unsigned int *) &rnd); + byte = byte % iov[element].iov_len; + int stop = rand_r((unsigned int *) &rnd); + if (!(stop % 3)) { // 33% chance + tn_iov = element + 1; + tiov[element].iov_len = byte; + if (!byte) + tn_iov--; + if (!tn_iov) { + tiov[element].iov_len = 1; + tn_iov++; + } + // printf("partitial read %d [%d]\n",tn_iov,tiov[element].iov_len); + } + return socketManager.read_vector(fd, &tiov[0], tn_iov); +} +#endif // TEST_PARTIAL_READS + +#if TEST_PARTIAL_WRITES +// +// Test code which mimic the network backing up (too little buffering) +// +int +partial_writev(int fd, IOVec * iov, int n_iov, int seq) +{ + int rnd = seq; + int sum = 0; + int i = 0; + for (i = 0; i < n_iov; i++) { + int l = iov[i].iov_len; + int r = rand_r((unsigned int *) &rnd); + if ((r >> 4) & 1) { + l = ((unsigned int) rand_r((unsigned int *) &rnd)) % iov[i].iov_len; + if (!l) { + l = iov[i].iov_len; + } + } + ink_assert(l <= iov[i].iov_len); + fprintf(stderr, "writing %d: [%d] &%X %d of %d\n", seq, i, iov[i].iov_base, l, iov[i].iov_len); + int res = socketManager.write(fd, iov[i].iov_base, l); + if (res < 0) { + return res; + } + sum += res; + if (res != iov[i].iov_len) { + return sum; + } + } + return sum; +} +#endif // TEST_PARTIAL_WRITES + +//////////////////////////////////////////////////////////////////////// +// Global periodic system dump functions +//////////////////////////////////////////////////////////////////////// +#ifdef ENABLE_TIME_TRACE +int inmsg_time_dist[TIME_DIST_BUCKETS_SIZE]; +int inmsg_events = 0; + +int cluster_send_time_dist[TIME_DIST_BUCKETS_SIZE]; +int cluster_send_events = 0; +#endif // ENABLE_TIME_TRACE + +int time_trace = 0; + +void +dump_time_buckets() +{ +#ifdef ENABLE_TIME_TRACE + printf("\nremote ops:\n"); + for (int i = 0; i < TIME_DIST_BUCKETS_SIZE; ++i) { + printf("%d ", rmt_callback_time_dist[i]); + rmt_callback_time_dist[i] = 0; + } + printf("\nremote lookup ops:\n"); + for (int j = 0; j < TIME_DIST_BUCKETS_SIZE; ++j) { + printf("%d ", lkrmt_callback_time_dist[j]); + lkrmt_callback_time_dist[j] = 0; + } + printf("\nlocal cache ops:\n"); + for (int k = 0; k < TIME_DIST_BUCKETS_SIZE; ++k) { + printf("%d ", callback_time_dist[k]); + callback_time_dist[k] = 0; + } + printf("\nphysical cache ops:\n"); + for (int l = 0; l < TIME_DIST_BUCKETS_SIZE; ++l) { + printf("%d ", cdb_callback_time_dist[l]); + cdb_callback_time_dist[l] = 0; + } + printf("\nin message ops:\n"); + for (int m = 0; m < TIME_DIST_BUCKETS_SIZE; ++m) { + printf("%d ", inmsg_time_dist[m]); + inmsg_time_dist[m] = 0; + } + printf("\ncluster send time:\n"); + for (int n = 0; n < TIME_DIST_BUCKETS_SIZE; ++n) { + printf("%d ", cluster_send_time_dist[n]); + cluster_send_time_dist[n] = 0; + } +#endif // ENABLE_TIME_TRACE +} + +GlobalClusterPeriodicEvent::GlobalClusterPeriodicEvent():Continuation(new_ProxyMutex()) +{ + SET_HANDLER((GClusterPEHandler) & GlobalClusterPeriodicEvent::calloutEvent); +} + +GlobalClusterPeriodicEvent::~GlobalClusterPeriodicEvent() +{ + _thisCallout->cancel(this); +} + +void +GlobalClusterPeriodicEvent::init() +{ + _thisCallout = eventProcessor.schedule_every(this, HRTIME_SECONDS(10), ET_CALL); +} + +int +GlobalClusterPeriodicEvent::calloutEvent(Event * e, void *data) +{ + NOWARN_UNUSED(e); + NOWARN_UNUSED(data); + if (time_trace) { + dump_time_buckets(); + } + clusterProcessor.compute_cluster_mode(); + return EVENT_CONT; +} + +// End of ClusterLib.cc diff --git a/iocore/cluster/ClusterLoadMonitor.cc b/iocore/cluster/ClusterLoadMonitor.cc new file mode 100644 index 00000000..84793392 --- /dev/null +++ b/iocore/cluster/ClusterLoadMonitor.cc @@ -0,0 +1,322 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterLoadMonitor.cc +****************************************************************************/ + +#include "P_Cluster.h" +int + ClusterLoadMonitor::cf_monitor_enabled; +int + ClusterLoadMonitor::cf_ping_message_send_msec_interval; +int + ClusterLoadMonitor::cf_num_ping_response_buckets; +int + ClusterLoadMonitor::cf_msecs_per_ping_response_bucket; +int + ClusterLoadMonitor::cf_ping_latency_threshold_msecs; +int + ClusterLoadMonitor::cf_cluster_load_compute_msec_interval; +int + ClusterLoadMonitor::cf_cluster_periodic_msec_interval; +int + ClusterLoadMonitor::cf_ping_history_buf_length; +int + ClusterLoadMonitor::cf_cluster_load_clear_duration; +int + ClusterLoadMonitor::cf_cluster_load_exceed_duration; + +ClusterLoadMonitor::ClusterLoadMonitor(ClusterMachine * m) +:Continuation(0), machine(m), ping_history_buf_head(0), +periodic_action(0), cluster_overloaded(0), cancel_periodic(0), +cluster_load_msg_sequence_number(0), cluster_load_msg_start_sequence_number(0) +{ + mutex = this->machine->clusterHandler->mutex; + SET_HANDLER(&ClusterLoadMonitor::cluster_load_periodic); + + ping_message_send_msec_interval = cf_ping_message_send_msec_interval ? cf_ping_message_send_msec_interval : 100; + Debug("cluster_monitor", "ping_message_send_msec_interval=%d", ping_message_send_msec_interval); + + num_ping_response_buckets = cf_num_ping_response_buckets ? cf_num_ping_response_buckets : 100; + Debug("cluster_monitor", "num_ping_response_buckets=%d", num_ping_response_buckets); + + msecs_per_ping_response_bucket = cf_msecs_per_ping_response_bucket ? cf_msecs_per_ping_response_bucket : 50; + Debug("cluster_monitor", "msecs_per_ping_response_bucket=%d", msecs_per_ping_response_bucket); + + ping_latency_threshold_msecs = cf_ping_latency_threshold_msecs ? cf_ping_latency_threshold_msecs : 500; + Debug("cluster_monitor", "ping_latency_threshold_msecs=%d", ping_latency_threshold_msecs); + + cluster_load_compute_msec_interval = + cf_cluster_load_compute_msec_interval ? cf_cluster_load_compute_msec_interval : 5000; + Debug("cluster_monitor", "cluster_load_compute_msec_interval=%d", cluster_load_compute_msec_interval); + + cluster_periodic_msec_interval = cf_cluster_periodic_msec_interval ? cf_cluster_periodic_msec_interval : 100; + Debug("cluster_monitor", "cluster_periodic_msec_interval=%d", cluster_periodic_msec_interval); + + ping_history_buf_length = cf_ping_history_buf_length ? cf_ping_history_buf_length : 120; + Debug("cluster_monitor", "ping_history_buf_length=%d", ping_history_buf_length); + + cluster_load_clear_duration = cf_cluster_load_clear_duration ? cf_cluster_load_clear_duration : 24; + Debug("cluster_monitor", "cluster_load_clear_duration=%d", cluster_load_clear_duration); + + cluster_load_exceed_duration = cf_cluster_load_exceed_duration ? cf_cluster_load_exceed_duration : 4; + Debug("cluster_monitor", "cluster_load_exceed_duration=%d", cluster_load_exceed_duration); + + int nbytes = sizeof(int) * num_ping_response_buckets; + ping_response_buckets = (int *) xmalloc(nbytes); + memset((char *) ping_response_buckets, 0, nbytes); + + nbytes = sizeof(ink_hrtime) * ping_history_buf_length; + ping_response_history_buf = (ink_hrtime *) xmalloc(nbytes); + memset((char *) ping_response_history_buf, 0, nbytes); + + last_ping_message_sent = HRTIME_SECONDS(0); + last_cluster_load_compute = HRTIME_SECONDS(0); +} + +void +ClusterLoadMonitor::init() +{ + periodic_action = eventProcessor.schedule_every(this, HRTIME_MSECONDS(cluster_periodic_msec_interval), ET_CALL); +} + +ClusterLoadMonitor::~ClusterLoadMonitor() +{ + // + // Note: Since the ClusterLoadMonitor is only associated + // with the ClusterHandler, a periodic callback operating + // on a freed ClusterLoadMonitor is not possible, since the + // ClusterHandler is only deleted after several minutes. Allowing + // plenty of time for the periodic to cancel itself via the + // "cancel_periodic" flag. + // + ink_release_assert(!periodic_action); + if (ping_response_buckets) { + xfree(ping_response_buckets); + ping_response_buckets = 0; + } + if (ping_response_history_buf) { + xfree(ping_response_history_buf); + ping_response_history_buf = 0; + } +} + +void +ClusterLoadMonitor::cancel_monitor() +{ + if (!cancel_periodic) + cancel_periodic = 1; +} + +bool ClusterLoadMonitor::is_cluster_overloaded() +{ + return (cluster_overloaded ? true : false); +} + +void +ClusterLoadMonitor::compute_cluster_load() +{ + // Compute ping message latency by scanning the response time + // buckets and averaging the results. + + int n; + int sum = 0; + int entries = 0; + int n_bucket = 0; + + for (n = 0; n < num_ping_response_buckets; ++n) { + if (ping_response_buckets[n]) { + entries += ping_response_buckets[n]; + sum += (ping_response_buckets[n] * (n + 1)); + } + ping_response_buckets[n] = 0; + } + if (entries) { + n_bucket = sum / entries; + } else { + n_bucket = 1; + } + ink_hrtime current_ping_latency = HRTIME_MSECONDS(n_bucket * msecs_per_ping_response_bucket); + + // Invalidate messages associated with this sample interval + cluster_load_msg_start_sequence_number = cluster_load_msg_sequence_number; + + // Log ping latency in history buffer. + + ping_response_history_buf[ping_history_buf_head++] = current_ping_latency; + ping_history_buf_head = ping_history_buf_head % ping_history_buf_length; + + // Determine the current state of the cluster interconnect using + // the configured limits. We determine the state as follows. + // if (cluster overloaded) + // Determine if it is still in the overload state by examining + // the last 'cluster_load_clear_duration' entries in the history + // buffer and declaring it not overloaded if none of the entries + // exceed the threshold. + // else + // Determine if it is now in the overload state by examining + // the last 'cluster_load_exceed_duration' entries in the history + // buffer and declaring it overloaded if all of the entries + // exceed the threshold. + + int start, end; + ink_hrtime ping_latency_threshold = HRTIME_MSECONDS(ping_latency_threshold_msecs); + + start = ping_history_buf_head - 1; + if (start < 0) + start += ping_history_buf_length; + end = start; + + if (cluster_overloaded) { + end -= (cluster_load_clear_duration <= ping_history_buf_length ? + cluster_load_clear_duration : ping_history_buf_length); + } else { + end -= (cluster_load_exceed_duration <= ping_history_buf_length ? + cluster_load_exceed_duration : ping_history_buf_length); + } + if (end < 0) + end += ping_history_buf_length; + + int threshold_clear = 0; + int threshold_exceeded = 0; + do { + if (ping_response_history_buf[start] >= ping_latency_threshold) + ++threshold_exceeded; + else + ++threshold_clear; + if (--start < 0) + start = start + ping_history_buf_length; + } while (start != end); + + if (cluster_overloaded) { + if (threshold_exceeded == 0) + cluster_overloaded = 0; + } else { + if (threshold_exceeded && (threshold_clear == 0)) + cluster_overloaded = 1; + } + Debug("cluster_monitor", + "[%u.%u.%u.%u] overload=%d, clear=%d, exceed=%d, latency=%d", + DOT_SEPARATED(this->machine->ip), cluster_overloaded, threshold_clear, threshold_exceeded, n_bucket); +} + +void +ClusterLoadMonitor::note_ping_response_time(ink_hrtime response_time, int sequence_number) +{ +#ifdef CLUSTER_TOMCAT + ProxyMutex *mutex = this->machine->clusterHandler->mutex; // hack for stats +#endif + + CLUSTER_SUM_DYN_STAT(CLUSTER_PING_TIME_STAT, response_time); + int bucket = (int) + (response_time / HRTIME_MSECONDS(msecs_per_ping_response_bucket)); + Debug("cluster_monitor_ping", "[%u.%u.%u.%u] ping: %d %d", DOT_SEPARATED(this->machine->ip), bucket, sequence_number); + + if (bucket >= num_ping_response_buckets) + bucket = num_ping_response_buckets - 1; + ink_atomic_increment(&ping_response_buckets[bucket], 1); +} + +void +ClusterLoadMonitor::recv_cluster_load_msg(cluster_load_ping_msg * m) +{ + // We have received back our ping message. + ink_hrtime now = ink_get_hrtime(); + + if ((now >= m->send_time) + && ((m->sequence_number >= cluster_load_msg_start_sequence_number) + && (m->sequence_number < cluster_load_msg_sequence_number))) { + // Valid message, note response time. + note_ping_response_time(now - m->send_time, m->sequence_number); + } +} + +void +ClusterLoadMonitor::cluster_load_ping_rethandler(ClusterMachine * from, void *data, int len) +{ + // Global cluster load ping message return handler which + // dispatches the result to the class specific handler. + + ClusterHandler *ch = from->clusterHandler; + if (ch) { + if (len == sizeof(struct cluster_load_ping_msg)) { + struct cluster_load_ping_msg m; + memcpy((void *) &m, data, len); // unmarshal + + if (m.monitor && (m.magicno == cluster_load_ping_msg::CL_MSG_MAGICNO) + && (m.version == cluster_load_ping_msg::CL_MSG_VERSION)) { + m.monitor->recv_cluster_load_msg(&m); + } + } + } +} + +void +ClusterLoadMonitor::send_cluster_load_msg(ink_hrtime current_time) +{ + // Build and send cluster load ping message. + + struct cluster_load_ping_msg m(this); + + m.sequence_number = cluster_load_msg_sequence_number++; + m.send_time = current_time; + cluster_ping(machine, cluster_load_ping_rethandler, (void *) &m, sizeof(m)); +} + +int +ClusterLoadMonitor::cluster_load_periodic(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + + // Perform periodic cluster load computation actions. + + if (cancel_periodic) { + periodic_action->cancel(); + periodic_action = 0; + return EVENT_DONE; + } + + if (!cf_monitor_enabled) { + return EVENT_CONT; + } + // Generate periodic ping messages. + + ink_hrtime current_time = ink_get_hrtime(); + if ((current_time - last_ping_message_sent) > HRTIME_MSECONDS(ping_message_send_msec_interval)) { + send_cluster_load_msg(current_time); + last_ping_message_sent = current_time; + } + // Compute cluster load. + + if ((current_time - last_cluster_load_compute) > HRTIME_MSECONDS(cluster_load_compute_msec_interval)) { + compute_cluster_load(); + last_cluster_load_compute = current_time; + } + return EVENT_CONT; +} + +// End of ClusterLoadMonitor.cc diff --git a/iocore/cluster/ClusterMachine.cc b/iocore/cluster/ClusterMachine.cc new file mode 100644 index 00000000..262445da --- /dev/null +++ b/iocore/cluster/ClusterMachine.cc @@ -0,0 +1,271 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Machine.cc + ****************************************************************************/ + +#include "ink_config.h" +#include +#include "P_Cluster.h" +extern char cache_system_config_directory[PATH_NAME_MAX + 1]; + +MachineList *machines_config = NULL; +MachineList *cluster_config = NULL; + +ProxyMutex *the_cluster_config_mutex; + +static ClusterMachine *cluster_machine; + +MachineList * +the_cluster_machines_config() +{ + return machines_config; +} + +MachineList * +the_cluster_config() +{ + return cluster_config; +} + +ClusterMachine * +this_cluster_machine() +{ + return cluster_machine; +} + +void +create_this_cluster_machine() +{ + the_cluster_config_mutex = new_ProxyMutex(); + cluster_machine = NEW(new ClusterMachine); +} + +ClusterMachine::ClusterMachine(char *ahostname, unsigned int aip, int aport): +dead(false), +hostname(ahostname), +ip(aip), +cluster_port(aport), +msg_proto_major(0), +msg_proto_minor(0), +clusterHandler(0) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; +#ifndef INK_NO_CLUSTER + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_MACHINES_ALLOCATED_STAT); +#endif + if (!aip) { + char localhost[1024]; + if (!ahostname) { + ink_release_assert(!gethostname(localhost, 1023)); + ahostname = localhost; + } + hostname = xstrdup(ahostname); + + // If we are running if the manager, it the our ip address for + // clustering from the manager, so the manager can control what + // interface we cluster over. Otherwise figure it out ourselves +#ifdef LOCAL_CLUSTER_TEST_MODE + ip = inet_addr("127.0.0.1"); +#else +#ifdef CLUSTER_TEST + int clustering_enabled = true; +#else + int clustering_enabled = !!getenv("PROXY_CLUSTER_ADDR"); +#endif + if (clustering_enabled) { + char *clusterIP = getenv("PROXY_CLUSTER_ADDR"); + Debug("cluster_note", "[Machine::Machine] Cluster IP addr: %s\n", clusterIP); + ip = inet_addr(clusterIP); + } else { + + ink_gethostbyname_r_data data; + struct hostent *r = ink_gethostbyname_r(ahostname, &data); + if (!r) { + Warning("unable to DNS %s: %d", ahostname, data.herrno); + ip = 0; + } else { + + // lowest IP address + + ip = (unsigned int) -1; // 0xFFFFFFFF + for (int i = 0; r->h_addr_list[i]; i++) + if (ip > *(unsigned int *) r->h_addr_list[i]) + ip = *(unsigned int *) r->h_addr_list[i]; + if (ip == (unsigned int) -1) + ip = 0; + } + //ip = htonl(ip); for the alpha! + } +#endif // LOCAL_CLUSTER_TEST_MODE + } else { + + ip = aip; + + ink_gethostbyaddr_r_data data; + struct hostent *r = ink_gethostbyaddr_r((char *) &ip, sizeof(int), + AF_INET, &data); + + if (r == NULL) { + unsigned char x[4]; + memset(x, 0, sizeof(x)); + *(uint32_t *) & x = (uint32_t) ip; + Debug("machine_debug", "unable to reverse DNS %u.%u.%u.%u: %d", x[0], x[1], x[2], x[3], data.herrno); + } else + hostname = xstrdup(r->h_name); + } + if (hostname) + hostname_len = strlen(hostname); + else + hostname_len = 0; +} + +ClusterMachine::~ClusterMachine() +{ + if (hostname) + xfree(hostname); +} + +#ifndef INK_NO_CLUSTER +struct MachineTimeoutContinuation; +typedef int (MachineTimeoutContinuation::*McTimeoutContHandler) (int, void *); +struct MachineTimeoutContinuation: public Continuation +{ + ClusterMachine *m; + int dieEvent(int event, Event * e) + { + (void) event; + (void) e; + delete m; + delete this; + return EVENT_DONE; + } + MachineTimeoutContinuation(ClusterMachine * am):Continuation(NULL), m(am) + { + SET_HANDLER((McTimeoutContHandler) & MachineTimeoutContinuation::dieEvent); + } +}; + +void +free_ClusterMachine(ClusterMachine * m) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + // delay before the final free + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_MACHINES_FREED_STAT); + m->dead = true; + eventProcessor.schedule_in(NEW(new MachineTimeoutContinuation(m)), MACHINE_TIMEOUT, ET_CALL); +} + +void +free_MachineList(MachineList * l) +{ + new_Freer(l, MACHINE_TIMEOUT); +} + +MachineList * +read_MachineList(char *filename, int afd) +{ + char line[256]; + int n = -1, i = 0, ln = 0; + MachineList *l = NULL; + ink_assert(filename || (afd != -1)); + char p[PATH_NAME_MAX]; + size_t remaining_str_size = sizeof p; + if (filename) { + ink_strncpy(p, cache_system_config_directory, remaining_str_size); + remaining_str_size -= strlen(cache_system_config_directory); + strncat(p, "/", remaining_str_size); + remaining_str_size--; + strncat(p, filename, remaining_str_size); + } + int fd = ((afd != -1) ? afd : open(p, O_RDONLY)); + if (fd >= 0) { + while (ink_file_fd_readline(fd, sizeof(line) - 1, line) > 0) { + ln++; + if (*line == '#') + continue; + if (n == -1 && ParseRules::is_digit(*line)) { + n = atoi(line); + if (n > 0) { + l = (MachineList *) xmalloc(sizeof(MachineList) + (n - 1) * sizeof(MachineListElement)); + l->n = 0; + } else { + l = NULL; + } + continue; + } + if (l && ParseRules::is_digit(*line) && i < n) { + char *port = strchr(line, ':'); + if (!port) + goto Lfail; + *port++ = 0; + l->machine[i].ip = inet_addr(line); + if (-1 == (int) l->machine[i].ip) { + if (afd == -1) { + Warning("read machine list failure, bad ip, line %d", ln); + return NULL; + } else { + char s[256]; + snprintf(s, sizeof s, "bad ip, line %d", ln); + return (MachineList *) xstrdup(s); + } + } + l->machine[i].port = atoi(port); + if (!l->machine[i].port) + goto Lfail; + i++; + l->n++; + continue; + Lfail: + if (afd == -1) { + Warning("read machine list failure, bad port, line %d", ln); + return NULL; + } else { + char s[256]; + snprintf(s, sizeof s, "bad port, line %d", ln); + return (MachineList *) xstrdup(s); + } + } + } + close(fd); + } else { + Warning("read machine list failure, open failed"); + return NULL; + } + if (n >= 0) { + if (i != n) { + if (afd == -1) { + Warning("read machine list failure, length mismatch"); + return NULL; + } else + xfree(l); + return (MachineList *) xstrdup("number of machines does not match length of list\n"); + } + } + return (afd != -1) ? (MachineList *) NULL : l; +} +#endif // INK_NO_CLUSTER diff --git a/iocore/cluster/ClusterProcessor.cc b/iocore/cluster/ClusterProcessor.cc new file mode 100644 index 00000000..e7316d5f --- /dev/null +++ b/iocore/cluster/ClusterProcessor.cc @@ -0,0 +1,825 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterProcessor.cc +****************************************************************************/ + +#include "P_Cluster.h" +/*************************************************************************/ +// ClusterProcessor member functions (Public class) +/*************************************************************************/ +int cluster_port_number = DEFAULT_CLUSTER_PORT_NUMBER; +int cache_clustering_enabled = 0; + +ClusterProcessor clusterProcessor; +RecRawStatBlock *cluster_rsb = NULL; +int ET_CLUSTER; + +ClusterProcessor::ClusterProcessor():accept_handler(NULL), this_cluster(NULL) +{ +} + +ClusterProcessor::~ClusterProcessor() +{ + if (accept_handler) { + accept_handler->ShutdownDelete(); + accept_handler = 0; + } +} + +int +ClusterProcessor::internal_invoke_remote(ClusterMachine * m, int cluster_fn, + void *data, int len, int options, void *cmsg) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + // + // RPC facility for intercluster communication available to other + // subsystems. + // + bool steal = (options & CLUSTER_OPT_STEAL ? true : false); + bool delay = (options & CLUSTER_OPT_DELAY ? true : false); + bool data_in_ocntl = (options & CLUSTER_OPT_DATA_IS_OCONTROL ? true : false); + bool malloced = (cluster_fn == CLUSTER_FUNCTION_MALLOCED); + OutgoingControl *c; + + ClusterHandler *ch = m->clusterHandler; + if (!ch || (!malloced && !((unsigned int) cluster_fn < (uint32_t) SIZE_clusterFunction))) { + // Invalid message or node is down, free message data + if (malloced) { + xfree(data); + } + if (cmsg) { + invoke_remote_data_args *args = (invoke_remote_data_args *) + (((OutgoingControl *) cmsg)->data + sizeof(int32_t)); + ink_assert(args->magicno == invoke_remote_data_args::MagicNo); + + args->data_oc->freeall(); + ((OutgoingControl *) cmsg)->freeall(); + } + if (data_in_ocntl) { + c = *((OutgoingControl **) ((char *) data - sizeof(OutgoingControl *))); + c->freeall(); + } + return -1; + } + + if (data_in_ocntl) { + c = *((OutgoingControl **) ((char *) data - sizeof(OutgoingControl *))); + } else { + c = OutgoingControl::alloc(); + } + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CTRL_MSGS_SENT_STAT); + c->m = m; + c->submit_time = ink_get_hrtime(); + + if (malloced) { + c->set_data((char *) data, len); + } else { + if (!data_in_ocntl) { + c->len = len + sizeof(int32_t); + c->alloc_data(); + } + if (!c->fast_data()) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_SLOW_CTRL_MSGS_SENT_STAT); + } + *(int32_t *) c->data = cluster_fn; + if (!data_in_ocntl) { + memcpy(c->data + sizeof(int32_t), data, len); + } + } + + SET_CONTINUATION_HANDLER(c, (OutgoingCtrlHandler) & OutgoingControl::startEvent); + + ///////////////////////////////////// + // Compound message adjustments + ///////////////////////////////////// + if (cmsg) { + invoke_remote_data_args *args = (invoke_remote_data_args *) + (((OutgoingControl *) cmsg)->data + sizeof(int32_t)); + ink_assert(args->magicno == invoke_remote_data_args::MagicNo); + args->msg_oc = c; + c = (OutgoingControl *) cmsg; + } +#ifndef CLUSTER_THREAD_STEALING + delay = true; +#endif + if (!delay) { + EThread *tt = this_ethread(); + { + int q = ClusterFuncToQpri(cluster_fn); + ink_atomiclist_push(&ch->outgoing_control_al[q], (void *) c); + + MUTEX_TRY_LOCK(lock, ch->mutex, tt); + if (!lock) { + return 1; + } + if (steal) + ch->steal_thread(tt); + return 1; + } + } else { + c->mutex = ch->mutex; + eventProcessor.schedule_imm(c); + return 0; + } +} + +int +ClusterProcessor::invoke_remote(ClusterMachine * m, int cluster_fn, void *data, int len, int options) +{ + return internal_invoke_remote(m, cluster_fn, data, len, options, (void *) NULL); +} + +int +ClusterProcessor::invoke_remote_data(ClusterMachine * m, int cluster_fn, + void *data, int data_len, + IOBufferBlock * buf, + int dest_channel, ClusterVCToken * token, + void (*bufdata_free_proc) (void *), void *bufdata_free_proc_arg, int options) +{ + if (!buf) { + // No buffer data, translate this into a invoke_remote() request + return internal_invoke_remote(m, cluster_fn, data, data_len, options, (void *) NULL); + } + ink_assert(data); + ink_assert(data_len); + ink_assert(dest_channel); + ink_assert(token); + ink_assert(bufdata_free_proc); + ink_assert(bufdata_free_proc_arg); + + ///////////////////////////////////////////////////////////////////////// + // Build the compound message as described by invoke_remote_data_args. + ///////////////////////////////////////////////////////////////////////// + + // Build OutgoingControl for buffer data + OutgoingControl *bufdata_oc = OutgoingControl::alloc(); + bufdata_oc->set_data(buf, bufdata_free_proc, bufdata_free_proc_arg); + + // Build OutgoingControl for compound message header + invoke_remote_data_args mh; + mh.msg_oc = 0; + mh.data_oc = bufdata_oc; + mh.dest_channel = dest_channel; + mh.token = *token; + + OutgoingControl *chdr = OutgoingControl::alloc(); + chdr->submit_time = ink_get_hrtime(); + chdr->len = sizeof(int32_t) + sizeof(mh); + chdr->alloc_data(); + *(int32_t *) chdr->data = -1; // always -1 for compound message + memcpy(chdr->data + sizeof(int32_t), (char *) &mh, sizeof(mh)); + + return internal_invoke_remote(m, cluster_fn, data, data_len, options, (void *) chdr); +} + +void +ClusterProcessor::free_remote_data(char *p, int l) +{ + NOWARN_UNUSED(l); + char *d = p - sizeof(int32_t); // reset to ptr to function code + int data_hdr = ClusterControl::DATA_HDR; + + ink_release_assert(*((uint8_t *) (d - data_hdr + 1)) == (uint8_t) ALLOC_DATA_MAGIC); + unsigned char size_index = *(d - data_hdr); + if (!(size_index & 0x80)) { + ink_release_assert(size_index <= (DEFAULT_BUFFER_SIZES - 1)); + } else { + ink_release_assert(size_index == 0xff); + } + + // Extract 'this' pointer + + ClusterControl *ccl; + memcpy((char *) &ccl, (d - data_hdr + 2), sizeof(void *)); + ink_assert(ccl->valid_alloc_data()); + + // Deallocate control structure and data + + ccl->freeall(); +} + +ClusterVConnection * +ClusterProcessor::open_local(Continuation * cont, ClusterMachine * m, ClusterVCToken & token, int options) +{ + // + // New connect protocol. + // As a VC initiator, establish the VC connection to the remote node + // by allocating the VC locally and requiring the caller to pass the + // token and channel id in the remote request. The remote handler calls + // connect_local to establish the remote side of the connection. + // + bool immediate = ((options & CLUSTER_OPT_IMMEDIATE) ? true : false); + bool allow_immediate = ((options & CLUSTER_OPT_ALLOW_IMMEDIATE) ? true : false); + + ClusterHandler *ch = m->clusterHandler; + if (!ch) + return NULL; + EThread *t = ch->thread; + if (!t) + return NULL; + + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + ClusterVConnection *vc = clusterVCAllocator.alloc(); + vc->new_connect_read = (options & CLUSTER_OPT_CONN_READ ? 1 : 0); + vc->start_time = ink_get_hrtime(); + vc->last_activity_time = vc->start_time; + vc->machine = m; + vc->token.alloc(); + token = vc->token; +#ifdef CLUSTER_THREAD_STEALING + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_OPENNED_STAT); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_OPEN_STAT); + MUTEX_TRY_LOCK(lock, ch->mutex, thread); + if (!lock) { +#endif + if (immediate) { + clusterVCAllocator_free(vc); + return NULL; + } + vc->action_ = cont; + ink_atomiclist_push(&ch->external_incoming_open_local, (void *) vc); + return CLUSTER_DELAYED_OPEN; + +#ifdef CLUSTER_THREAD_STEALING + } else { + if (!(immediate || allow_immediate)) + vc->action_ = cont; + if (vc->start(thread) < 0) { + return NULL; + } + if (immediate || allow_immediate) { + return vc; + } else { + return CLUSTER_DELAYED_OPEN; + } + } +#endif +} + +ClusterVConnection * +ClusterProcessor::connect_local(Continuation * cont, ClusterVCToken * token, int channel, int options) +{ + // + // Establish VC connection initiated by remote node on the local node + // using the given token and channel id. + // + bool immediate = ((options & CLUSTER_OPT_IMMEDIATE) ? true : false); + bool allow_immediate = ((options & CLUSTER_OPT_ALLOW_IMMEDIATE) ? true : false); + +#ifdef LOCAL_CLUSTER_TEST_MODE + int ip = inet_addr("127.0.0.1"); + ClusterMachine *m; + m = this_cluster->current_configuration()->find(ip, token->ip_created); +#else + ClusterMachine *m = this_cluster->current_configuration()->find(token->ip_created); +#endif + if (!m) + return NULL; + ClusterHandler *ch = m->clusterHandler; + if (!ch) + return NULL; + EThread *t = ch->thread; + if (!t) + return NULL; + + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + ClusterVConnection *vc = clusterVCAllocator.alloc(); + vc->new_connect_read = (options & CLUSTER_OPT_CONN_READ ? 1 : 0); + vc->start_time = ink_get_hrtime(); + vc->last_activity_time = vc->start_time; + vc->machine = m; + vc->token = *token; + vc->channel = channel; +#ifdef CLUSTER_THREAD_STEALING + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_OPENNED_STAT); + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_CONNECTIONS_OPEN_STAT); + MUTEX_TRY_LOCK(lock, ch->mutex, thread); + if (!lock) { +#endif + if (immediate) { + clusterVCAllocator_free(vc); + return NULL; + } + vc->mutex = ch->mutex; + vc->action_ = cont; + ch->thread->schedule_imm(vc); + return CLUSTER_DELAYED_OPEN; +#ifdef CLUSTER_THREAD_STEALING + } else { + if (!(immediate || allow_immediate)) + vc->action_ = cont; + if (vc->start(thread) < 0) { + return NULL; + } + if (immediate || allow_immediate) { + return vc; + } else { + return CLUSTER_DELAYED_OPEN; + } + } +#endif +} + +bool ClusterProcessor::disable_remote_cluster_ops(ClusterMachine * m) +{ + if (!m) + return false; + + ClusterHandler * + ch = m->clusterHandler; + if (ch) { + return ch->disable_remote_cluster_ops; + } else { + return true; + } +} + +//////////////////////////////////////////////////////////////////////////// +// Simplify debug access to stats +//////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// + +GlobalClusterPeriodicEvent * + PeriodicClusterEvent; + +#ifdef CLUSTER_TOMCAT +extern int cache_clustering_enabled; + +int CacheClusterMonitorEnabled = 0; +int CacheClusterMonitorIntervalSecs = 1; + +int cluster_send_buffer_size = 0; +int cluster_receive_buffer_size = 0; +unsigned long cluster_sockopt_flags = 0; + +int RPC_only_CacheCluster = 0; +#endif + +int +ClusterProcessor::init() +{ + cluster_rsb = RecAllocateRawStatBlock((int) cluster_stat_count); + // + // Statistics callbacks + // + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.connections_open", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CONNECTIONS_OPEN_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CONNECTIONS_OPEN_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.connections_opened", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CONNECTIONS_OPENNED_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CONNECTIONS_OPENNED_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.connections_closed", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CON_TOTAL_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CON_TOTAL_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.slow_ctrl_msgs_sent", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_SLOW_CTRL_MSGS_SENT_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_SLOW_CTRL_MSGS_SENT_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.connections_locked", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CONNECTIONS_LOCKED_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CONNECTIONS_LOCKED_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.reads", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_READ_BYTES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_READ_BYTES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.read_bytes", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_READ_BYTES_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_READ_BYTES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.writes", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_WRITE_BYTES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_WRITE_BYTES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.write_bytes", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_WRITE_BYTES_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_WRITE_BYTES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.control_messages_sent", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CTRL_MSGS_SEND_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CTRL_MSGS_SEND_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.control_messages_received", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CTRL_MSGS_RECV_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CTRL_MSGS_RECV_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.op_delayed_for_lock", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_OP_DELAYED_FOR_LOCK_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_OP_DELAYED_FOR_LOCK_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.connections_bumped", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CONNECTIONS_BUMPED_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CONNECTIONS_BUMPED_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.net_backup", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_NET_BACKUP_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_NET_BACKUP_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.nodes", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_NODES_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_NODES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.machines_allocated", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_MACHINES_ALLOCATED_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_MACHINES_ALLOCATED_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.machines_freed", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_MACHINES_FREED_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_MACHINES_FREED_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.configuration_changes", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CONFIGURATION_CHANGES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CONFIGURATION_CHANGES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.delayed_reads", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_DELAYED_READS_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_DELAYED_READS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.byte_bank_used", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_BYTE_BANK_USED_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_BYTE_BANK_USED_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.alloc_data_news", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_ALLOC_DATA_NEWS_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_ALLOC_DATA_NEWS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.write_bb_mallocs", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_WRITE_BB_MALLOCS_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_WRITE_BB_MALLOCS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.partial_reads", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_PARTIAL_READS_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_PARTIAL_READS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.partial_writes", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_PARTIAL_WRITES_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_PARTIAL_WRITES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.cache_outstanding", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CACHE_OUTSTANDING_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_OUTSTANDING_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.remote_op_timeouts", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_REMOTE_OP_TIMEOUTS_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_REMOTE_OP_TIMEOUTS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.remote_op_reply_timeouts", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_REMOTE_OP_REPLY_TIMEOUTS_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_REMOTE_OP_REPLY_TIMEOUTS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.chan_inuse", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CHAN_INUSE_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CHAN_INUSE_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.open_delays", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_OPEN_DELAY_TIME_STAT, RecRawStatSyncSum); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_OPEN_DELAY_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.connections_avg_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_CON_TOTAL_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CON_TOTAL_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.control_messages_avg_send_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_CTRL_MSGS_SEND_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CTRL_MSGS_SEND_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.control_messages_avg_receive_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_CTRL_MSGS_RECV_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CTRL_MSGS_RECV_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.open_delay_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_OPEN_DELAY_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_OPEN_DELAY_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.cache_callback_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_CACHE_CALLBACK_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_CALLBACK_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.rmt_cache_callback_time", + RECD_FLOAT, RECP_NON_PERSISTENT, + (int) CLUSTER_CACHE_RMT_CALLBACK_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_RMT_CALLBACK_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.lkrmt_cache_callback_time", + RECD_FLOAT, RECP_NON_PERSISTENT, + (int) CLUSTER_CACHE_LKRMT_CALLBACK_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_LKRMT_CALLBACK_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.local_connection_time", + RECD_FLOAT, RECP_NON_PERSISTENT, + (int) CLUSTER_LOCAL_CONNECTION_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_LOCAL_CONNECTION_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.remote_connection_time", + RECD_FLOAT, RECP_NON_PERSISTENT, + (int) CLUSTER_REMOTE_CONNECTION_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_REMOTE_CONNECTION_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.rdmsg_assemble_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_RDMSG_ASSEMBLE_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_RDMSG_ASSEMBLE_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.cluster_ping_time", + RECD_FLOAT, RECP_NON_PERSISTENT, (int) CLUSTER_PING_TIME_STAT, RecRawStatSyncHrTimeAvg); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_PING_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.cache_callbacks", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CACHE_CALLBACK_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_CALLBACK_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.rmt_cache_callbacks", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CACHE_RMT_CALLBACK_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_RMT_CALLBACK_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.lkrmt_cache_callbacks", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_CACHE_LKRMT_CALLBACK_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_CACHE_LKRMT_CALLBACK_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.local_connections_closed", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_LOCAL_CONNECTION_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_LOCAL_CONNECTION_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.remote_connections_closed", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_REMOTE_CONNECTION_TIME_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_REMOTE_CONNECTION_TIME_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.setdata_no_clustervc", + RECD_INT, RECP_NON_PERSISTENT, (int) cluster_setdata_no_CLUSTERVC_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(cluster_setdata_no_CLUSTERVC_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.setdata_no_tunnel", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_SETDATA_NO_TUNNEL_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_SETDATA_NO_TUNNEL_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.setdata_no_cachevc", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_SETDATA_NO_CACHEVC_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_SETDATA_NO_CACHEVC_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.setdata_no_cluster", + RECD_INT, RECP_NON_PERSISTENT, (int) cluster_setdata_no_CLUSTER_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(cluster_setdata_no_CLUSTER_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_write_stall", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_WRITE_STALL_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_WRITE_STALL_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.no_remote_space", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_NO_REMOTE_SPACE_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_NO_REMOTE_SPACE_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.level1_bank", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_LEVEL1_BANK_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_LEVEL1_BANK_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.multilevel_bank", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_MULTILEVEL_BANK_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_MULTILEVEL_BANK_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_insert_lock_misses", + RECD_INT, RECP_NON_PERSISTENT, + (int) CLUSTER_VC_CACHE_INSERT_LOCK_MISSES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_INSERT_LOCK_MISSES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_inserts", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_CACHE_INSERTS_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_INSERTS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_lookup_lock_misses", + RECD_INT, RECP_NON_PERSISTENT, + (int) CLUSTER_VC_CACHE_LOOKUP_LOCK_MISSES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_LOOKUP_LOCK_MISSES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_lookup_hits", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_CACHE_LOOKUP_HITS_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_LOOKUP_HITS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_lookup_misses", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_CACHE_LOOKUP_MISSES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_LOOKUP_MISSES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_scans", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_CACHE_SCANS_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_SCANS_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_scan_lock_misses", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_CACHE_SCAN_LOCK_MISSES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_SCAN_LOCK_MISSES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.vc_cache_purges", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_VC_CACHE_PURGES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_VC_CACHE_PURGES_STAT); + RecRegisterRawStat(cluster_rsb, RECT_PROCESS, + "proxy.process.cluster.write_lock_misses", + RECD_INT, RECP_NON_PERSISTENT, (int) CLUSTER_WRITE_LOCK_MISSES_STAT, RecRawStatSyncCount); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_WRITE_LOCK_MISSES_STAT); + CLUSTER_CLEAR_DYN_STAT(CLUSTER_NODES_STAT); // clear sum and count + // INKqa08033: win2k: ui: cluster warning light on + // Used to call CLUSTER_INCREMENT_DYN_STAT here; switch to SUM_GLOBAL_DYN_STAT + CLUSTER_SUM_GLOBAL_DYN_STAT(CLUSTER_NODES_STAT, 1); // one node in cluster, ME + + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_monitor_enabled, "proxy.config.cluster.load_monitor_enabled"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_ping_message_send_msec_interval, "proxy.config.cluster.ping_send_interval_msecs"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_num_ping_response_buckets, "proxy.config.cluster.ping_response_buckets"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_msecs_per_ping_response_bucket, "proxy.config.cluster.msecs_per_ping_response_bucket"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_ping_latency_threshold_msecs, "proxy.config.cluster.ping_latency_threshold_msecs"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_cluster_load_compute_msec_interval, "proxy.config.cluster.load_compute_interval_msecs"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_cluster_periodic_msec_interval, "proxy.config.cluster.periodic_timer_interval_msecs"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_ping_history_buf_length, "proxy.config.cluster.ping_history_buf_length"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_cluster_load_clear_duration, "proxy.config.cluster.cluster_load_clear_duration"); + IOCORE_ReadConfigInteger(ClusterLoadMonitor::cf_cluster_load_exceed_duration, "proxy.config.cluster.cluster_load_exceed_duration"); + + // + // Configuration callbacks + // + if (cluster_port_number != DEFAULT_CLUSTER_PORT_NUMBER) + cluster_port = cluster_port_number; + else { + IOCORE_ReadConfigInteger(cluster_port, "proxy.config.cluster.cluster_port"); + } + + IOCORE_EstablishStaticConfigInt32(CacheClusterMonitorEnabled, "proxy.config.cluster.enable_monitor"); + IOCORE_EstablishStaticConfigInt32(CacheClusterMonitorIntervalSecs, "proxy.config.cluster.monitor_interval_secs"); + IOCORE_ReadConfigInteger(cluster_receive_buffer_size, "proxy.config.cluster.receive_buffer_size"); + IOCORE_ReadConfigInteger(cluster_send_buffer_size, "proxy.config.cluster.send_buffer_size"); + IOCORE_ReadConfigInteger(cluster_sockopt_flags, "proxy.config.cluster.sock_option_flag"); + IOCORE_EstablishStaticConfigInt32(RPC_only_CacheCluster, "proxy.config.cluster.rpc_cache_cluster"); + + int cluster_type = 0; + IOCORE_ReadConfigInteger(cluster_type, "proxy.local.cluster.type"); + + create_this_cluster_machine(); +#ifdef NON_MODULAR + // Cluster API Initializations + clusterAPI_init(); +#endif + // Start global Cluster periodic event + PeriodicClusterEvent = NEW(new GlobalClusterPeriodicEvent); + PeriodicClusterEvent->init(); + + this_cluster = NEW(new Cluster); + ClusterConfiguration *cc = NEW(new ClusterConfiguration); + this_cluster->configurations.push(cc); + cc->n_machines = 1; + cc->machines[0] = this_cluster_machine(); + memset(cc->hash_table, 0, CLUSTER_HASH_TABLE_SIZE); + // 0 dummy output data + + memset(channel_dummy_output, 0, sizeof(channel_dummy_output)); + + if (cluster_type == 1) { + cache_clustering_enabled = 1; + Note("cache clustering enabled"); + compute_cluster_mode(); + } else { + cache_clustering_enabled = 0; + Note("cache clustering disabled"); + } + return 0; +} + +// function added to adhere to the name calling convention of init functions +int +init_clusterprocessor(void) +{ + return clusterProcessor.init(); +} + +int +ClusterProcessor::start() +{ +#ifdef LOCAL_CLUSTER_TEST_MODE + this_cluster_machine()->cluster_port = cluster_port; +#endif + if (cache_clustering_enabled && (cacheProcessor.IsCacheEnabled() == CACHE_INITIALIZED)) { + + ET_CLUSTER = eventProcessor.spawn_event_threads(1, "ET_CLUSTER"); + for (int i = 0; i < eventProcessor.n_threads_for_type[ET_CLUSTER]; i++) { + initialize_thread_for_net(eventProcessor.eventthread[ET_CLUSTER][i], i); + } + IOCORE_RegisterConfigUpdateFunc("proxy.config.cluster.cluster_configuration", machine_config_change, (void *) CLUSTER_CONFIG); + do_machine_config_change((void *) CLUSTER_CONFIG, "proxy.config.cluster.cluster_configuration"); + // TODO: Remove this? +#ifdef USE_SEPARATE_MACHINE_CONFIG + IOCORE_RegisterConfigUpdateFunc("proxy.config.cluster.machine_configuration", machine_config_change, (void *) MACHINE_CONFIG); + do_machine_config_change((void *) MACHINE_CONFIG, "proxy.config.cluster.machine_configuration"); +#endif + + accept_handler = NEW(new ClusterAccept(&cluster_port, cluster_receive_buffer_size, cluster_send_buffer_size)); + accept_handler->Init(); + } + return 0; +} + +void +ClusterProcessor::connect(char *hostname) +{ + // + // Construct a cluster link to the given machine + // + ClusterHandler *ch = NEW(new ClusterHandler); + SET_CONTINUATION_HANDLER(ch, (ClusterContHandler) & ClusterHandler::connectClusterEvent); + ch->hostname = xstrdup(hostname); + ch->connector = true; + eventProcessor.schedule_imm(ch, ET_CLUSTER); +} + +void +ClusterProcessor::connect(unsigned int ip, int port, bool delay) +{ + // + // Construct a cluster link to the given machine + // + ClusterHandler *ch = NEW(new ClusterHandler); + SET_CONTINUATION_HANDLER(ch, (ClusterContHandler) & ClusterHandler::connectClusterEvent); + ch->ip = ip; + ch->port = port; + ch->connector = true; + if (delay) + eventProcessor.schedule_in(ch, CLUSTER_MEMBER_DELAY, ET_CLUSTER); + else + eventProcessor.schedule_imm(ch, ET_CLUSTER); +} + +void +ClusterProcessor::send_machine_list(ClusterMachine * m) +{ + // + // In testing mode, cluster nodes automagically connect to all + // known hosts. This function is called on connect to exchange those + // lists. + // + MachineListMessage mlistmsg; + int vers = MachineListMessage::protoToVersion(m->msg_proto_major); + ClusterConfiguration *cc = this_cluster->current_configuration(); + void *data; + int len; + + if (vers == MachineListMessage::MACHINE_LIST_MESSAGE_VERSION) { + int n = 0; + MachineListMessage *msg = &mlistmsg; + + while (n < cc->n_machines) { + msg->ip[n] = cc->machines[n]->ip; + n++; + } + msg->n_ip = n; + data = (void *) msg; + len = msg->sizeof_fixedlen_msg() + (n * sizeof(uint32_t)); + + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"send_machine_list() bad msg version"); + } + invoke_remote(m, MACHINE_LIST_CLUSTER_FUNCTION, data, len); +} + +void +ClusterProcessor::compute_cluster_mode() +{ + if (RPC_only_CacheCluster) { + if (cache_clustering_enabled > 0) { + cache_clustering_enabled = -1; + Note("RPC only cache clustering"); + } + } else { + if (cache_clustering_enabled < 0) { + cache_clustering_enabled = 1; + Note("RPC only cache clustering disabled"); + } + } +} + +// End of ClusterProcessor.cc diff --git a/iocore/cluster/ClusterRPC.cc b/iocore/cluster/ClusterRPC.cc new file mode 100644 index 00000000..58302aff --- /dev/null +++ b/iocore/cluster/ClusterRPC.cc @@ -0,0 +1,386 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterRPC.cc +****************************************************************************/ + +#include "P_Cluster.h" +///////////////////////////////////////////////////////////////////////// +// All RPC function handlers (xxx_ClusterFunction() ) are invoked from +// ClusterHandler::update_channels_read(). +///////////////////////////////////////////////////////////////////////// + +void +ping_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + // + // Just return the data back + // + clusterProcessor.invoke_remote(from, PING_REPLY_CLUSTER_FUNCTION, data, len); +} + +void +ping_reply_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + // + // Pass back the data. + // + (void) from; + PingMessage *msg = (PingMessage *) data; + msg->fn(from, msg->data, (len - msg->sizeof_fixedlen_msg())); +} + +void +machine_list_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + (void) from; + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + MachineListMessage *m = (MachineListMessage *) data; + + if (mh->GetMsgVersion() != MachineListMessage::MACHINE_LIST_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"machine_list_ClusterFunction() bad msg version"); + } + if (m->NeedByteSwap()) + m->SwapBytes(); + + ink_assert(m->n_ip == ((len - m->sizeof_fixedlen_msg()) / sizeof(uint32_t))); + + // + // The machine list is a vector of ip's stored in network byte order. + // This list is exchanged whenever a new Cluster Connection is formed. + // + ClusterConfiguration *cc = this_cluster()->current_configuration(); + + for (unsigned int i = 0; i < m->n_ip; i++) { + for (int j = 0; j < cc->n_machines; j++) { + if (cc->machines[j]->ip == m->ip[i]) + goto Lfound; + } + // not found, must be a new machine + clusterProcessor.connect(m->ip[i]); + Lfound: + ; + } +} + +void +close_channel_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + CloseMessage *m = (CloseMessage *) data; + + if (mh->GetMsgVersion() != CloseMessage::CLOSE_CHAN_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"close_channel_ClusterFunction() bad msg version"); + } + if (m->NeedByteSwap()) + m->SwapBytes(); + + // + // Close the remote side of a VC connection (remote node is originator) + // + ink_assert(len >= (int) sizeof(CloseMessage)); + ClusterHandler *ch = from->clusterHandler; + if (!ch || !ch->channels) + return; + ClusterVConnection *vc = ch->channels[m->channel]; + if (VALID_CHANNEL(vc) && vc->token.sequence_number == m->sequence_number) { + vc->remote_closed = m->status; + vc->remote_lerrno = m->lerrno; + } +} + +void +test_ClusterFunction(ClusterMachine * m, void *data, int len) +{ + // + // Note: Only for testing. + // + if (ptest_ClusterFunction) + ptest_ClusterFunction(m, data, len); +} + +CacheVC * +ChannelToCacheWriteVC(ClusterHandler * ch, int channel, uint32_t channel_seqno, ClusterVConnection ** cluster_vc) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + ClusterVConnection *cvc = ch->channels[channel]; + if (!VALID_CHANNEL(cvc) + || (channel_seqno != cvc->token.sequence_number) + || (cvc->read.vio.op != VIO::READ)) { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTERVC_STAT); + return NULL; + } + // Tunneling from cluster to cache (remote write). + // Get cache VC pointer. + + OneWayTunnel *owt = (OneWayTunnel *) cvc->read.vio._cont; + if (!owt) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_SETDATA_NO_TUNNEL_STAT); + return NULL; + } + CacheVC *cache_vc = (CacheVC *) owt->vioTarget->vc_server; + if (!cache_vc) { + CLUSTER_INCREMENT_DYN_STAT(CLUSTER_SETDATA_NO_CACHEVC_STAT); + return NULL; + } + *cluster_vc = cvc; + return cache_vc; +} + +void +set_channel_data_ClusterFunction(ClusterMachine * from, void *tdata, int tlen) +{ + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + // We are called on the ET_CLUSTER thread. + + char *data; + int len; + int res; + + // Allocate memory for set channel data and pass it to the cache + IncomingControl *ic = IncomingControl::alloc(); + ic->len = tlen; + ic->alloc_data(); + + data = ic->data + sizeof(int32_t); // free_remote_data expects d+sizeof(int32_t) + memcpy(data, tdata, tlen); + len = tlen; + + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + SetChanDataMessage *m = (SetChanDataMessage *) data; + + if (mh->GetMsgVersion() != SetChanDataMessage::SET_CHANNEL_DATA_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"set_channel_data_ClusterFunction() bad msg version"); + } + if (m->NeedByteSwap()) + m->SwapBytes(); + + ClusterVConnection *cvc; + CacheVC *cache_vc; + ClusterHandler *ch = from->clusterHandler; + + if (ch) { + cache_vc = ChannelToCacheWriteVC(ch, m->channel, m->sequence_number, &cvc); + if (!cache_vc) { + ic->freeall(); + return; + } + // Unmarshal data. + switch (m->data_type) { + case CACHE_DATA_HTTP_INFO: + { + char *p = (char *) m + SetChanDataMessage::sizeof_fixedlen_msg(); + + IOBufferBlock *block_ref = ic->get_block(); + res = HTTPInfo::unmarshal(p, len, block_ref); + ink_assert(res > 0); + + CacheHTTPInfo h; + h.get_handle((char *) &m->data[0], len); + h.set_buffer_reference(block_ref); + cache_vc->set_http_info(&h); + ic->freeall(); + break; + } + default: + { + ink_release_assert(!"set_channel_data_ClusterFunction bad CacheDataType"); + } + } // End of switch + ++cvc->n_recv_set_data_msgs; // note received messages + + } else { + ic->freeall(); + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTER_STAT); + } +} + +void +post_setchan_send_ClusterFunction(ClusterMachine * to, void *data, int len) +{ + NOWARN_UNUSED(len); + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + // We are called on the ET_CLUSTER thread. + // set_data() control message has been queued into cluster transfer message. + // This allows us to assume that it has been sent. + // Decrement Cluster VC n_set_data_msgs to allow transmission of + // initial open_write data after (n_set_data_msgs == 0). + + SetChanDataMessage *m = (SetChanDataMessage *) data; + ClusterHandler *ch = to->clusterHandler; + ClusterVConnection *cvc; + + if (ch) { + cvc = ch->channels[m->channel]; + if (VALID_CHANNEL(cvc)) { + ink_atomic_increment(&cvc->n_set_data_msgs, -1); + } else { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTERVC_STAT); + } + } else { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTER_STAT); + } +} + +void +set_channel_pin_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + NOWARN_UNUSED(len); + // This isn't used. /leif + //EThread *thread = this_ethread(); + //ProxyMutex *mutex = thread->mutex; + + // We are called on the ET_CLUSTER thread. + + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + SetChanPinMessage *m = (SetChanPinMessage *) data; + + if (mh->GetMsgVersion() != SetChanPinMessage::SET_CHANNEL_PIN_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"set_channel_pin_ClusterFunction() bad msg version"); + } + + if (m->NeedByteSwap()) + m->SwapBytes(); + + ClusterVConnection *cvc = NULL; // Just to make GCC happy + CacheVC *cache_vc; + ClusterHandler *ch; + + if ((ch = from->clusterHandler) != 0) { + cache_vc = ChannelToCacheWriteVC(ch, m->channel, m->sequence_number, &cvc); + if (cache_vc) { + cache_vc->set_pin_in_cache(m->pin_time); + } + // cvc is always set in ChannelToCacheWriteVC, so need to check it + ++cvc->n_recv_set_data_msgs; // note received messages + } +} + +void +post_setchan_pin_ClusterFunction(ClusterMachine * to, void *data, int len) +{ + NOWARN_UNUSED(len); + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + // We are called on the ET_CLUSTER thread. + // Control message has been queued into cluster transfer message. + // This allows us to assume that it has been sent. + // Decrement Cluster VC n_set_data_msgs to allow transmission of + // initial open_write data after (n_set_data_msgs == 0). + + SetChanPinMessage *m = (SetChanPinMessage *) data; + ClusterHandler *ch = to->clusterHandler; + ClusterVConnection *cvc; + + if (ch) { + cvc = ch->channels[m->channel]; + if (VALID_CHANNEL(cvc)) { + ink_atomic_increment(&cvc->n_set_data_msgs, -1); + } else { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTERVC_STAT); + } + } else { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTER_STAT); + } +} + +void +set_channel_priority_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + NOWARN_UNUSED(len); + // This isn't used. + //EThread *thread = this_ethread(); + //ProxyMutex *mutex = thread->mutex; + + // We are called on the ET_CLUSTER thread. + + ClusterMessageHeader *mh = (ClusterMessageHeader *) data; + SetChanPriorityMessage *m = (SetChanPriorityMessage *) data; + + if (mh->GetMsgVersion() != SetChanPriorityMessage::SET_CHANNEL_PRIORITY_MESSAGE_VERSION) { //////////////////////////////////////////////// + // Convert from old to current message format + //////////////////////////////////////////////// + ink_release_assert(!"set_channel_priority_ClusterFunction() bad msg version"); + } + if (m->NeedByteSwap()) + m->SwapBytes(); + + ClusterVConnection *cvc = NULL; // Just to make GCC happy + CacheVC *cache_vc; + ClusterHandler *ch; + + if ((ch = from->clusterHandler) != 0) { + cache_vc = ChannelToCacheWriteVC(ch, m->channel, m->sequence_number, &cvc); + if (cache_vc) { + cache_vc->set_disk_io_priority(m->disk_priority); + } + // cvc is always set in ChannelToCacheWriteVC, so need to check it + ++cvc->n_recv_set_data_msgs; // note received messages + } +} + +void +post_setchan_priority_ClusterFunction(ClusterMachine * to, void *data, int len) +{ + NOWARN_UNUSED(len); + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + // We are called on the ET_CLUSTER thread. + // Control message has been queued into cluster transfer message. + // This allows us to assume that it has been sent. + // Decrement Cluster VC n_set_data_msgs to allow transmission of + // initial open_write data after (n_set_data_msgs == 0). + + SetChanPriorityMessage *m = (SetChanPriorityMessage *) data; + ClusterHandler *ch = to->clusterHandler; + ClusterVConnection *cvc; + + if (ch) { + cvc = ch->channels[m->channel]; + if (VALID_CHANNEL(cvc)) { + ink_atomic_increment(&cvc->n_set_data_msgs, -1); + } else { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTERVC_STAT); + } + } else { + CLUSTER_INCREMENT_DYN_STAT(cluster_setdata_no_CLUSTER_STAT); + } +} + +// End of ClusterRPC.cc diff --git a/iocore/cluster/ClusterVConnection.cc b/iocore/cluster/ClusterVConnection.cc new file mode 100644 index 00000000..b6a09133 --- /dev/null +++ b/iocore/cluster/ClusterVConnection.cc @@ -0,0 +1,629 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterVConnection.cc +****************************************************************************/ + +#include "P_Cluster.h" +ClassAllocator clusterVCAllocator("clusterVCAllocator"); +ClassAllocator byteBankAllocator("byteBankAllocator"); + +ByteBankDescriptor * +ByteBankDescriptor::ByteBankDescriptor_alloc(IOBufferBlock * iob) +{ + ByteBankDescriptor *b = byteBankAllocator.alloc(); + b->block = iob; + return b; +} + +void +ByteBankDescriptor::ByteBankDescriptor_free(ByteBankDescriptor * b) +{ + b->block = 0; + byteBankAllocator.free(b); +} + +void +clusterVCAllocator_free(ClusterVConnection * vc) +{ + vc->mutex = 0; + vc->action_ = 0; + vc->free(); + clusterVCAllocator.free(vc); +} + +ClusterVConnState::ClusterVConnState():enabled(0), priority(1), vio(VIO::NONE), queue(0), ifd(-1), delay_timeout(NULL) +{ +} + +ClusterVConnectionBase::ClusterVConnectionBase(): +thread(0), closed(0), inactivity_timeout_in(0), active_timeout_in(0), inactivity_timeout(NULL), active_timeout(NULL) +{ +} + +#ifdef DEBUG +int + ClusterVConnectionBase::enable_debug_trace = 0; +#endif + +VIO * +ClusterVConnectionBase::do_io_read(Continuation * acont, int64_t anbytes, MIOBuffer * abuffer) +{ + ink_assert(!closed); + read.vio.buffer.writer_for(abuffer); + read.vio.op = VIO::READ; + read.vio.set_continuation(acont); + read.vio.nbytes = anbytes; + read.vio.ndone = 0; + read.vio.vc_server = (VConnection *) this; + read.enabled = 1; + + ClusterVConnection *cvc = (ClusterVConnection *) this; + Debug("cluster_vc_xfer", "do_io_read [%s] chan %d", "", cvc->channel); + return &read.vio; +} + +VIO * +ClusterVConnectionBase::do_io_pread(Continuation * acont, int64_t anbytes, MIOBuffer * abuffer, int64_t off) +{ + NOWARN_UNUSED(acont); + NOWARN_UNUSED(anbytes); + NOWARN_UNUSED(abuffer); + NOWARN_UNUSED(off); + ink_assert(!"implemented"); + return 0; +} + +int +ClusterVConnection::get_header(void **ptr, int *len) +{ + NOWARN_UNUSED(ptr); + NOWARN_UNUSED(len); + ink_assert(!"implemented"); + return -1; +} + +int +ClusterVConnection::set_header(void *ptr, int len) +{ + NOWARN_UNUSED(ptr); + NOWARN_UNUSED(len); + ink_assert(!"implemented"); + return -1; +} + +int +ClusterVConnection::get_single_data(void **ptr, int *len) +{ + NOWARN_UNUSED(ptr); + NOWARN_UNUSED(len); + ink_assert(!"implemented"); + return -1; +} + +VIO * +ClusterVConnectionBase::do_io_write(Continuation * acont, int64_t anbytes, IOBufferReader * abuffer, bool owner) +{ + ink_assert(!closed); + ink_assert(!owner); + write.vio.buffer.reader_for(abuffer); + write.vio.op = VIO::WRITE; + write.vio.set_continuation(acont); + write.vio.nbytes = anbytes; + write.vio.ndone = 0; + write.vio.vc_server = (VConnection *) this; + write.enabled = 1; + + return &write.vio; +} + +void +ClusterVConnectionBase::do_io_close(int alerrno) +{ + read.enabled = 0; + write.enabled = 0; + read.vio.buffer.clear(); + write.vio.buffer.clear(); + INK_WRITE_MEMORY_BARRIER; + if (alerrno && alerrno != -1) + this->lerrno = alerrno; + + if (alerrno == -1) { + closed = 1; + } else { + closed = -1; + } +} + +void +ClusterVConnectionBase::reenable(VIO * vio) +{ + ink_assert(!closed); + if (vio == &read.vio) { + read.enabled = 1; +#ifdef DEBUG + if (enable_debug_trace && (vio->buffer.mbuf && !vio->buffer.writer()->write_avail())) + printf("NetVConnection re-enabled for read when full\n"); +#endif + } else if (vio == &write.vio) { + write.enabled = 1; +#ifdef DEBUG + if (enable_debug_trace && (vio->buffer.mbuf && !vio->buffer.reader()->read_avail())) + printf("NetVConnection re-enabled for write when empty\n"); +#endif + } else { + ink_assert(!"bad vio"); + } +} + +void +ClusterVConnectionBase::reenable_re(VIO * vio) +{ + reenable(vio); +} + +ClusterVConnection::ClusterVConnection(int is_new_connect_read) + : machine(NULL), + new_connect_read(is_new_connect_read), + remote_free(0), + last_local_free(0), + channel(0), + close_disabled(0), + remote_closed(0), + remote_close_disabled(1), + remote_lerrno(0), + start_time(0), + last_activity_time(0), + n_set_data_msgs(0), + n_recv_set_data_msgs(0), + pending_remote_fill(0), + have_all_data(0), + initial_data_bytes(0), + current_cont(0), + iov_map(CLUSTER_IOV_NOT_OPEN), + write_list_tail(0), + write_list_bytes(0), + write_bytes_in_transit(0), + alternate(), + time_pin(0), + disk_io_priority(0) +{ +#ifdef DEBUG + read.vio.buffer.name = "ClusterVConnection.read"; + write.vio.buffer.name = "ClusterVConnection.write"; +#endif + SET_HANDLER((ClusterVConnHandler) & ClusterVConnection::startEvent); +} + +ClusterVConnection::~ClusterVConnection() +{ + free(); +} + +void +ClusterVConnection::free() +{ + if (alternate.valid()) { + alternate.destroy(); + } + ByteBankDescriptor *d; + while ((d = byte_bank_q.dequeue())) { + ByteBankDescriptor::ByteBankDescriptor_free(d); + } + read_block = 0; + remote_write_block = 0; + marshal_buf = 0; + write_list = 0; + write_list_tail = 0; + write_list_bytes = 0; + write_bytes_in_transit = 0; +} + +void +ClusterVConnection::do_io_close(int alerrno) +{ +#ifdef CLUSTER_TOMCAT + ProxyMutex *mutex = (this_ethread())->mutex; +#endif + ink_hrtime now = ink_get_hrtime(); + CLUSTER_SUM_DYN_STAT(CLUSTER_CON_TOTAL_TIME_STAT, now - start_time); + CLUSTER_SUM_DYN_STAT(CLUSTER_LOCAL_CONNECTION_TIME_STAT, now - start_time); + ClusterVConnectionBase::do_io_close(alerrno); +} + +int +ClusterVConnection::startEvent(int event, Event * e) +{ + // + // Safe to call with e == NULL from the same thread. + // + (void) event; + start(e ? e->ethread : (EThread *) NULL); + return EVENT_DONE; +} + +int +ClusterVConnection::mainEvent(int event, Event * e) +{ + (void) event; + (void) e; + ink_assert(!"unexpected event"); + return EVENT_DONE; +} + +int +ClusterVConnection::start(EThread * t) +{ + // + // New channel connect protocol. Establish VC locally and send the + // channel id to the target. Reverse of existing connect protocol + // + ////////////////////////////////////////////////////////////////////////// + // In the new VC connect protocol, we always establish the local side + // of the connection followed by the remote side. + // + // Read connection notes: + // ---------------------- + // The response message now consists of the standard reply message + // along with a portion of the object data. This data is always + // transferred in the same Cluster transfer message as channel data. + // In order to transfer data into a partially connected VC, we introduced + // a VC "pending_remote_fill" state allowing us to move the initial data + // using the existing user channel mechanism. + // Initially, both sides of the connection set "pending_remote_fill". + // + // "pending_remote_fill" allows us to make the following assumptions. + // 1) No free space messages are sent for VC(s) in this state. + // 2) Writer side, the initial write data is described by + // vc->remote_write_block NOT by vc->write.vio.buffer, since + // vc->write.vio is reserved for use in the OneWayTunnel. + // OneWayTunnel is used when all the object data cannot be + // contained in the initial send buffer. + // 3) Writer side, write vio mutex not acquired for initial data write. + /////////////////////////////////////////////////////////////////////////// + + int status; + ClusterHandler *ch = NULL; + if (!channel) { +#ifdef CLUSTER_TOMCAT + Ptr m = action_.mutex; + if (!m) { + m = new_ProxyMutex(); + } +#else + Ptr m = action_.mutex; +#endif + + // Establish the local side of the VC connection + MUTEX_TRY_LOCK(lock, m, t); + if (!lock) { + t->schedule_in(this, CLUSTER_CONNECT_RETRY); + return EVENT_DONE; + } + ch = machine->clusterHandler; + if (!ch) { + if (action_.continuation) { + action_.continuation->handleEvent(CLUSTER_EVENT_OPEN_FAILED, (void *) -ECLUSTER_NO_MACHINE); + clusterVCAllocator_free(this); + return EVENT_DONE; + } else { + // if we have been invoked immediately + clusterVCAllocator_free(this); + return -1; + } + } + + channel = ch->alloc_channel(this); + if (channel < 0) { + if (action_.continuation) { + action_.continuation->handleEvent(CLUSTER_EVENT_OPEN_FAILED, (void *) -ECLUSTER_NOMORE_CHANNELS); + clusterVCAllocator_free(this); + return EVENT_DONE; + } else { + // if we have been invoked immediately + clusterVCAllocator_free(this); + return -1; + } + + } else { + Debug(CL_TRACE, "VC start alloc local chan=%d VC=0x%x", channel, this); + if (new_connect_read) + this->pending_remote_fill = 1; + } + + } else { + // Establish the remote side of the VC connection + ch = machine->clusterHandler; + if ((status = ch->alloc_channel(this, channel)) < 0) { + Debug(CL_TRACE, "VC start alloc remote failed chan=%d VC=0x%x", channel, this); + clusterVCAllocator_free(this); + return status; // Channel active or no more channels + } else { + Debug(CL_TRACE, "VC start alloc remote chan=%d VC=0x%x", channel, this); + if (new_connect_read) + this->pending_remote_fill = 1; + this->iov_map = CLUSTER_IOV_NONE; // disable connect timeout + } + } + cluster_set_priority(ch, &read, CLUSTER_INITIAL_PRIORITY); + cluster_schedule(ch, this, &read); + cluster_set_priority(ch, &write, CLUSTER_INITIAL_PRIORITY); + cluster_schedule(ch, this, &write); + if (action_.continuation) { + action_.continuation->handleEvent(CLUSTER_EVENT_OPEN, this); + } + mutex = NULL; + return EVENT_DONE; +} + +int +ClusterVConnection::was_closed() +{ + return (closed && !close_disabled); +} + +void +ClusterVConnection::allow_close() +{ + close_disabled = 0; +} + +void +ClusterVConnection::disable_close() +{ + close_disabled = 1; +} + +int +ClusterVConnection::was_remote_closed() +{ + if (!byte_bank_q.head && !remote_close_disabled) + return remote_closed; + else + return 0; +} + +void +ClusterVConnection::allow_remote_close() +{ + remote_close_disabled = 0; +} + +bool ClusterVConnection::schedule_write() +{ + // + // Schedule write if we have all data or current write data is + // at least DEFAULT_MAX_BUFFER_SIZE. + // + if (write_list) { + if ((closed < 0) || remote_closed) { + // User aborted connection, dump data. + + write_list = 0; + write_list_tail = 0; + write_list_bytes = 0; + + return false; + } + + if (closed || (write_list_bytes >= DEFAULT_MAX_BUFFER_SIZE)) { + // No more data to write or buffer list is full, start write + return true; + } else { + // Buffer list is not full, defer write + return false; + } + } else { + return false; + } +} + +void +ClusterVConnection::set_type(int options) +{ + new_connect_read = (options & CLUSTER_OPT_CONN_READ) ? 1 : 0; + if (new_connect_read) { + pending_remote_fill = 1; + } else { + pending_remote_fill = 0; + } +} + +// Overide functions in base class VConnection. +bool ClusterVConnection::get_data(int id, void *data) +{ + switch (id) { + case CACHE_DATA_SIZE: + { + *((int64_t *) data) = get_object_size(); + return true; + } + case CACHE_DATA_HTTP_INFO: + { + ink_release_assert(!"ClusterVConnection::get_data CACHE_DATA_HTTP_INFO not supported"); + } + case CACHE_DATA_KEY: + { + ink_release_assert(!"ClusterVConnection::get_data CACHE_DATA_KEY not supported"); + } + default: + { + ink_release_assert(!"ClusterVConnection::get_data invalid id"); + } + } + return false; +} + +void +ClusterVConnection::get_http_info(CacheHTTPInfo ** info) +{ + *info = &alternate; +} + +int64_t +ClusterVConnection::get_object_size() +{ + return alternate.object_size_get(); +} + +void +ClusterVConnection::set_http_info(CacheHTTPInfo * d) +{ + int flen, len; + void *data; + int res; + SetChanDataMessage *m; + SetChanDataMessage msg; + + // + // set_http_info() is a mechanism to associate additional data with a + // open_write() ClusterVConnection. It is only allowed after a + // successful open_write() and prior to issuing the do_io(VIO::WRITE). + // Cache semantics dictate that set_http_info() be established prior + // to transferring any data on the ClusterVConnection. + // + ink_release_assert(this->write.vio.op == VIO::NONE); // not true if do_io() + // already done + ink_release_assert(this->read.vio.op == VIO::NONE); // should always be true + + int vers = SetChanDataMessage::protoToVersion(machine->msg_proto_major); + if (vers == SetChanDataMessage::SET_CHANNEL_DATA_MESSAGE_VERSION) { + flen = SetChanDataMessage::sizeof_fixedlen_msg(); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"ClusterVConnection::set_http_info() bad msg version"); + } + + // Create message and marshal data. + + CacheHTTPInfo *r = d; + len = r->marshal_length(); + data = (void *) ALLOCA_DOUBLE(flen + len); + memcpy((char *) data, (char *) &msg, sizeof(msg)); + m = (SetChanDataMessage *) data; + m->data_type = CACHE_DATA_HTTP_INFO; + + char *p = (char *) m + flen; + res = r->marshal(p, len); + if (res < 0) { + r->destroy(); + return; + } + r->destroy(); + + m->channel = channel; + m->sequence_number = token.sequence_number; + + // note pending set_data() msgs on VC. + ink_atomic_increment(&n_set_data_msgs, 1); + + clusterProcessor.invoke_remote(machine, SET_CHANNEL_DATA_CLUSTER_FUNCTION, data, flen + len); +} + +bool ClusterVConnection::set_pin_in_cache(time_t t) +{ + SetChanPinMessage msg; + + // + // set_pin_in_cache() is a mechanism to set an attribute on a + // open_write() ClusterVConnection. It is only allowed after a + // successful open_write() and prior to issuing the do_io(VIO::WRITE). + // + ink_release_assert(this->write.vio.op == VIO::NONE); // not true if do_io() + // already done + ink_release_assert(this->read.vio.op == VIO::NONE); // should always be true + time_pin = t; + + int vers = SetChanPinMessage::protoToVersion(machine->msg_proto_major); + + if (vers == SetChanPinMessage::SET_CHANNEL_PIN_MESSAGE_VERSION) { + SetChanPinMessage::sizeof_fixedlen_msg(); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"ClusterVConnection::set_pin_in_cache() bad msg " "version"); + } + msg.channel = channel; + msg.sequence_number = token.sequence_number; + msg.pin_time = time_pin; + + // note pending set_data() msgs on VC. + ink_atomic_increment(&n_set_data_msgs, 1); + + clusterProcessor.invoke_remote(machine, SET_CHANNEL_PIN_CLUSTER_FUNCTION, (char *) &msg, sizeof(msg)); + return true; +} + +time_t ClusterVConnection::get_pin_in_cache() +{ + return time_pin; +} + +bool ClusterVConnection::set_disk_io_priority(int priority) +{ + SetChanPriorityMessage msg; + + // + // set_disk_io_priority() is a mechanism to set an attribute on a + // open_write() ClusterVConnection. It is only allowed after a + // successful open_write() and prior to issuing the do_io(VIO::WRITE). + // + ink_release_assert(this->write.vio.op == VIO::NONE); // not true if do_io() + // already done + ink_release_assert(this->read.vio.op == VIO::NONE); // should always be true + disk_io_priority = priority; + + int vers = SetChanPriorityMessage::protoToVersion(machine->msg_proto_major); + + if (vers == SetChanPriorityMessage::SET_CHANNEL_PRIORITY_MESSAGE_VERSION) { + SetChanPriorityMessage::sizeof_fixedlen_msg(); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"ClusterVConnection::set_disk_io_priority() bad msg " "version"); + } + msg.channel = channel; + msg.sequence_number = token.sequence_number; + msg.disk_priority = priority; + + // note pending set_data() msgs on VC. + ink_atomic_increment(&n_set_data_msgs, 1); + + clusterProcessor.invoke_remote(machine, SET_CHANNEL_PRIORITY_CLUSTER_FUNCTION, (char *) &msg, sizeof(msg)); + return true; +} + +int +ClusterVConnection::get_disk_io_priority() +{ + return disk_io_priority; +} + +// End of ClusterVConnection.cc diff --git a/iocore/cluster/Inline.cc b/iocore/cluster/Inline.cc new file mode 100644 index 00000000..a4a23d03 --- /dev/null +++ b/iocore/cluster/Inline.cc @@ -0,0 +1,31 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Inline Functions as globals for users using the public interface + * + */ +#define TS_INLINE +#define INLINE_CC + +#include "P_Cluster.h" diff --git a/iocore/cluster/Makefile.am b/iocore/cluster/Makefile.am new file mode 100644 index 00000000..394c761c --- /dev/null +++ b/iocore/cluster/Makefile.am @@ -0,0 +1,57 @@ +# Makefile.am for the traffic/iocore/cluster hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy/http \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/utils + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +noinst_LIBRARIES = libinkcluster.a + +libinkcluster_a_SOURCES = \ + ClusterAPI.cc \ + ClusterCache.cc \ + ClusterConfig.cc \ + ClusterHandler.cc \ + ClusterHandlerBase.cc \ + ClusterHash.cc \ + ClusterLib.cc \ + ClusterLoadMonitor.cc \ + ClusterMachine.cc \ + ClusterProcessor.cc \ + ClusterRPC.cc \ + ClusterVConnection.cc \ + P_Cluster.h \ + P_ClusterCache.h \ + P_ClusterCacheInternal.h \ + P_ClusterHandler.h \ + P_ClusterInline.h \ + P_ClusterInternal.h \ + P_ClusterLib.h \ + P_ClusterLoadMonitor.h \ + P_ClusterMachine.h \ + P_TimeTrace.h \ + Inline.cc + diff --git a/iocore/cluster/Makefile.in b/iocore/cluster/Makefile.in new file mode 100644 index 00000000..3834bb41 --- /dev/null +++ b/iocore/cluster/Makefile.in @@ -0,0 +1,743 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/cluster hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = iocore/cluster +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinkcluster_a_AR = $(AR) $(ARFLAGS) +libinkcluster_a_LIBADD = +am_libinkcluster_a_OBJECTS = ClusterAPI.$(OBJEXT) \ + ClusterCache.$(OBJEXT) ClusterConfig.$(OBJEXT) \ + ClusterHandler.$(OBJEXT) ClusterHandlerBase.$(OBJEXT) \ + ClusterHash.$(OBJEXT) ClusterLib.$(OBJEXT) \ + ClusterLoadMonitor.$(OBJEXT) ClusterMachine.$(OBJEXT) \ + ClusterProcessor.$(OBJEXT) ClusterRPC.$(OBJEXT) \ + ClusterVConnection.$(OBJEXT) Inline.$(OBJEXT) +libinkcluster_a_OBJECTS = $(am_libinkcluster_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinkcluster_a_SOURCES) +DIST_SOURCES = $(libinkcluster_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy/http \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/utils + +noinst_LIBRARIES = libinkcluster.a +libinkcluster_a_SOURCES = \ + ClusterAPI.cc \ + ClusterCache.cc \ + ClusterConfig.cc \ + ClusterHandler.cc \ + ClusterHandlerBase.cc \ + ClusterHash.cc \ + ClusterLib.cc \ + ClusterLoadMonitor.cc \ + ClusterMachine.cc \ + ClusterProcessor.cc \ + ClusterRPC.cc \ + ClusterVConnection.cc \ + P_Cluster.h \ + P_ClusterCache.h \ + P_ClusterCacheInternal.h \ + P_ClusterHandler.h \ + P_ClusterInline.h \ + P_ClusterInternal.h \ + P_ClusterLib.h \ + P_ClusterLoadMonitor.h \ + P_ClusterMachine.h \ + P_TimeTrace.h \ + Inline.cc + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/cluster/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/cluster/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinkcluster.a: $(libinkcluster_a_OBJECTS) $(libinkcluster_a_DEPENDENCIES) + -rm -f libinkcluster.a + $(libinkcluster_a_AR) libinkcluster.a $(libinkcluster_a_OBJECTS) $(libinkcluster_a_LIBADD) + $(RANLIB) libinkcluster.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterAPI.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterCache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterConfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterHandler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterHandlerBase.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterHash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterLib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterLoadMonitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterMachine.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterProcessor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterRPC.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClusterVConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/cluster/P_Cluster.h b/iocore/cluster/P_Cluster.h new file mode 100644 index 00000000..7c42a951 --- /dev/null +++ b/iocore/cluster/P_Cluster.h @@ -0,0 +1,144 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_CLUSTER_H__ +#define _P_CLUSTER_H__ + +#ifndef INLINE_CC +#undef TS_INLINE +#define TS_INLINE inline +#endif + +#include "libts.h" +#include "P_EventSystem.h" +#include "I_RecProcess.h" +#include "P_Net.h" +#include "P_Cache.h" + +#ifdef HTTP_CACHE +#include "MIME.h" +#include "HTTP.h" +// #include "HttpTransactCache.h" +#endif + +#include "P_ClusterMachine.h" +#include "P_ClusterCache.h" +#include "P_ClusterCacheInternal.h" +#include "P_ClusterInternal.h" +#include "P_ClusterHandler.h" +#include "P_ClusterInline.h" +#include "P_ClusterLib.h" +#include "P_ClusterLoadMonitor.h" +#include "P_TimeTrace.h" + + +#define ECLUSTER_NO_VC (CLUSTER_ERRNO+0) +#define ECLUSTER_NO_MACHINE (CLUSTER_ERRNO+1) +#define ECLUSTER_OP_TIMEOUT (CLUSTER_ERRNO+2) +#define ECLUSTER_ORB_DATA_READ (CLUSTER_ERRNO+3) +#define ECLUSTER_ORB_EIO (CLUSTER_ERRNO+4) +#define ECLUSTER_CHANNEL_INUSE (CLUSTER_ERRNO+5) +#define ECLUSTER_NOMORE_CHANNELS (CLUSTER_ERRNO+6) + +int init_clusterprocessor(void); +enum +{ + CLUSTER_CONNECTIONS_OPEN_STAT, + CLUSTER_CONNECTIONS_OPENNED_STAT, + CLUSTER_CON_TOTAL_TIME_STAT, + CLUSTER_CTRL_MSGS_SENT_STAT, + CLUSTER_SLOW_CTRL_MSGS_SENT_STAT, + CLUSTER_CTRL_MSGS_RECVD_STAT, + CLUSTER_SLOW_CTRL_MSGS_RECVD_STAT, + CLUSTER_CTRL_MSGS_SEND_TIME_STAT, + CLUSTER_CTRL_MSGS_RECV_TIME_STAT, + CLUSTER_READ_BYTES_STAT, + CLUSTER_WRITE_BYTES_STAT, + CLUSTER_OP_DELAYED_FOR_LOCK_STAT, + CLUSTER_CONNECTIONS_LOCKED_STAT, + CLUSTER_CONNECTIONS_BUMPED_STAT, + CLUSTER_NODES_STAT, + CLUSTER_NET_BACKUP_STAT, + CLUSTER_MACHINES_ALLOCATED_STAT, + CLUSTER_MACHINES_FREED_STAT, + CLUSTER_CONFIGURATION_CHANGES_STAT, + CLUSTER_DELAYED_READS_STAT, + CLUSTER_BYTE_BANK_USED_STAT, + CLUSTER_ALLOC_DATA_NEWS_STAT, + CLUSTER_WRITE_BB_MALLOCS_STAT, + CLUSTER_PARTIAL_READS_STAT, + CLUSTER_PARTIAL_WRITES_STAT, + CLUSTER_CACHE_OUTSTANDING_STAT, + CLUSTER_REMOTE_OP_TIMEOUTS_STAT, + CLUSTER_REMOTE_OP_REPLY_TIMEOUTS_STAT, + CLUSTER_CHAN_INUSE_STAT, + CLUSTER_OPEN_DELAYS_STAT, + CLUSTER_OPEN_DELAY_TIME_STAT, + CLUSTER_CACHE_CALLBACKS_STAT, + CLUSTER_CACHE_CALLBACK_TIME_STAT, + CLUSTER_THREAD_STEAL_EXPIRES_STAT, + CLUSTER_RDMSG_ASSEMBLE_TIME_STAT, + CLUSTER_PING_TIME_STAT, + cluster_setdata_no_CLUSTERVC_STAT, + CLUSTER_SETDATA_NO_TUNNEL_STAT, + CLUSTER_SETDATA_NO_CACHEVC_STAT, + cluster_setdata_no_CLUSTER_STAT, + CLUSTER_VC_WRITE_STALL_STAT, + CLUSTER_NO_REMOTE_SPACE_STAT, + CLUSTER_LEVEL1_BANK_STAT, + CLUSTER_MULTILEVEL_BANK_STAT, + CLUSTER_VC_CACHE_INSERT_LOCK_MISSES_STAT, + CLUSTER_VC_CACHE_INSERTS_STAT, + CLUSTER_VC_CACHE_LOOKUP_LOCK_MISSES_STAT, + CLUSTER_VC_CACHE_LOOKUP_HITS_STAT, + CLUSTER_VC_CACHE_LOOKUP_MISSES_STAT, + CLUSTER_VC_CACHE_SCANS_STAT, + CLUSTER_VC_CACHE_SCAN_LOCK_MISSES_STAT, + CLUSTER_VC_CACHE_PURGES_STAT, + CLUSTER_WRITE_LOCK_MISSES_STAT, + CLUSTER_CACHE_RMT_CALLBACK_TIME_STAT, + CLUSTER_CACHE_LKRMT_CALLBACK_TIME_STAT, + CLUSTER_LOCAL_CONNECTION_TIME_STAT, + CLUSTER_REMOTE_CONNECTION_TIME_STAT, + CLUSTER_SETDATA_NO_CLUSTERVC_STAT, + CLUSTER_SETDATA_NO_CLUSTER_STAT, + cluster_stat_count +}; + +extern RecRawStatBlock *cluster_rsb; +#define CLUSTER_INCREMENT_DYN_STAT(x) \ + RecIncrRawStat(cluster_rsb, mutex->thread_holding, (int) x, 1); +#define CLUSTER_DECREMENT_DYN_STAT(x) \ + RecIncrRawStat(cluster_rsb, mutex->thread_holding, (int) x, -1); +#define CLUSTER_SUM_DYN_STAT(x, y) \ + RecIncrRawStat(cluster_rsb, mutex->thread_holding, (int) x, (int) y); +#define CLUSTER_SUM_GLOBAL_DYN_STAT(x, y) \ + RecIncrGlobalRawStatSum(cluster_rsb,x,y) +#define CLUSTER_CLEAR_DYN_STAT(x) \ +do { \ + RecSetRawStatSum(cluster_rsb, x, 0); \ + RecSetRawStatCount(cluster_rsb, x, 0); \ +} while (0); + + +#endif diff --git a/iocore/cluster/P_ClusterCache.h b/iocore/cluster/P_ClusterCache.h new file mode 100644 index 00000000..952b83e4 --- /dev/null +++ b/iocore/cluster/P_ClusterCache.h @@ -0,0 +1,1170 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Cluster.h + + +****************************************************************************/ + +#ifndef _P_Cluster_Cache_h +#define _P_Cluster_Cache_h + +//***************************************************************************** +// Initially derived from Cluster.h "1.77.2.11 1999/01/21 03:24:10" +//***************************************************************************** + +/****************************************************************************/ +// #define LOCAL_CLUSTER_TEST_MODE 1 +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// Set the above #define to enable local clustering. "Local clustering" +// is a test only mode where all cluster nodes reside on the same host. +// +// Configuration notes: +// - For "cluster.config" entries, always use "127.0.0.1" as the IP +// address and select a host unique cluster port. +// +// Restrictions: +// 1) Does not work with the manager. You must only run with the server +// and hand configure "cluster.config". +// 2) Currently, this has only been tested in a two node configuration. +// +/****************************************************************************/ + +#include "P_ClusterMachine.h" + +// +// Cluster Processor +// +// - monitors the status of the cluster +// - provides communication between machines in the cluster +// - provides callbacks to other processors when the cluster configuration +// changes +// +#define CLUSTER_MAJOR_VERSION 3 +#define CLUSTER_MINOR_VERSION 0 + +// Lowest supported major/minor cluster version +#define MIN_CLUSTER_MAJOR_VERSION CLUSTER_MAJOR_VERSION +#define MIN_CLUSTER_MINOR_VERSION CLUSTER_MINOR_VERSION + + +#define DEFAULT_CLUSTER_PORT_NUMBER 0 +#define DEFAULT_CLUSTER_HOST "" + +#define MAX_CLUSTER_SEND_LENGTH INT_MAX + +#define CLUSTER_MAX_MACHINES 256 +// less than 1% disparity at 255 machines, 32707 is prime less than 2^15 +#define CLUSTER_HASH_TABLE_SIZE 32707 + +// after timeout the configuration is "dead" +#define CLUSTER_CONFIGURATION_TIMEOUT HRTIME_DAY +// after zombie the configuration is deleted +#define CLUSTER_CONFIGURATION_ZOMBIE (HRTIME_DAY*2) + + +// the number of configurations into the past we probe for data +// one allows a new machine to come into or fall out of the +// cluster without loss of data. If the data is redistributed within +// one day, no data will be lost. +#define CONFIGURATION_HISTORY_PROBE_DEPTH 1 + + +// move these to a central event definition file (Event.h) +#define CLUSTER_EVENT_CHANGE (CLUSTER_EVENT_EVENTS_START) +#define CLUSTER_EVENT_CONFIGURATION (CLUSTER_EVENT_EVENTS_START+1) +#define CLUSTER_EVENT_OPEN (CLUSTER_EVENT_EVENTS_START+2) +#define CLUSTER_EVENT_OPEN_EXISTS (CLUSTER_EVENT_EVENTS_START+3) +#define CLUSTER_EVENT_OPEN_FAILED (CLUSTER_EVENT_EVENTS_START+4) + +// internal event code +#define CLUSTER_EVENT_STEAL_THREAD (CLUSTER_EVENT_EVENTS_START+50) + +////////////////////////////////////////////////////////////// +// Miscellaneous byte swap routines +////////////////////////////////////////////////////////////// +inline void +swap16(uint16_t * d) +{ + unsigned char *p = (unsigned char *) d; + *d = ((p[1] << 8) | p[0]); +} + +inline uint16_t +swap16(uint16_t d) +{ + swap16(&d); + return d; +} + +inline void +swap32(uint32_t * d) +{ + unsigned char *p = (unsigned char *) d; + *d = ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); +} + +inline uint32_t +swap32(uint32_t d) +{ + swap32(&d); + return d; +} + +inline void +swap64(uint64_t * d) +{ + unsigned char *p = (unsigned char *) d; + *d = (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48) | + ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32) | + ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16) | ((uint64_t) p[1] << 8) | (uint64_t) p[0]); +} + +inline uint64_t +swap64(uint64_t d) +{ + swap64(&d); + return d; +} + +////////////////////////////////////////////////////////////// + +struct ClusterConfiguration +{ + int n_machines; + ClusterMachine *machines[CLUSTER_MAX_MACHINES]; + + ClusterMachine *machine_hash(unsigned int hash_value) + { + return machines[hash_table[hash_value % CLUSTER_HASH_TABLE_SIZE]]; + } + + ClusterMachine *find(unsigned int ip, int port = 0) { + for (int i = 0; i < n_machines; i++) + if (ip == machines[i]->ip && (!port || !machines[i]->cluster_port || machines[i]->cluster_port == port)) + return machines[i]; + return NULL; + } + + // + // Private + // + ClusterConfiguration(); + unsigned char hash_table[CLUSTER_HASH_TABLE_SIZE]; + ink_hrtime changed; + SLINK(ClusterConfiguration, link); +}; + +inline bool +machine_in_vector(ClusterMachine * m, ClusterMachine ** mm, int len) +{ + for (int i = 0; i < len; i++) + if (m == mm[i]) + return true; + return false; +} + +// +// Return a machine list based on the given hash which is ordered from +// now to the past. Returned list contains no duplicates and depth_list[0] +// entry (current configuration) is always valid. Entries following +// depth_list[0] are considered online. +// Returns 0 on Success else non-zero on error. +// +int +cluster_machine_depth_list(unsigned int hash, ClusterMachine ** depth_list, + int depth_list_size = (CONFIGURATION_HISTORY_PROBE_DEPTH + 1)); + +// +// Returns either a machine or NULL. +// Finds a machine starting at probe_depth going up to +// CONFIGURATION_HISTORY_PROBE_DEPTH +// which is up, not the current machine and has not yet been probed. +// Updates: probe_depth and past_probes. +// +inkcoreapi ClusterMachine *cluster_machine_at_depth(unsigned int hash, int *probe_depth = NULL, + ClusterMachine ** past_probes = NULL); + +// +// Cluster +// A cluster of machines which act as a single cache. +// +struct Cluster +{ + // + // Public Interface + // + + // + // Cluster Hash Function + // + + // Takes a hash value to a machine. The hash function has the following + // properties: + // 1 - it divides input domain into the output range evenly (within 1%) + // 2 - it tends to produce the same Machine for the same hash_value's + // for different configurations + // 3 - it produces the hash same function for a given configuration of + // machines independent of the order they were added or removed + // from the cluster. (it is a pure function of the configuration) + // Thread-safe + // + ClusterMachine *machine_hash(unsigned int hash_value) + { + return current_configuration()->machine_hash(hash_value); + } + + // + // Cluster Configuration + // + + // Register callback for a cluster configuration change. + // calls cont->handleEvent(EVENT_CLUSTER_CHANGE); + // Thread-safe + // + void cluster_change_callback(Continuation * cont); + + // Return the current configuration + // Thread-safe + // + ClusterConfiguration *current_configuration() + { + return configurations.head; + } + + // Return the previous configuration. + // Use from within the cluster_change_callback. + // Thread-safe + // + ClusterConfiguration *previous_configuration() + { + return configurations.head->link.next; + } + + // + // Private + // + // The configurations are updated only in the thread which is + // accepting cluster connections. + // + SLL configurations; + + Cluster(); +}; + +// +// ClusterVCToken +// An token passed between nodes to represent a virtualized connection. +// (see ClusterProcessor::alloc_remote() and attach_remote() below) +// +struct ClusterVCToken +{ + // + // Marshal this data to send the token across the cluster + // + uint32_t ip_created; + uint32_t sequence_number; + + bool is_clear() + { + return !ip_created; + } + void clear() + { + ip_created = 0; + sequence_number = 0; + } + + ClusterVCToken(unsigned int aip = 0, unsigned int aseq = 0) +: ip_created(aip), sequence_number(aseq) { + } + // + // Private + // + void alloc(); + + inline void SwapBytes() + { + swap32(&sequence_number); + } +}; + +// +// ClusterFunctionPtr +// A pointer to a procedure which can be invoked accross the cluster. +// This must be registered. +// +typedef void ClusterFunction(ClusterMachine * from, void *data, int len); +typedef ClusterFunction *ClusterFunctionPtr; + +struct ClusterVConnectionBase; + +struct ClusterVConnState +{ + // + // Private + // + volatile int enabled; + // multiples of XXX_PERIOD, high = less often + int priority; + VIO vio; + void *queue; + int ifd; + Event *delay_timeout; + Link link; + + // void enqueue(void * q, ClusterVConnection * vc); + ClusterVConnState(); +}; + +struct ClusterVConnectionBase: public CacheVConnection +{ + // + // Initiate an IO operation. + // "data" is unused. + // Only one READ and one WRITE may be active at one time. + // THREAD-SAFE, may be called when not handling an event from + // the ClusterVConnectionBase, or the ClusterVConnectionBase + // creation callback. + // + + virtual VIO *do_io_read(Continuation * c, int64_t nbytes, MIOBuffer * buf); + virtual VIO *do_io_write(Continuation * c, int64_t nbytes, IOBufferReader * buf, bool owner = false); + virtual void do_io_shutdown(ShutdownHowTo_t howto) + { + (void) howto; + ink_assert(!"shutdown of cluster connection"); + } + virtual void do_io_close(int lerrno = -1); + virtual VIO* do_io_pread(Continuation*, int64_t, MIOBuffer*, int64_t); + + // Set the timeouts associated with this connection. + // active_timeout is for the total elasped time of the connection. + // inactivity_timeout is the elapsed time *while an operation was + // enabled* during which the connection was unable to sink/provide data. + // calling these functions repeatedly resets the timeout. + // NOT THREAD-SAFE, may only be called when handing an event from this + // ClusterVConnectionBase, or the ClusterVConnectionBase + // creation callback. + // + void set_active_timeout(ink_hrtime timeout_in); + void set_inactivity_timeout(ink_hrtime timeout_in); + void cancel_active_timeout(); + void cancel_inactivity_timeout(); + + ClusterVConnectionBase(); + +#ifdef DEBUG + // Class static data + static int enable_debug_trace; +#endif + Action action_; + EThread *thread; + volatile int closed; + ClusterVConnState read; + ClusterVConnState write; + LINKM(ClusterVConnectionBase, read, link) + LINKM(ClusterVConnectionBase, write, link) + ink_hrtime inactivity_timeout_in; + ink_hrtime active_timeout_in; + Event *inactivity_timeout; + Event *active_timeout; + + virtual void reenable(VIO *); + virtual void reenable_re(VIO *); +}; + +inline void +ClusterVConnectionBase::set_active_timeout(ink_hrtime timeout) +{ + active_timeout_in = timeout; + if (active_timeout) { + ink_assert(!active_timeout->cancelled); + if (active_timeout->ethread == this_ethread()) + active_timeout->schedule_in(timeout); + else { + active_timeout->cancel(this); + active_timeout = thread->schedule_in(this, timeout); + } + } else { + if (thread) { + active_timeout = thread->schedule_in(this, timeout); + } + } +} + +inline void +ClusterVConnectionBase::set_inactivity_timeout(ink_hrtime timeout) +{ + inactivity_timeout_in = timeout; + if (inactivity_timeout) { + ink_assert(!inactivity_timeout->cancelled); + if (inactivity_timeout->ethread == this_ethread()) + inactivity_timeout->schedule_in(timeout); + else { + inactivity_timeout->cancel(this); + inactivity_timeout = thread->schedule_in(this, timeout); + } + } else { + if (thread) { + inactivity_timeout = thread->schedule_in(this, timeout); + } + } +} + +inline void +ClusterVConnectionBase::cancel_active_timeout() +{ + if (active_timeout) { + active_timeout->cancel(this); + active_timeout = NULL; + active_timeout_in = 0; + } +} + +inline void +ClusterVConnectionBase::cancel_inactivity_timeout() +{ + if (inactivity_timeout) { + inactivity_timeout->cancel(this); + inactivity_timeout = NULL; + inactivity_timeout_in = 0; + } +} + +// Data debt owed to VC which is deferred due to lock miss +class ByteBankDescriptor +{ +public: + ByteBankDescriptor() + { + } + IOBufferBlock *get_block() + { + return block; + } + + static ByteBankDescriptor *ByteBankDescriptor_alloc(IOBufferBlock *); + static void ByteBankDescriptor_free(ByteBankDescriptor *); + +public: + LINK(ByteBankDescriptor, link); + +private: + Ptr block; // holder of bank bytes +}; + +// +// ClusterVConnection +// +struct ClusterVConnection: public ClusterVConnectionBase +{ + // + // Public Interface (included from ClusterVConnectionBase) + // + // Thread-safe (see Net.h for details) + // + // virtual VIO * do_io( + // int op, + // Continuation * c = NULL, + // int nbytes = INT64_MAX, + // MIOBuffer * buf = 0, + // int whence = SEEK_CUR); + // + // NOT Thread-safe (see Net.h for details) + // + // void set_active_timeout(ink_hrtime timeout_in); + // void set_inactivity_timeout(ink_hrtime timeout_in); + + // + // Private + // + + int startEvent(int event, Event * e); + int mainEvent(int event, Event * e); + + // 0 on success -1 on failure + int start(EThread * t); // New connect protocol + + ClusterVConnection(int is_new_connect_read = 0); + ~ClusterVConnection(); + void free(); // Destructor actions (we are using ClassAllocator) + + virtual void do_io_close(int lerrno = -1); + + ClusterMachine *machine; + // + // Read Channel: (new_connect_read == true) + // - open_local() caller is reader + // - connect_local() caller is writer + // + // Write Channel: (new_connect_read == false) + // - open_local() caller is writer + // - connect_local() caller is reader + // + int new_connect_read; // Data flow direction wrt origin node + int remote_free; + int last_local_free; + int channel; + ClusterVCToken token; + volatile int close_disabled; + volatile int remote_closed; + volatile int remote_close_disabled; + volatile int remote_lerrno; + int was_closed(); + void allow_close(); + void disable_close(); + int was_remote_closed(); + void allow_remote_close(); + bool schedule_write(); + void set_type(int); + ink_hrtime start_time; + ink_hrtime last_activity_time; + Queue byte_bank_q; // done awaiting completion + int n_set_data_msgs; // # pending set_data() msgs on VC + int n_recv_set_data_msgs; // # set_data() msgs received on VC + volatile int pending_remote_fill; // Remote fill pending on connection + Ptr read_block; // Hold current data for open read + bool have_all_data; // All data in read_block + int initial_data_bytes; // bytes in open_read buffer + Ptr remote_write_block; // Write side data for remote fill + void *current_cont; // Track current continuation (debug) + +#define CLUSTER_IOV_NOT_OPEN -2 +#define CLUSTER_IOV_NONE -1 + int iov_map; // which iov? + + Ptr read_locked; + Ptr write_locked; + + // Data buffer for unmarshaled objects from remote node. + Ptr marshal_buf; + + // Pending write data + Ptr write_list; + IOBufferBlock *write_list_tail; + int write_list_bytes; + int write_bytes_in_transit; + + CacheHTTPInfo alternate; + time_t time_pin; + int disk_io_priority; + void set_remote_fill_action(Action *); + + // For VC(s) established via OPEN_READ, we are passed a CacheHTTPInfo + // in the reply. + virtual bool get_data(int id, void *data); // backward compatibility + virtual void get_http_info(CacheHTTPInfo **); + virtual int64_t get_object_size(); + + // For VC(s) established via the HTTP version of OPEN_WRITE, additional + // data for the VC is passed in a second message. This additional + // data has a lifetime equal to the cache VC + virtual void set_http_info(CacheHTTPInfo *); + + virtual bool set_pin_in_cache(time_t time_pin); + virtual time_t get_pin_in_cache(); + virtual bool set_disk_io_priority(int priority); + virtual int get_disk_io_priority(); + bool is_ram_cache_hit() + { + return 0; + } + virtual int get_header(void **ptr, int *len); + virtual int set_header(void *ptr, int len); + virtual int get_single_data(void **ptr, int *len); +}; + +// +// Cluster operation options +// +#define CLUSTER_OPT_STEAL 0x0001 // allow thread stealing +#define CLUSTER_OPT_IMMEDIATE 0x0002 // require immediate response +#define CLUSTER_OPT_ALLOW_IMMEDIATE 0x0004 // allow immediate response +#define CLUSTER_OPT_DELAY 0x0008 // require delayed response +#define CLUSTER_OPT_CONN_READ 0x0010 // new conn read +#define CLUSTER_OPT_CONN_WRITE 0x0020 // new conn write +#define CLUSTER_OPT_DATA_IS_OCONTROL 0x0040 // data in OutgoingControl +#define CLUSTER_FUNCTION_MALLOCED -1 + +struct ClusterRemoteDataHeader +{ + int32_t cluster_function; +}; +// +// ClusterProcessor +// +class ClusterAccept; + +struct ClusterProcessor +{ + // + // Public Interface + // + + // Invoke a function on a remote node + // marshall your own data, provide a continuation for timeouts and errors + // + // Options: CLUSTER_OPT_DELAY, CLUSTER_OPT_STEAL, CLUSTER_OPT_DATA_IS_OCONTROL + // Returns: 1 for immediate send, 0 for delayed, -1 for error + + int invoke_remote(ClusterMachine * m, int cluster_fn_index, void *data, int len, int options = CLUSTER_OPT_STEAL); + + int invoke_remote_data(ClusterMachine * m, int cluster_fn_index, + void *data, int data_len, + IOBufferBlock * buf, + int logical_channel, ClusterVCToken * token, + void (*bufdata_free) (void *), void *bufdata_free_arg, int options = CLUSTER_OPT_STEAL); + + // Pass the data in as a malloc'ed block to be freed by callee + int invoke_remote_malloced(ClusterMachine * m, ClusterRemoteDataHeader * data, int len /* including header */ ) + { + return invoke_remote(m, CLUSTER_FUNCTION_MALLOCED, data, len); + } + void free_remote_data(char *data, int len); + + // Allocate the local side of a remote VConnection. + // returns a token which can be passed to the remote side + // through an existing link and passed to attach_remoteVC() + // if CLUSTER_OPT_IMMEDIATE is set, CLUSTER_DELAYED_OPEN will not be returned + // + // Options: CLUSTER_OPT_IMMEDIATE, CLUSTER_OPT_ALLOW_IMMEDIATE + // Returns: pointer for CLUSTER_OPT_IMMEDIATE + // or CLUSTER_DELAYED_OPEN on success, + // NULL on failure + // calls: cont->handleEvent( CLUSTER_EVENT_OPEN, ClusterVConnection *) + // on delayed success. + // + // NOTE: the CLUSTER_EVENT_OPEN may be called before "open/connect" returns + +#define CLUSTER_DELAYED_OPEN ((ClusterVConnection*)-1) +#define CLUSTER_NODE_DOWN ((ClusterVConnection*)-2) + ClusterVConnection *open_local(Continuation * cont, ClusterMachine * m, ClusterVCToken & token, int options = 0); + + // Get the other side of a remote VConnection which was previously + // allocated with open. + // + // Options: CLUSTER_OPT_IMMEDIATE, CLUSTER_OPT_ALLOW_IMMEDIATE + // return a pointer or CLUSTER_DELAYED_OPEN success, NULL on failure + // + ClusterVConnection *connect_local(Continuation * cont, ClusterVCToken * token, int channel, int options = 0); + inkcoreapi bool disable_remote_cluster_ops(ClusterMachine *); + + // + // Processor interface + // + virtual int init(); + virtual int start(); + + ClusterProcessor(); + virtual ~ ClusterProcessor(); + + // + // Private + // + ClusterAccept *accept_handler; + Cluster *this_cluster; + // Connect to a new cluster machine + void connect(char *hostname); + void connect(unsigned int ip, int port = 0, bool delay = false); + // send the list of known machines to new machine + void send_machine_list(ClusterMachine * m); + void compute_cluster_mode(); + // Internal invoke_remote interface + int internal_invoke_remote(ClusterMachine * m, int cluster_fn, void *data, int len, int options, void *cmsg); +}; + +inkcoreapi extern ClusterProcessor clusterProcessor; + +inline Cluster * +this_cluster() +{ + return clusterProcessor.this_cluster; +} + +// +// Set up a thread to receive events from the ClusterProcessor +// This function should be called for all threads created to +// accept such events by the EventProcesor. +// +void initialize_thread_for_cluster(EThread * thread); + +// +// ClusterFunction Registry +// +// Declare an instance of this class here to register +// a function. In order to allow older versions of software +// to co-exist with newer versions, always add to the bottom +// of the list. +// + +extern ClusterFunction *ptest_ClusterFunction; + +extern ClusterFunction test_ClusterFunction; +extern ClusterFunction ping_ClusterFunction; +extern ClusterFunction ping_reply_ClusterFunction; +extern ClusterFunction machine_list_ClusterFunction; +extern ClusterFunction close_channel_ClusterFunction; +extern ClusterFunction get_hostinfo_ClusterFunction; +extern ClusterFunction put_hostinfo_ClusterFunction; +extern ClusterFunction cache_lookup_ClusterFunction; +extern ClusterFunction cache_op_ClusterFunction; +extern ClusterFunction cache_op_malloc_ClusterFunction; +extern ClusterFunction cache_op_result_ClusterFunction; +extern ClusterFunction set_channel_data_ClusterFunction; +extern ClusterFunction post_setchan_send_ClusterFunction; +extern ClusterFunction set_channel_pin_ClusterFunction; +extern ClusterFunction post_setchan_pin_ClusterFunction; +extern ClusterFunction set_channel_priority_ClusterFunction; +extern ClusterFunction post_setchan_priority_ClusterFunction; +extern ClusterFunction default_api_ClusterFunction; + +struct ClusterFunctionDescriptor +{ + bool fMalloced; // the function will free the data + bool ClusterFunc; // Process incoming message only + // in ET_CLUSTER thread. + int q_priority; // lower is higher priority + ClusterFunctionPtr pfn; + ClusterFunctionPtr post_pfn; // msg queue/send callout +}; + +#define CLUSTER_CMSG_QUEUES 2 +#define CMSG_MAX_PRI 0 +#define CMSG_LOW_PRI (CLUSTER_CMSG_QUEUES-1) + +#ifndef DEFINE_CLUSTER_FUNCTIONS +extern +#endif +ClusterFunctionDescriptor clusterFunction[] +#ifdef DEFINE_CLUSTER_FUNCTIONS + = { + {false, true, CMSG_LOW_PRI, test_ClusterFunction, 0}, + {false, true, CMSG_LOW_PRI, ping_ClusterFunction, 0}, + {false, true, CMSG_LOW_PRI, ping_reply_ClusterFunction, 0}, + {false, true, CMSG_LOW_PRI, machine_list_ClusterFunction, 0}, + {false, true, CMSG_LOW_PRI, close_channel_ClusterFunction, 0}, + {false, false, CMSG_LOW_PRI, + get_hostinfo_ClusterFunction, 0}, // in HostDB.cc + {false, false, CMSG_LOW_PRI, + put_hostinfo_ClusterFunction, 0}, // in HostDB.cc + {false, true, CMSG_LOW_PRI, + cache_lookup_ClusterFunction, 0}, // in CacheCont.cc + {true, true, CMSG_LOW_PRI, cache_op_malloc_ClusterFunction, 0}, + {false, true, CMSG_LOW_PRI, cache_op_ClusterFunction, 0}, + {false, false, CMSG_LOW_PRI, cache_op_result_ClusterFunction, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, // OBSOLETE + {false, false, CMSG_LOW_PRI, 0, 0}, // OBSOLETE + {false, false, CMSG_LOW_PRI, 0, 0}, // OBSOLETE + {false, true, CMSG_MAX_PRI, set_channel_data_ClusterFunction, + post_setchan_send_ClusterFunction}, + {false, true, CMSG_MAX_PRI, set_channel_pin_ClusterFunction, + post_setchan_pin_ClusterFunction}, + {false, true, CMSG_MAX_PRI, set_channel_priority_ClusterFunction, + post_setchan_priority_ClusterFunction}, + /******************************************** + * RESERVED for future cluster internal use * + ********************************************/ + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + {false, false, CMSG_LOW_PRI, 0, 0}, + + /********************************************* + * RESERVED for Cluster RPC API use * + *********************************************/ +#ifdef NON_MODULAR + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0}, + {true, false, CMSG_LOW_PRI, default_api_ClusterFunction, 0} +#endif + // ********** ADD NEW ENTRIES ABOVE THIS LINE ************ +} +#endif + +; +extern int SIZE_clusterFunction; // clusterFunction[] entries + +////////////////////////////////////////////////////////////// +// Map from Cluster Function code to send queue priority +////////////////////////////////////////////////////////////// +inline int +ClusterFuncToQpri(int cluster_func) +{ + if (cluster_func < 0) { + return CMSG_LOW_PRI; + } else { + return clusterFunction[cluster_func].q_priority; + } +} + +// +// This table had better match the above list +// +#define TEST_CLUSTER_FUNCTION 0 +#define PING_CLUSTER_FUNCTION 1 +#define PING_REPLY_CLUSTER_FUNCTION 2 +#define MACHINE_LIST_CLUSTER_FUNCTION 3 +#define CLOSE_CHANNEL_CLUSTER_FUNCTION 4 +#define GET_HOSTINFO_CLUSTER_FUNCTION 5 +#define PUT_HOSTINFO_CLUSTER_FUNCTION 6 +#define CACHE_LOOKUP_CLUSTER_FUNCTION 7 +#define CACHE_OP_MALLOCED_CLUSTER_FUNCTION 8 +#define CACHE_OP_CLUSTER_FUNCTION 9 +#define CACHE_OP_RESULT_CLUSTER_FUNCTION 10 +#define SET_CHANNEL_DATA_CLUSTER_FUNCTION 14 +#define SET_CHANNEL_PIN_CLUSTER_FUNCTION 15 +#define SET_CHANNEL_PRIORITY_CLUSTER_FUNCTION 16 + +/******************************************** + * RESERVED for future cluster internal use * + ********************************************/ +#define INTERNAL_RESERVED1_CLUSTER_FUNCTION 17 +#define INTERNAL_RESERVED2_CLUSTER_FUNCTION 18 +#define INTERNAL_RESERVED3_CLUSTER_FUNCTION 19 +#define INTERNAL_RESERVED4_CLUSTER_FUNCTION 20 +#define INTERNAL_RESERVED5_CLUSTER_FUNCTION 21 +#define INTERNAL_RESERVED6_CLUSTER_FUNCTION 22 +#define INTERNAL_RESERVED7_CLUSTER_FUNCTION 23 +#define INTERNAL_RESERVED8_CLUSTER_FUNCTION 24 +#define INTERNAL_RESERVED9_CLUSTER_FUNCTION 25 +#define INTERNAL_RESERVED10_CLUSTER_FUNCTION 26 +#define INTERNAL_RESERVED11_CLUSTER_FUNCTION 27 +#define INTERNAL_RESERVED12_CLUSTER_FUNCTION 28 +#define INTERNAL_RESERVED13_CLUSTER_FUNCTION 29 +#define INTERNAL_RESERVED14_CLUSTER_FUNCTION 30 +#define INTERNAL_RESERVED15_CLUSTER_FUNCTION 31 +#define INTERNAL_RESERVED16_CLUSTER_FUNCTION 32 +#define INTERNAL_RESERVED17_CLUSTER_FUNCTION 33 +#define INTERNAL_RESERVED18_CLUSTER_FUNCTION 34 +#define INTERNAL_RESERVED19_CLUSTER_FUNCTION 35 +#define INTERNAL_RESERVED20_CLUSTER_FUNCTION 36 +#define INTERNAL_RESERVED21_CLUSTER_FUNCTION 37 +#define INTERNAL_RESERVED22_CLUSTER_FUNCTION 38 +#define INTERNAL_RESERVED23_CLUSTER_FUNCTION 39 +#define INTERNAL_RESERVED24_CLUSTER_FUNCTION 40 +#define INTERNAL_RESERVED25_CLUSTER_FUNCTION 41 +#define INTERNAL_RESERVED26_CLUSTER_FUNCTION 42 +#define INTERNAL_RESERVED27_CLUSTER_FUNCTION 43 +#define INTERNAL_RESERVED28_CLUSTER_FUNCTION 44 +#define INTERNAL_RESERVED29_CLUSTER_FUNCTION 45 +#define INTERNAL_RESERVED30_CLUSTER_FUNCTION 46 +#define INTERNAL_RESERVED31_CLUSTER_FUNCTION 47 +#define INTERNAL_RESERVED32_CLUSTER_FUNCTION 48 +#define INTERNAL_RESERVED33_CLUSTER_FUNCTION 49 +#define INTERNAL_RESERVED34_CLUSTER_FUNCTION 50 + +/**************************************************************************** + * Cluster RPC API definitions. * + * * + **************************************************************************** + * Note: All of the following must be kept in sync with INKClusterRPCKey_t * + * definition in ts/ts.h and ts/experimental.h * + ****************************************************************************/ + +/************************************************ + * RESERVED for Wireless Group * + ************************************************/ +#define API_F01_CLUSTER_FUNCTION 51 +#define API_F02_CLUSTER_FUNCTION 52 +#define API_F03_CLUSTER_FUNCTION 53 +#define API_F04_CLUSTER_FUNCTION 54 +#define API_F05_CLUSTER_FUNCTION 55 +#define API_F06_CLUSTER_FUNCTION 56 +#define API_F07_CLUSTER_FUNCTION 57 +#define API_F08_CLUSTER_FUNCTION 58 +#define API_F09_CLUSTER_FUNCTION 59 +#define API_F10_CLUSTER_FUNCTION 60 + +/************************************************ + * RESERVED for future use * + ************************************************/ +#define API_F11_CLUSTER_FUNCTION 61 +#define API_F12_CLUSTER_FUNCTION 62 +#define API_F13_CLUSTER_FUNCTION 63 +#define API_F14_CLUSTER_FUNCTION 64 +#define API_F15_CLUSTER_FUNCTION 65 +#define API_F16_CLUSTER_FUNCTION 66 +#define API_F17_CLUSTER_FUNCTION 67 +#define API_F18_CLUSTER_FUNCTION 68 +#define API_F19_CLUSTER_FUNCTION 69 +#define API_F20_CLUSTER_FUNCTION 70 + +#define API_F21_CLUSTER_FUNCTION 71 +#define API_F22_CLUSTER_FUNCTION 72 +#define API_F23_CLUSTER_FUNCTION 73 +#define API_F24_CLUSTER_FUNCTION 74 +#define API_F25_CLUSTER_FUNCTION 75 +#define API_F26_CLUSTER_FUNCTION 76 +#define API_F27_CLUSTER_FUNCTION 77 +#define API_F28_CLUSTER_FUNCTION 78 +#define API_F29_CLUSTER_FUNCTION 79 +#define API_F30_CLUSTER_FUNCTION 80 + +#define API_STARECT_CLUSTER_FUNCTION API_F01_CLUSTER_FUNCTION +#define API_END_CLUSTER_FUNCTION API_F30_CLUSTER_FUNCTION + +#define UNDEFINED_CLUSTER_FUNCTION 0xFDEFFDEF + +////////////////////////////////////////////// +// Initial cluster connect exchange message +////////////////////////////////////////////// +struct ClusterHelloMessage +{ + uint16_t _NativeByteOrder; + uint16_t _major; + uint16_t _minor; + uint16_t _min_major; + uint16_t _min_minor; +#ifdef LOCAL_CLUSTER_TEST_MODE + int16_t _port; + char _pad[116]; // pad out to 128 bytes +#else + char _pad[118]; // pad out to 128 bytes +#endif + + ClusterHelloMessage():_NativeByteOrder(1) + { + _major = CLUSTER_MAJOR_VERSION; + _minor = CLUSTER_MINOR_VERSION; + _min_major = MIN_CLUSTER_MAJOR_VERSION; + _min_minor = MIN_CLUSTER_MINOR_VERSION; + memset(_pad, '\0', sizeof(_pad)); + } + int NativeByteOrder() + { + return (_NativeByteOrder == 1); + } + void AdjustByteOrder() + { + if (!NativeByteOrder()) { + swap16(&_major); + swap16(&_minor); + swap16(&_min_major); + swap16(&_min_minor); + } + } +}; + +/////////////////////////////////////////////////////////////////// +// Cluster message header definition. +/////////////////////////////////////////////////////////////////// +struct ClusterMessageHeader +{ + uint16_t _InNativeByteOrder; // always non-zero + uint16_t _MsgVersion; // always non-zero + + void _init(uint16_t msg_version) + { + _InNativeByteOrder = 1; + _MsgVersion = msg_version; + } + ClusterMessageHeader():_InNativeByteOrder(0), _MsgVersion(0) + { + } + ClusterMessageHeader(uint16_t msg_version) { + _init(msg_version); + } + int MsgInNativeByteOrder() + { + return (_InNativeByteOrder == 1); + } + int NeedByteSwap() + { + return (_InNativeByteOrder != 1); + } + int GetMsgVersion() + { + if (NeedByteSwap()) { + return swap16(_MsgVersion); + } else { + return _MsgVersion; + } + } +}; + +/////////////////////////////////////////////////////////////////// + +// +// cluster_ping +// +typedef void (*PingReturnFunction) (ClusterMachine *, void *data, int len); + +struct PingMessage:public ClusterMessageHeader +{ + PingReturnFunction fn; // Note: Pointer to a func + char data[1]; // start of data + + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + PING_MESSAGE_VERSION = MAX_VERSION + }; + + PingMessage(uint16_t vers = PING_MESSAGE_VERSION) +: ClusterMessageHeader(vers), fn(NULL) { + data[0] = '\0'; + } + ///////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return PING_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + PingMessage *p = 0; + // Maybe use offsetof here instead. /leif + return (uintptr_t) (&p->data[0]); + } + void init(uint16_t vers = PING_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + } // No action, message is always reflected back + ///////////////////////////////////////////////////////////////////////////// +}; + +inline void +cluster_ping(ClusterMachine * m, PingReturnFunction fn, void *data, int len) +{ + PingMessage *msg = (PingMessage *)alloca(PingMessage::sizeof_fixedlen_msg() + len); + msg->init(); + msg->fn = fn; + memcpy(msg->data, data, len); + clusterProcessor.invoke_remote(m, PING_CLUSTER_FUNCTION, (void *) msg, (msg->sizeof_fixedlen_msg() + len)); +} + +// filled with 0's +extern char channel_dummy_output[DEFAULT_MAX_BUFFER_SIZE]; + +// +// Private (for testing) +// +ClusterConfiguration *configuration_add_machine(ClusterConfiguration * c, ClusterMachine * m); +ClusterConfiguration *configuration_remove_machine(ClusterConfiguration * c, ClusterMachine * m); +extern bool machineClusterHash; +extern bool boundClusterHash; +extern bool randClusterHash; + +void build_cluster_hash_table(ClusterConfiguration *); + +inline void +ClusterVC_enqueue_read(Queue &q, ClusterVConnectionBase * vc) +{ + ClusterVConnState * cs = &vc->read; + ink_assert(!cs->queue); + cs->queue = &q; + q.enqueue(vc); +} + +inline void +ClusterVC_enqueue_write(Queue &q, ClusterVConnectionBase * vc) +{ + ClusterVConnState * cs = &vc->write; + ink_assert(!cs->queue); + cs->queue = &q; + q.enqueue(vc); +} + +inline void +ClusterVC_remove_read(ClusterVConnectionBase * vc) +{ + ClusterVConnState * cs = &vc->read; + ink_assert(cs->queue); + ((Queue *)cs->queue)->remove(vc); + cs->queue = NULL; +} + +inline void +ClusterVC_remove_write(ClusterVConnectionBase * vc) +{ + ClusterVConnState * cs = &vc->write; + ink_assert(cs->queue); + ((Queue *)cs->queue)->remove(vc); + cs->queue = NULL; +} + + +#endif /* _Cluster_h */ diff --git a/iocore/cluster/P_ClusterCacheInternal.h b/iocore/cluster/P_ClusterCacheInternal.h new file mode 100644 index 00000000..937099b4 --- /dev/null +++ b/iocore/cluster/P_ClusterCacheInternal.h @@ -0,0 +1,836 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ClusterCacheInternal.h +****************************************************************************/ + +#ifndef __P_CLUSTERCACHEINTERNAL_H__ +#define __P_CLUSTERCACHEINTERNAL_H__ +#include "P_ClusterCache.h" +#include "I_OneWayTunnel.h" + +// +// Compilation Options +// +#define CACHE_USE_OPEN_VIO 0 // EXPERIMENTAL: not fully tested +#define DO_REPLICATION 0 // EXPERIMENTAL: not fully tested + +// +// Constants +// +#define META_DATA_FAST_ALLOC_LIMIT 1 +#define CACHE_CLUSTER_TIMEOUT HRTIME_MSECONDS(5000) +#define CACHE_RETRY_PERIOD HRTIME_MSECONDS(10) +#define REMOTE_CONNECT_HASH (16 * 1024) + +// +// Macros +// +#define FOLDHASH(_ip,_seq) (_seq % REMOTE_CONNECT_HASH) +#define ALIGN_DOUBLE(_p) ((((uintptr_t) (_p)) + 7) & ~7) +#define ALLOCA_DOUBLE(_sz) ALIGN_DOUBLE(alloca((_sz) + 8)) + + +// +// Testing +// +#define TEST(_x) +//#define TEST(_x) _x + +//#define TTEST(_x) +//fprintf(stderr, _x " at: %d\n", +// ((unsigned int)(ink_get_hrtime()/HRTIME_MSECOND)) % 1000) +#define TTEST(_x) + +//#define TIMEOUT_TEST(_x) _x +#define TIMEOUT_TEST(_x) + +extern int cache_migrate_on_demand; +extern int ET_CLUSTER; +// +// Compile time options. +// +// Only one of PROBE_LOCAL_CACHE_FIRST or PROBE_LOCAL_CACHE_LAST +// should be set. These indicate that the local cache should be +// probed at this point regardless of the dedicated location of the +// object. Note, if the owning machine goes down the local machine +// will be probed anyway. +// +#define PROBE_LOCAL_CACHE_FIRST DO_REPLICATION +#define PROBE_LOCAL_CACHE_LAST false + +// +// This continuation handles all cache cluster traffic, on both +// sides (state machine client and cache server) +// +struct CacheContinuation; +typedef int (CacheContinuation::*CacheContHandler) (int, void *); +struct CacheContinuation:public Continuation +{ + enum + { + MagicNo = 0x92183123 + }; + int magicno; + void *callback_data; + void *callback_data_2; + INK_MD5 url_md5; + Event *timeout; + Action action; + ClusterMachine *target_machine; + int probe_depth; + ClusterMachine *past_probes[CONFIGURATION_HISTORY_PROBE_DEPTH]; + ink_hrtime start_time; + ClusterMachine *from; + VConnection *cache_vc; + bool cache_read; + int result; // return event code + int result_error; // error code associated with event + ClusterVCToken token; + unsigned int seq_number; + uint16_t cfl_flags; // Request flags; see CFL_XXX defines + CacheFragType frag_type; + int nbytes; + unsigned int target_ip; + int request_opcode; + bool local_lookup_only; + bool no_reply_message; + bool request_timeout; // timeout occurred before + // op complete + bool expect_cache_callback; + + // remove_and_delete() specific data + bool use_deferred_callback; + + // open_read/write data + + time_t pin_in_cache; + + // setMsgBufferLen(), allocMsgBuffer() and freeMsgBuffer() data + + Ptr rw_buf_msg; + int rw_buf_msg_len; + + // open data + + ClusterVConnection *read_cluster_vc; + ClusterVConnection *write_cluster_vc; + int cluster_vc_channel; + ClusterVCToken open_local_token; + + // Readahead on open read specific data + + int caller_buf_freebytes; // remote bufsize for + // initial data + VIO *readahead_vio; + IOBufferReader *readahead_reader; + Ptr readahead_data; + bool have_all_data; // all object data in response + + CacheHTTPInfo cache_vc_info; + OneWayTunnel *tunnel; + Ptr tunnel_mutex; + CacheContinuation *tunnel_cont; + bool tunnel_closed; + Action *cache_action; + Event *lookup_open_write_vc_event; + + // Incoming data generated from unmarshaling request/response ops + + Arena ic_arena; + CacheHTTPHdr ic_request; + CacheHTTPHdr ic_response; + CacheLookupHttpConfig *ic_params; + CacheHTTPInfo ic_old_info; + CacheHTTPInfo ic_new_info; + Ptr ic_hostname; + int ic_hostname_len; + + // debugging + int cache_op_ClusterFunction; + + int lookupEvent(int event, void *d); + int probeLookupEvent(int event, void *d); + int remoteOpEvent(int event, Event * e); + int replyLookupEvent(int event, void *d); + int replyOpEvent(int event, VConnection * vc); + int handleReplyEvent(int event, Event * e); + int callbackEvent(int event, Event * e); + int setupVCdataRead(int event, VConnection * vc); + int VCdataRead(int event, VIO * target_vio); + int setupReadWriteVC(int, VConnection *); + ClusterVConnection *lookupOpenWriteVC(); + int lookupOpenWriteVCEvent(int, Event *); + int localVCsetupEvent(int event, ClusterVConnection * vc); + void insert_cache_callback_user(ClusterVConnection *, int, void *); + int insertCallbackEvent(int, Event *); + void callback_user(int result, void *d); + void defer_callback_result(int result, void *d); + int callbackResultEvent(int event, Event * e); + void setupReadBufTunnel(VConnection *, VConnection *); + int tunnelClosedEvent(int event, void *); + int remove_and_delete(int, Event *); + + + inline void setMsgBufferLen(int l, IOBufferData * b = 0) { + ink_assert(rw_buf_msg == 0); + ink_assert(rw_buf_msg_len == 0); + + rw_buf_msg = b; + rw_buf_msg_len = l; + } + + inline int getMsgBufferLen() + { + return rw_buf_msg_len; + } + + inline void allocMsgBuffer() + { + ink_assert(rw_buf_msg == 0); + ink_assert(rw_buf_msg_len); + if (rw_buf_msg_len <= DEFAULT_MAX_BUFFER_SIZE) { + rw_buf_msg = new_IOBufferData(buffer_size_to_index(rw_buf_msg_len, MAX_BUFFER_SIZE_INDEX)); + } else { + rw_buf_msg = new_xmalloc_IOBufferData(xmalloc(rw_buf_msg_len), rw_buf_msg_len); + } + } + + inline char *getMsgBuffer() + { + ink_assert(rw_buf_msg); + return rw_buf_msg->data(); + } + + inline IOBufferData *getMsgBufferIOBData() + { + return rw_buf_msg; + } + + inline void freeMsgBuffer() + { + if (rw_buf_msg) { + rw_buf_msg = 0; + rw_buf_msg_len = 0; + } + } + + inline void free() + { + token.clear(); + + if (cache_vc_info.valid()) { + cache_vc_info.destroy(); + } + // Deallocate unmarshaled data + if (ic_params) { + delete ic_params; + ic_params = 0; + } + if (ic_request.valid()) { + ic_request.clear(); + } + if (ic_response.valid()) { + ic_response.clear(); + } + if (ic_old_info.valid()) { + ic_old_info.destroy(); + } + if (ic_new_info.valid()) { + ic_new_info.destroy(); + } + ic_arena.reset(); + freeMsgBuffer(); + + tunnel_mutex = 0; + readahead_data = 0; + ic_hostname = 0; + } + +CacheContinuation(): + Continuation(NULL), + magicno(MagicNo), + callback_data(0), + callback_data_2(0), + timeout(0), + target_machine(0), + probe_depth(0), + start_time(0), + cache_read(false), + result(0), + result_error(0), + seq_number(0), + cfl_flags(0), + frag_type(CACHE_FRAG_TYPE_NONE), + nbytes(0), + target_ip(0), + request_opcode(0), + local_lookup_only(0), + no_reply_message(0), + request_timeout(0), + expect_cache_callback(true), + use_deferred_callback(0), + pin_in_cache(0), + rw_buf_msg_len(0), + read_cluster_vc(0), + write_cluster_vc(0), + cluster_vc_channel(0), + caller_buf_freebytes(0), + readahead_vio(0), + readahead_reader(0), + have_all_data(false), + cache_vc_info(), + tunnel(0), + tunnel_cont(0), + tunnel_closed(0), + lookup_open_write_vc_event(0), + ic_arena(), + ic_request(), + ic_response(), ic_params(0), ic_old_info(), ic_new_info(), ic_hostname_len(0), cache_op_ClusterFunction(0) { + token.clear(); + SET_HANDLER((CacheContHandler) & CacheContinuation::remoteOpEvent); + } + + inline static bool is_ClusterThread(EThread * et) + { + int etype = ET_CLUSTER; + int i; + for (i = 0; i < eventProcessor.n_threads_for_type[etype]; ++i) { + if (et == eventProcessor.eventthread[etype][i]) { + return true; + } + } + return false; + } + + // Static class member functions + static int init(); + static CacheContinuation *cacheContAllocator_alloc(); + static void cacheContAllocator_free(CacheContinuation *); + inkcoreapi static Action *callback_failure(Action *, int, int, CacheContinuation * this_cc = 0); + static Action *do_remote_lookup(Continuation *, CacheKey *, CacheContinuation *, CacheFragType, char *, int); + inkcoreapi static Action *do_op(Continuation *, ClusterMachine *, void *, int, char *, int, + int nbytes = -1, MIOBuffer * b = 0); + static int setup_local_vc(char *data, int data_len, CacheContinuation * cc, ClusterMachine * mp, Action **); + static void disposeOfDataBuffer(void *buf); + static int handleDisposeEvent(int event, CacheContinuation * cc); + static int32_t getObjectSize(VConnection *, int, CacheHTTPInfo *); +}; + +///////////////////////////////////////// +// Cache OP specific args for do_op() // +///////////////////////////////////////// + +// Bit definitions for cfl_flags. +// Note: Limited to 16 bits +#define CFL_OVERWRITE_ON_WRITE (1 << 1) +#define CFL_REMOVE_USER_AGENTS (1 << 2) +#define CFL_REMOVE_LINK (1 << 3) +#define CFL_LOPENWRITE_HAVE_OLDINFO (1 << 4) +#define CFL_ALLOW_MULTIPLE_WRITES (1 << 5) +#define CFL_MAX (1 << 15) + +struct CacheOpArgs_General +{ + INK_MD5 *url_md5; + time_t pin_in_cache; // open_write() specific arg + CacheFragType frag_type; + uint16_t cfl_flags; + + CacheOpArgs_General():url_md5(NULL), pin_in_cache(0), frag_type(CACHE_FRAG_TYPE_NONE), cfl_flags(0) + { + } +}; + +struct CacheOpArgs_Link +{ + INK_MD5 *from; + INK_MD5 *to; + uint16_t cfl_flags; // see CFL_XXX defines + CacheFragType frag_type; + + CacheOpArgs_Link():from(NULL), to(NULL), cfl_flags(0), frag_type(CACHE_FRAG_TYPE_NONE) + { + } +}; + +struct CacheOpArgs_Deref +{ + INK_MD5 *md5; + uint16_t cfl_flags; // see CFL_XXX defines + CacheFragType frag_type; + + CacheOpArgs_Deref():md5(NULL), cfl_flags(0), frag_type(CACHE_FRAG_TYPE_NONE) + { + } +}; + +/////////////////////////////////// +// Over the wire message formats // +/////////////////////////////////// +struct CacheLookupMsg:public ClusterMessageHeader +{ + INK_MD5 url_md5; + uint32_t seq_number; + uint32_t frag_type; + uint8_t moi[4]; + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + CACHE_LOOKUP_MESSAGE_VERSION = MAX_VERSION + }; + CacheLookupMsg(uint16_t vers = CACHE_LOOKUP_MESSAGE_VERSION): + ClusterMessageHeader(vers), seq_number(0), frag_type(0) { + memset(moi, 0, sizeof(moi)); + } + + ////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return CACHE_LOOKUP_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + CacheLookupMsg *p = 0; + + // Maybe use offsetoff here instead. /leif + return (int) ALIGN_DOUBLE(&p->moi[0]); + } + void init(uint16_t vers = CACHE_LOOKUP_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + ink_release_assert(!"No byte swap for INK_MD5"); + swap32(&seq_number); + swap32(&frag_type); + } + } + ////////////////////////////////////////////////////////////////////////// +}; + +struct CacheOpMsg_long:public ClusterMessageHeader +{ + uint8_t opcode; + uint8_t frag_type; + uint16_t cfl_flags; // see CFL_XXX defines + INK_MD5 url_md5; + uint32_t seq_number; + uint32_t nbytes; + uint32_t data; // used by open_write() + int32_t channel; // used by open interfaces + ClusterVCToken token; + int32_t buffer_size; // used by open read interface + uint8_t moi[4]; + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + CACHE_OP_LONG_MESSAGE_VERSION = MAX_VERSION + }; + CacheOpMsg_long(uint16_t vers = CACHE_OP_LONG_MESSAGE_VERSION): + ClusterMessageHeader(vers), + opcode(0), frag_type(0), cfl_flags(0), seq_number(0), nbytes(0), data(0), channel(0), buffer_size(0) { + memset(moi, 0, sizeof(moi)); + } + + ////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return CACHE_OP_LONG_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + CacheOpMsg_long *p = 0; + + // Change to offsetof maybe? /leif + return (int) ALIGN_DOUBLE(&p->moi[0]); + } + void init(uint16_t vers = CACHE_OP_LONG_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + ink_release_assert(!"No byte swap for INK_MD5"); + swap16(&cfl_flags); + swap32(&seq_number); + swap32(&nbytes); + swap32(&data); + swap32((uint32_t *) & channel); + token.SwapBytes(); + swap32((uint32_t *) & buffer_size); + swap32((uint32_t *) & frag_type); + } + } + ////////////////////////////////////////////////////////////////////////// +}; + +struct CacheOpMsg_short:public ClusterMessageHeader +{ + uint8_t opcode; + uint8_t frag_type; // currently used by open_write() (low level) + uint16_t cfl_flags; // see CFL_XXX defines + INK_MD5 md5; + uint32_t seq_number; + uint32_t nbytes; + uint32_t data; // currently used by open_write() (low level) + int32_t channel; // used by open interfaces + ClusterVCToken token; // used by open interfaces + int32_t buffer_size; // used by open read interface + + // Variable portion of message + uint8_t moi[4]; + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + CACHE_OP_SHORT_MESSAGE_VERSION = MAX_VERSION + }; + CacheOpMsg_short(uint16_t vers = CACHE_OP_SHORT_MESSAGE_VERSION): + ClusterMessageHeader(vers), + opcode(0), frag_type(0), cfl_flags(0), seq_number(0), nbytes(0), data(0), channel(0), buffer_size(0) { + memset(moi, 0, sizeof(moi)); + } + + ////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return CACHE_OP_SHORT_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + CacheOpMsg_short *p = 0; + // Use offsetof. /leif + return (int) ALIGN_DOUBLE(&p->moi[0]); + } + void init(uint16_t vers = CACHE_OP_SHORT_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + ink_release_assert(!"No byte swap for INK_MD5"); + swap16(&cfl_flags); + swap32(&seq_number); + swap32(&nbytes); + swap32(&data); + if (opcode == CACHE_OPEN_READ) { + swap32((uint32_t *) & buffer_size); + swap32((uint32_t *) & channel); + token.SwapBytes(); + } + } + } + ////////////////////////////////////////////////////////////////////////// +}; + +struct CacheOpMsg_short_2:public ClusterMessageHeader +{ + uint8_t opcode; + uint8_t frag_type; + uint16_t cfl_flags; // see CFL_XXX defines + INK_MD5 md5_1; + INK_MD5 md5_2; + uint32_t seq_number; + uint8_t moi[4]; + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + CACHE_OP_SHORT_2_MESSAGE_VERSION = MAX_VERSION + }; + CacheOpMsg_short_2(uint16_t vers = CACHE_OP_SHORT_2_MESSAGE_VERSION) +: ClusterMessageHeader(vers), opcode(0), frag_type(0), cfl_flags(0), seq_number(0) { + memset(moi, 0, sizeof(moi)); + } + ////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return CACHE_OP_SHORT_2_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + CacheOpMsg_short_2 *p = 0; + // Use offsetof already. /leif + return (int) ALIGN_DOUBLE(&p->moi[0]); + } + void init(uint16_t vers = CACHE_OP_SHORT_2_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + ink_release_assert(!"No byte swap for MD5_1"); + ink_release_assert(!"No byte swap for MD5_2"); + swap16(&cfl_flags); + swap32(&seq_number); + } + } + ////////////////////////////////////////////////////////////////////////// +}; + +struct CacheOpReplyMsg:public ClusterMessageHeader +{ + uint32_t seq_number; + int32_t result; + ClusterVCToken token; + uint8_t moi[4]; // Used by CACHE_OPEN_READ & CACHE_LINK reply + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + CACHE_OP_REPLY_MESSAGE_VERSION = MAX_VERSION + }; + CacheOpReplyMsg(uint16_t vers = CACHE_OP_REPLY_MESSAGE_VERSION): + ClusterMessageHeader(vers), seq_number(0), result(0) { + memset(moi, 0, sizeof(moi)); + } + + ////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return CACHE_OP_REPLY_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + CacheOpReplyMsg *p = 0; + // Use offsetof. /leif + return (int) ALIGN_DOUBLE(&p->moi[0]); + } + void init(uint16_t vers = CACHE_OP_REPLY_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + swap32(&seq_number); + swap32((uint32_t *) & result); + token.SwapBytes(); + } + } + ////////////////////////////////////////////////////////////////////////// +}; + +inline int +maxval(int a, int b) +{ + return ((a > b) ? a : b); +} + +inline int +op_to_sizeof_fixedlen_msg(int op) +{ + switch (op) { + case CACHE_LOOKUP_OP: + { + return CacheLookupMsg::sizeof_fixedlen_msg(); + } + case CACHE_OPEN_WRITE_BUFFER: + case CACHE_OPEN_WRITE_BUFFER_LONG: + { + ink_release_assert(!"op_to_sizeof_fixedlen_msg() op not supported"); + return 0; + } + case CACHE_OPEN_WRITE: + case CACHE_OPEN_READ: + case CACHE_OPEN_READ_BUFFER: + { + return CacheOpMsg_short::sizeof_fixedlen_msg(); + } + case CACHE_OPEN_READ_LONG: + case CACHE_OPEN_READ_BUFFER_LONG: + case CACHE_OPEN_WRITE_LONG: + { + return CacheOpMsg_long::sizeof_fixedlen_msg(); + } + case CACHE_UPDATE: + case CACHE_REMOVE: + case CACHE_DEREF: + { + return CacheOpMsg_short::sizeof_fixedlen_msg(); + } + case CACHE_LINK: + { + return CacheOpMsg_short_2::sizeof_fixedlen_msg(); + } + default: + { + ink_release_assert(!"op_to_sizeof_fixedlen_msg() unknown op"); + return 0; + } + } // End of switch +} + +////////////////////////////////////////////////////////////////////////////// + +static inline bool +event_is_lookup(int event) +{ + switch (event) { + default: + return false; + case CACHE_EVENT_LOOKUP: + case CACHE_EVENT_LOOKUP_FAILED: + return true; + } +} + +static inline bool +event_is_open(int event) +{ + switch (event) { + default: + return false; + case CACHE_EVENT_OPEN_READ: + case CACHE_EVENT_OPEN_WRITE: + return true; + } +} + +static inline bool +op_is_read(int opcode) +{ + switch (opcode) { + case CACHE_OPEN_READ: + case CACHE_OPEN_READ_LONG: + case CACHE_OPEN_READ_BUFFER: + case CACHE_OPEN_READ_BUFFER_LONG: + return true; + default: + return false; + } +} + +static inline bool +op_is_shortform(int opcode) +{ + switch (opcode) { + case CACHE_OPEN_READ: + case CACHE_OPEN_READ_BUFFER: + case CACHE_OPEN_WRITE: + case CACHE_OPEN_WRITE_BUFFER: + return true; + default: + return false; + } +} + +static inline int +op_failure(int opcode) +{ + switch (opcode) { + case CACHE_OPEN_WRITE: + case CACHE_OPEN_WRITE_LONG: + case CACHE_OPEN_WRITE_BUFFER: + case CACHE_OPEN_WRITE_BUFFER_LONG: + return CACHE_EVENT_OPEN_WRITE_FAILED; + + case CACHE_OPEN_READ: + case CACHE_OPEN_READ_LONG: + case CACHE_OPEN_READ_BUFFER: + case CACHE_OPEN_READ_BUFFER_LONG: + return CACHE_EVENT_OPEN_READ_FAILED; + + case CACHE_UPDATE: + return CACHE_EVENT_UPDATE_FAILED; + case CACHE_REMOVE: + return CACHE_EVENT_REMOVE_FAILED; + case CACHE_LINK: + return CACHE_EVENT_LINK_FAILED; + case CACHE_DEREF: + return CACHE_EVENT_DEREF_FAILED; + } + return -1; +} + +static inline int +op_needs_marshalled_coi(int opcode) +{ + switch (opcode) { + case CACHE_OPEN_WRITE: + case CACHE_OPEN_WRITE_BUFFER: + case CACHE_OPEN_READ: + case CACHE_OPEN_READ_BUFFER: + case CACHE_REMOVE: + case CACHE_LINK: + case CACHE_DEREF: + return 0; + + case CACHE_OPEN_WRITE_LONG: + case CACHE_OPEN_WRITE_BUFFER_LONG: + case CACHE_OPEN_READ_LONG: + case CACHE_OPEN_READ_BUFFER_LONG: + case CACHE_UPDATE: + return 0; + + default: + return 0; + } +} + +static inline int +event_reply_may_have_moi(int event) +{ + switch (event) { + case CACHE_EVENT_OPEN_READ: + case CACHE_EVENT_LINK: + case CACHE_EVENT_LINK_FAILED: + case CACHE_EVENT_OPEN_READ_FAILED: + case CACHE_EVENT_OPEN_WRITE_FAILED: + case CACHE_EVENT_REMOVE_FAILED: + case CACHE_EVENT_UPDATE_FAILED: + case CACHE_EVENT_DEREF_FAILED: + return true; + default: + return false; + } +} + +static inline int +event_is_failure(int event) +{ + switch (event) { + case CACHE_EVENT_LOOKUP_FAILED: + case CACHE_EVENT_OPEN_READ_FAILED: + case CACHE_EVENT_OPEN_WRITE_FAILED: + case CACHE_EVENT_UPDATE_FAILED: + case CACHE_EVENT_REMOVE_FAILED: + case CACHE_EVENT_LINK_FAILED: + case CACHE_EVENT_DEREF_FAILED: + return true; + default: + return false; + } +} + +#endif // __CLUSTERCACHEINTERNAL_H__ diff --git a/iocore/cluster/P_ClusterHandler.h b/iocore/cluster/P_ClusterHandler.h new file mode 100644 index 00000000..c575e48b --- /dev/null +++ b/iocore/cluster/P_ClusterHandler.h @@ -0,0 +1,666 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterHandler.h +****************************************************************************/ + +#ifndef _P_ClusterHandler_h +#define _P_ClusterHandler_h + + +class ClusterLoadMonitor; + +struct ClusterCalloutContinuation; +typedef int (ClusterCalloutContinuation::*ClstCoutContHandler) (int, void *); + +struct ClusterCalloutContinuation:public Continuation +{ + struct ClusterHandler *_ch; + + int CalloutHandler(int event, Event * e); + ClusterCalloutContinuation(struct ClusterHandler *ch); + ~ClusterCalloutContinuation(); +}; + +struct ClusterControl: public Continuation +{ + int len; // TODO: Should this be 64-bit ? + char size_index; + int64_t *real_data; + char *data; + void (*free_proc) (void *); + void *free_proc_arg; + Ptr iob_block; + + IOBufferBlock *get_block() + { + return iob_block; + } + bool fast_data() + { + return (len <= MAX_FAST_CONTROL_MESSAGE); + } + bool valid_alloc_data() + { + return iob_block && real_data && data; + } + + enum + { + // DATA_HDR = size_index (1 byte) + magicno (1 byte) + sizeof(this) + + DATA_HDR = (sizeof(int64_t) * 2) // must be multiple of sizeof(int64_t) + }; + + ClusterControl(); + void real_alloc_data(int, bool); + void free_data(); + virtual void freeall() = 0; +}; + +struct OutgoingControl: public ClusterControl +{ + ClusterMachine *m; + ink_hrtime submit_time; + + static OutgoingControl *alloc(); + + OutgoingControl(); + void alloc_data(bool align_int32_on_non_int64_boundary = true) { + real_alloc_data(1, align_int32_on_non_int64_boundary); /* read access */ + } + + void set_data(char *adata, int alen) + { + data = adata; + len = alen; + free_proc = 0; + free_proc_arg = 0; + real_data = 0; + + // Create IOBufferBlock wrapper around passed data. + + iob_block = new_IOBufferBlock(); + iob_block->set_internal(adata, alen, BUFFER_SIZE_FOR_XMALLOC(alen)); + iob_block->_buf_end = iob_block->end(); + } + + void set_data(IOBufferBlock * buf, void (*free_data_proc) (void *), void *free_data_arg) + { + data = buf->data->data(); + len = bytes_IOBufferBlockList(buf, 1); // read avail bytes + free_proc = free_data_proc; + free_proc_arg = free_data_arg; + real_data = 0; + iob_block = buf; + } + int startEvent(int event, Event * e); + virtual void freeall(); +}; + +// +// incoming control messsage are received by this machine +// +struct IncomingControl: public ClusterControl +{ + ink_hrtime recognized_time; + + static IncomingControl *alloc(); + + IncomingControl(); + void alloc_data(bool align_int32_on_non_int64_boundary = true) { + real_alloc_data(0, align_int32_on_non_int64_boundary); /* write access */ + } + virtual void freeall(); +}; + +// +// Interface structure for internal_invoke_remote() +// +struct invoke_remote_data_args +{ + int32_t magicno; + OutgoingControl *msg_oc; + OutgoingControl *data_oc; + int dest_channel; + ClusterVCToken token; + + enum + { + MagicNo = 0x04141998 + }; + invoke_remote_data_args():magicno(MagicNo), msg_oc(NULL), data_oc(NULL), dest_channel(0) + { + } +}; + +// +// Descriptor of a chunk of a message (see Memo.ClusterIODesign) +// This has been tested for aligment on the Sparc using TestDescriptor.cc +// + +// type +#define CLUSTER_SEND_FREE 0 +#define CLUSTER_SEND_DATA 1 +#define CLUSTER_SEQUENCE_NUMBER(_x) (((unsigned int)_x)&0xFFFF) + +struct Descriptor +{ // Note: Over the Wire structure + uint32_t type:1; + uint32_t channel:15; + uint16_t sequence_number; // lower 16 bits of the ClusterVCToken.seq + uint32_t length; + + inline void SwapBytes() + { + swap16((uint16_t *) this); // Hack + swap16((uint16_t *) & sequence_number); + swap32((uint32_t *) & length); + } +}; + +struct ClusterMsgHeader +{ // Note: Over the Wire structure + uint16_t count; + uint16_t descriptor_cksum; + uint16_t control_bytes_cksum; + uint16_t unused; + uint32_t control_bytes; + uint32_t count_check; + + void clear() + { + count = 0; + descriptor_cksum = 0; + control_bytes_cksum = 0; + unused = 0; + control_bytes = 0; + count_check = 0; + } + ClusterMsgHeader():count(0), descriptor_cksum(0), control_bytes_cksum(0), unused(0), control_bytes(0), count_check(0) + { + } + inline void SwapBytes() + { + swap16((uint16_t *) & count); + swap16((uint16_t *) & descriptor_cksum); + swap16((uint16_t *) & control_bytes_cksum); + swap16((uint16_t *) & unused); + swap32((uint32_t *) & control_bytes); + swap32((uint32_t *) & count_check); + } +}; + +struct ClusterMsg +{ + Descriptor *descriptor; + Ptr iob_descriptor_block; + int count; + int control_bytes; + int descriptor_cksum; + int control_bytes_cksum; + int unused; + int state; // Only used by read to denote + // read phase (count, descriptor, data) + Queue outgoing_control; + Queue outgoing_small_control; + Queue outgoing_callout; // compound msg callbacks + + // read processing usage. + int control_data_offset; + int did_small_control_set_data; + int did_large_control_set_data; + int did_small_control_msgs; + int did_large_control_msgs; + int did_freespace_msgs; + + ClusterMsgHeader *hdr() + { + return (ClusterMsgHeader *) (((char *) descriptor) + - sizeof(ClusterMsgHeader)); + } + + IOBufferBlock *get_block() + { + return iob_descriptor_block; + } + + IOBufferBlock *get_block_header() + { + int start_offset; + + start_offset = (char *) hdr() - iob_descriptor_block->buf(); + iob_descriptor_block->reset(); + iob_descriptor_block->next = 0; + iob_descriptor_block->fill(start_offset); + iob_descriptor_block->consume(start_offset); + return iob_descriptor_block; + } + + IOBufferBlock *get_block_descriptor() + { + int start_offset; + + start_offset = ((char *) hdr() + sizeof(ClusterMsgHeader)) + - iob_descriptor_block->buf(); + iob_descriptor_block->reset(); + iob_descriptor_block->next = 0; + iob_descriptor_block->fill(start_offset); + iob_descriptor_block->consume(start_offset); + return iob_descriptor_block; + } + + void clear() + { + hdr()->clear(); + count = 0; + control_bytes = 0; + descriptor_cksum = 0; + control_bytes_cksum = 0; + unused = 0; + state = 0; + outgoing_control.clear(); + outgoing_small_control.clear(); + control_data_offset = 0; + did_small_control_set_data = 0; + did_large_control_set_data = 0; + did_small_control_msgs = 0; + did_large_control_msgs = 0; + did_freespace_msgs = 0; + } + uint16_t calc_control_bytes_cksum() + { + uint16_t cksum = 0; + char *p = (char *) &descriptor[count]; + char *endp = p + control_bytes; + while (p < endp) { + cksum += *p; + ++p; + } + return cksum; + } + uint16_t calc_descriptor_cksum() + { + uint16_t cksum = 0; + char *p = (char *) &descriptor[0]; + char *endp = (char *) &descriptor[count]; + while (p < endp) { + cksum += *p; + ++p; + } + return cksum; + } +ClusterMsg():descriptor(NULL), iob_descriptor_block(NULL), count(0), + control_bytes(0), + descriptor_cksum(0), control_bytes_cksum(0), + unused(0), state(0), + control_data_offset(0), + did_small_control_set_data(0), + did_large_control_set_data(0), did_small_control_msgs(0), did_large_control_msgs(0), did_freespace_msgs(0) { + } + +}; + +// +// State for a particular (read/write) direction of a cluster link +// +struct ClusterHandler; +struct ClusterState: public Continuation +{ + ClusterHandler *ch; + bool read_channel; + bool do_iodone_event; // schedule_imm() on i/o complete + int n_descriptors; + ClusterMsg msg; + unsigned int sequence_number; + int to_do; // # of bytes to transact + int did; // # of bytes transacted + int n_iov; // defined iov(s) in this operation + int io_complete; // current i/o complete + int io_complete_event; // current i/o complete event + VIO *v; // VIO associated with current op + int bytes_xfered; // bytes xfered at last callback + int last_ndone; // last do_io ndone + int total_bytes_xfered; + IOVec *iov; // io vector for readv, writev + Ptr iob_iov; + + // Write byte bank structures + char *byte_bank; // bytes buffered for transit + int n_byte_bank; // number of bytes buffered for transit + int byte_bank_size; // allocated size of byte bank + + int missed; + bool missed_msg; + ink_hrtime last_time; + ink_hrtime start_time; + + Ptr block[MAX_TCOUNT]; + class MIOBuffer *mbuf; + int state; // See enum defs below + + + enum + { + READ_START = 1, + READ_HEADER, + READ_AWAIT_HEADER, + READ_SETUP_DESCRIPTOR, + READ_DESCRIPTOR, + READ_AWAIT_DESCRIPTOR, + READ_SETUP_DATA, + READ_DATA, + READ_AWAIT_DATA, + READ_POST_COMPLETE, + READ_COMPLETE + } read_state_t; + + enum + { + WRITE_START = 1, + WRITE_SETUP, + WRITE_INITIATE, + WRITE_AWAIT_COMPLETION, + WRITE_POST_COMPLETE, + WRITE_COMPLETE + } write_state_t; + + ClusterState(ClusterHandler *, bool); + ~ClusterState(); + IOBufferData *get_data(); + void build_do_io_vector(); + int doIO(); + int doIO_read_event(int, void *); + int doIO_write_event(int, void *); + void IOComplete(); +}; + +// +// ClusterHandlerBase superclass for processors with +// bi-directional VConnections. +// +struct ClusterHandlerBase: public Continuation +{ + // + // Private + // + Queue *read_vcs; + Queue *write_vcs; + int cur_vcs; + int min_priority; + Event *trigger_event; + + ClusterHandlerBase():Continuation(NULL), read_vcs(NULL), write_vcs(NULL), cur_vcs(0), min_priority(1) + { + } +}; + +struct ClusterHandler:public ClusterHandlerBase +{ +#ifdef MSG_TRACE + FILE *t_fd; +#endif + NetVConnection *net_vc; + EThread *thread; + unsigned int ip; + int port; + char *hostname; + ClusterMachine *machine; + int ifd; + + int32_t active; // handler currently running + bool on_stolen_thread; + + struct ChannelData + { + int channel_number; + LINK(ChannelData, link); + }; + + int n_channels; + ClusterVConnection **channels; + struct ChannelData **channel_data; + Queue free_local_channels; + + bool connector; + int cluster_connect_state; // see clcon_state_t enum + ClusterHelloMessage clusteringVersion; + ClusterHelloMessage nodeClusteringVersion; + bool needByteSwap; + int configLookupFails; + +#define CONFIG_LOOKUP_RETRIES 10 + + enum + { + CLCON_INITIAL = 1, + CLCON_SEND_MSG, + CLCON_SEND_MSG_COMPLETE, + CLCON_READ_MSG, + CLCON_READ_MSG_COMPLETE, + CLCON_VALIDATE_MSG, + CLCON_ABORT_CONNECT, + CLCON_DELETE_CONNECT + } clcon_state_t; + + InkAtomicList outgoing_control_al[CLUSTER_CMSG_QUEUES]; + InkAtomicList external_incoming_control; + InkAtomicList external_incoming_open_local; + ClusterCalloutContinuation * callout_cont[MAX_COMPLETION_CALLBACK_EVENTS]; + Event *callout_events[MAX_COMPLETION_CALLBACK_EVENTS]; + Event *cluster_periodic_event; + Queue outgoing_control[CLUSTER_CMSG_QUEUES]; + Queue incoming_control; + ClusterState read; + ClusterState write; + + ink_hrtime current_time; + ink_hrtime last; + ink_hrtime last_report; + int n_since_last_report; + ink_hrtime last_cluster_op_enable; + ink_hrtime last_trace_dump; + + DLL delayed_reads; + ClusterLoadMonitor *clm; + bool disable_remote_cluster_ops; + + // process_write() state data + int pw_write_descriptors_built; + int pw_freespace_descriptors_built; + int pw_controldata_descriptors_built; + int pw_time_expired; + bool started_on_stolen_thread; + bool control_message_write; + +#ifdef CLUSTER_STATS + Ptr message_blk; + + int64_t _vc_writes; + int64_t _vc_write_bytes; + int64_t _control_write_bytes; + int _dw_missed_lock; + int _dw_not_enabled; + int _dw_wait_remote_fill; + int _dw_no_active_vio; + int _dw_not_enabled_or_no_write; + int _dw_set_data_pending; + int _dw_no_free_space; + int _fw_missed_lock; + int _fw_not_enabled; + int _fw_wait_remote_fill; + int _fw_no_active_vio; + int _fw_not_enabled_or_no_read; + int _process_read_calls; + int _n_read_start; + int _n_read_header; + int _n_read_await_header; + int _n_read_setup_descriptor; + int _n_read_descriptor; + int _n_read_await_descriptor; + int _n_read_setup_data; + int _n_read_data; + int _n_read_await_data; + int _n_read_post_complete; + int _n_read_complete; + int _process_write_calls; + int _n_write_start; + int _n_write_setup; + int _n_write_initiate; + int _n_write_await_completion; + int _n_write_post_complete; + int _n_write_complete; + + void clear_cluster_stats() + { + _vc_writes = 0; + _vc_write_bytes = 0; + _control_write_bytes = 0; + _dw_missed_lock = 0; + _dw_not_enabled = 0; + _dw_wait_remote_fill = 0; + _dw_no_active_vio = 0; + _dw_not_enabled_or_no_write = 0; + _dw_set_data_pending = 0; + _dw_no_free_space = 0; + _fw_missed_lock = 0; + _fw_not_enabled = 0; + _fw_wait_remote_fill = 0; + _fw_no_active_vio = 0; + _fw_not_enabled_or_no_read = 0; + _process_read_calls = 0; + _n_read_start = 0; + _n_read_header = 0; + _n_read_await_header = 0; + _n_read_setup_descriptor = 0; + _n_read_descriptor = 0; + _n_read_await_descriptor = 0; + _n_read_setup_data = 0; + _n_read_data = 0; + _n_read_await_data = 0; + _n_read_post_complete = 0; + _n_read_complete = 0; + _process_write_calls = 0; + _n_write_start = 0; + _n_write_setup = 0; + _n_write_initiate = 0; + _n_write_await_completion = 0; + _n_write_post_complete = 0; + _n_write_complete = 0; + } +#endif // CLUSTER_STATS + + ClusterHandler(); + ~ClusterHandler(); + bool check_channel(int c); + int alloc_channel(ClusterVConnection * vc, int requested_channel = 0); + void free_channel(ClusterVConnection * vc); +// +// local_channel() +// - Initiator node-node TCP socket && Odd channel => Local Channel +// - !Initiator node-node TCP socket && Even channel => Local Channel + inline bool local_channel(int i) + { + return !connector == !(i & 1); + } + + void close_ClusterVConnection(ClusterVConnection *); + int cluster_signal_and_update(int event, ClusterVConnection * vc, ClusterVConnState * s); + int cluster_signal_and_update_locked(int event, ClusterVConnection * vc, ClusterVConnState * s); + int cluster_signal_error_and_update(ClusterVConnection * vc, ClusterVConnState * s, int lerrno); + void close_free_lock(ClusterVConnection *, ClusterVConnState *); + +#define CLUSTER_READ true +#define CLUSTER_WRITE false + + bool build_data_vector(char *, int, bool); + bool build_initial_vector(bool); + + void add_to_byte_bank(ClusterVConnection *); + void update_channels_read(); + int process_incoming_callouts(ProxyMutex *); + void update_channels_partial_read(); + void process_set_data_msgs(); + void process_small_control_msgs(); + void process_large_control_msgs(); + void process_freespace_msgs(); + bool complete_channel_read(int, ClusterVConnection * vc); + void finish_delayed_reads(); + // returns: false if the channel was closed + + void update_channels_written(bool); + + int build_write_descriptors(); + int build_freespace_descriptors(); + int build_controlmsg_descriptors(); + int add_small_controlmsg_descriptors(); + int valid_for_data_write(ClusterVConnection * vc); + int valid_for_freespace_write(ClusterVConnection * vc); + + int machine_down(); + int remote_close(ClusterVConnection * vc, ClusterVConnState * ns); + void steal_thread(EThread * t); + +#define CLUSTER_FREE_ALL_LOCKS -1 + void free_locks(bool read_flag, int i = CLUSTER_FREE_ALL_LOCKS); + bool get_read_locks(); + bool get_write_locks(); + int zombify(Event * e = NULL); // optional event to use + + int connectClusterEvent(int event, Event * e); + int startClusterEvent(int event, Event * e); + int mainClusterEvent(int event, Event * e); + int beginClusterEvent(int event, Event * e); + int zombieClusterEvent(int event, Event * e); + int protoZombieEvent(int event, Event * e); + + bool vc_ok_read(ClusterVConnection *); + bool vc_ok_write(ClusterVConnection *); + int do_open_local_requests(); + void swap_descriptor_bytes(); + int process_read(ink_hrtime); + int process_write(ink_hrtime, bool); + + void dump_write_msg(int); + void dump_read_msg(); + int compute_active_channels(); + void dump_internal_data(); + +#ifdef CLUSTER_IMMEDIATE_NETIO + void build_poll(bool); +#endif +}; + +// Valid (ClusterVConnection *) in ClusterHandler.channels[] +#define VALID_CHANNEL(vc) (vc && !(((uintptr_t) vc) & 1)) + +// outgoing control continuations +extern ClassAllocator outControlAllocator; + +// incoming control descriptors +extern ClassAllocator inControlAllocator; + +#endif /* _ClusterHandler_h */ diff --git a/iocore/cluster/P_ClusterInline.h b/iocore/cluster/P_ClusterInline.h new file mode 100644 index 00000000..baa801a1 --- /dev/null +++ b/iocore/cluster/P_ClusterInline.h @@ -0,0 +1,411 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ClusterInline.h +****************************************************************************/ + +#ifndef __P_CLUSTERINLINE_H__ +#define __P_CLUSTERINLINE_H__ +#include "P_ClusterCacheInternal.h" +#include "P_CacheInternal.h" + +inline Action * +Cluster_lookup(Continuation * cont, CacheKey * key, CacheFragType frag_type, char *hostname, int host_len) +{ + // Try to send remote, if not possible, handle locally + Action *retAct; + ClusterMachine *m = cluster_machine_at_depth(cache_hash(*key)); + if (!clusterProcessor.disable_remote_cluster_ops(m)) { + CacheContinuation *cc = CacheContinuation::cacheContAllocator_alloc(); + cc->action = cont; + cc->mutex = cont->mutex; + retAct = CacheContinuation::do_remote_lookup(cont, key, cc, frag_type, hostname, host_len); + if (retAct) { + return retAct; + } else { + // not remote, do local lookup + CacheContinuation::cacheContAllocator_free(cc); + return (Action *) NULL; + } + } else { + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_LOOKUP_FAILED, 0); + } + return (Action *) NULL; +} + +inline Action * +Cluster_read(ClusterMachine * owner_machine, int opcode, + Continuation * cont, MIOBuffer * buf, + CacheURL * url, CacheHTTPHdr * request, + CacheLookupHttpConfig * params, CacheKey * key, + time_t pin_in_cache, CacheFragType frag_type, char *hostname, int host_len) +{ + (void) params; + if (clusterProcessor.disable_remote_cluster_ops(owner_machine)) { + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_OPEN_READ_FAILED, 0); + } + int vers = CacheOpMsg_long::protoToVersion(owner_machine->msg_proto_major); + int flen; + int len = 0; + int cur_len; + int res = 0; + char *msg; + char *data; + + if (vers == CacheOpMsg_long::CACHE_OP_LONG_MESSAGE_VERSION) { + if ((opcode == CACHE_OPEN_READ_LONG) + || (opcode == CACHE_OPEN_READ_BUFFER_LONG)) { + // Determine length of data to Marshal + flen = op_to_sizeof_fixedlen_msg(opcode); + + const char *url_hostname; + int url_hlen; + INK_MD5 url_only_md5; + + Cache::generate_key(&url_only_md5, url, 0); + url_hostname = url->host_get(&url_hlen); + + len += request->m_heap->marshal_length(); + len += params->marshal_length(); + len += url_hlen; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + // Perform data Marshal operation + msg = (char *) ALLOCA_DOUBLE(flen + len); +#ifdef PURIFY + memset((char *) msg, 0, flen); +#endif + data = msg + flen; + + cur_len = len; + res = request->m_heap->marshal(data, cur_len); + if (res < 0) { + goto err_exit; + } + data += res; + cur_len -= res; + if ((res = params->marshal(data, cur_len)) < 0) + goto err_exit; + data += res; + cur_len -= res; + memcpy(data, url_hostname, url_hlen); + + CacheOpArgs_General readArgs; + readArgs.url_md5 = &url_only_md5; + readArgs.pin_in_cache = pin_in_cache; + readArgs.frag_type = frag_type; + return CacheContinuation::do_op(cont, owner_machine, (void *) &readArgs, + opcode, (char *) msg, (flen + len), -1, buf); + } else { + // Build message if we have host data. + + if (host_len) { + // Determine length of data to Marshal + flen = op_to_sizeof_fixedlen_msg(opcode); + len = host_len; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + msg = (char *) ALLOCA_DOUBLE(flen + len); +#ifdef PURIFY + memset((char *) msg, 0, flen); +#endif + data = msg + flen; + memcpy(data, hostname, host_len); + + } else { + msg = 0; + flen = 0; + len = 0; + } + CacheOpArgs_General readArgs; + readArgs.url_md5 = key; + readArgs.frag_type = frag_type; + return CacheContinuation::do_op(cont, owner_machine, (void *) &readArgs, + opcode, (char *) msg, (flen + len), -1, buf); + } + + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"CacheOpMsg_long [read] bad msg version"); + } +err_exit: + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_OPEN_READ_FAILED, 0); +} + +inline Action * +Cluster_write(Continuation * cont, int expected_size, + MIOBuffer * buf, ClusterMachine * m, + INK_MD5 * url_md5, CacheFragType ft, int options, + time_t pin_in_cache, int opcode, + CacheKey * key, CacheURL * url, + CacheHTTPHdr * request, CacheHTTPInfo * old_info, char *hostname, int host_len) +{ + (void) key; + (void) request; + if (clusterProcessor.disable_remote_cluster_ops(m)) { + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_OPEN_WRITE_FAILED, 0); + } + char *msg = 0; + char *data = 0; + int allow_multiple_writes = 0; + int len = 0; + int flen = 0; + int vers = CacheOpMsg_long::protoToVersion(m->msg_proto_major); + + switch (opcode) { + case CACHE_OPEN_WRITE: + { + // Build message if we have host data + if (host_len) { + // Determine length of data to Marshal + flen = op_to_sizeof_fixedlen_msg(CACHE_OPEN_WRITE); + len = host_len; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + msg = (char *) ALLOCA_DOUBLE(flen + len); + data = msg + flen; + + memcpy(data, hostname, host_len); + } + break; + } + case CACHE_OPEN_WRITE_LONG: + { + int url_hlen; + const char *url_hostname = url->host_get(&url_hlen); + + // Determine length of data to Marshal + flen = op_to_sizeof_fixedlen_msg(CACHE_OPEN_WRITE_LONG); + len = 0; + + if (old_info == (CacheHTTPInfo *) CACHE_ALLOW_MULTIPLE_WRITES) { + old_info = 0; + allow_multiple_writes = 1; + } + if (old_info) { + len += old_info->marshal_length(); + } + len += url_hlen; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + // Perform data Marshal operation + msg = (char *) ALLOCA_DOUBLE(flen + len); + data = msg + flen; + int res = 0; + + int cur_len = len; + + if (old_info) { + res = old_info->marshal(data, cur_len); + if (res < 0) { + goto err_exit; + } + data += res; + cur_len -= res; + } + memcpy(data, url_hostname, url_hlen); + break; + } + default: + { + ink_release_assert(!"open_write_internal invalid opcode."); + } // End of case + } // End of switch + + if (vers == CacheOpMsg_long::CACHE_OP_LONG_MESSAGE_VERSION) { + // Do remote open_write() + CacheOpArgs_General writeArgs; + writeArgs.url_md5 = url_md5; + writeArgs.pin_in_cache = pin_in_cache; + writeArgs.frag_type = ft; + writeArgs.cfl_flags |= (options & CACHE_WRITE_OPT_OVERWRITE ? CFL_OVERWRITE_ON_WRITE : 0); + writeArgs.cfl_flags |= (old_info ? CFL_LOPENWRITE_HAVE_OLDINFO : 0); + writeArgs.cfl_flags |= (allow_multiple_writes ? CFL_ALLOW_MULTIPLE_WRITES : 0); + + return CacheContinuation::do_op(cont, m, (void *) &writeArgs, opcode, msg, flen + len, expected_size, buf); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"CacheOpMsg_long [write] bad msg version"); + return (Action *) 0; + } + +err_exit: + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_OPEN_WRITE_FAILED, 0); +} + +inline Action * +Cluster_link(ClusterMachine * m, Continuation * cont, CacheKey * from, CacheKey * to, + CacheFragType type, char *hostname, int host_len) +{ + if (clusterProcessor.disable_remote_cluster_ops(m)) { + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_LINK_FAILED, 0); + } + + int vers = CacheOpMsg_short_2::protoToVersion(m->msg_proto_major); + if (vers == CacheOpMsg_short_2::CACHE_OP_SHORT_2_MESSAGE_VERSION) { + // Do remote link + + // Allocate memory for message header + int flen = op_to_sizeof_fixedlen_msg(CACHE_LINK); + int len = host_len; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + char *msg = (char *) ALLOCA_DOUBLE(flen + len); + memcpy((msg + flen), hostname, host_len); + + // Setup args for remote link + CacheOpArgs_Link linkArgs; + linkArgs.from = from; + linkArgs.to = to; + linkArgs.frag_type = type; + return CacheContinuation::do_op(cont, m, (void *) &linkArgs, CACHE_LINK, msg, (flen + len)); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"CacheOpMsg_short_2 [CACHE_LINK] bad msg version"); + return 0; + } + +err_exit: + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_LINK_FAILED, 0); +} + +inline Action * +Cluster_deref(ClusterMachine * m, Continuation * cont, CacheKey * key, CacheFragType type, char *hostname, int host_len) +{ + if (clusterProcessor.disable_remote_cluster_ops(m)) { + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_DEREF_FAILED, 0); + } + + int vers = CacheOpMsg_short::protoToVersion(m->msg_proto_major); + if (vers == CacheOpMsg_short::CACHE_OP_SHORT_MESSAGE_VERSION) { + // Do remote deref + + // Allocate memory for message header + int flen = op_to_sizeof_fixedlen_msg(CACHE_DEREF); + int len = host_len; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + char *msg = (char *) ALLOCA_DOUBLE(flen + len); + memcpy((msg + flen), hostname, host_len); + + // Setup args for remote deref + CacheOpArgs_Deref drefArgs; + drefArgs.md5 = key; + drefArgs.frag_type = type; + return CacheContinuation::do_op(cont, m, (void *) &drefArgs, CACHE_DEREF, msg, (flen + len)); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"CacheOpMsg_short [CACHE_DEREF] bad msg version"); + return 0; + } + +err_exit: + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_DEREF_FAILED, 0); +} + +inline Action * +Cluster_remove(ClusterMachine * m, Continuation * cont, CacheKey * key, + bool rm_user_agents, bool rm_link, CacheFragType frag_type, char *hostname, int host_len) +{ + if (clusterProcessor.disable_remote_cluster_ops(m)) { + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_REMOVE_FAILED, 0); + } + + int vers = CacheOpMsg_short::protoToVersion(m->msg_proto_major); + if (vers == CacheOpMsg_short::CACHE_OP_SHORT_MESSAGE_VERSION) { + // Do remote update + + // Allocate memory for message header + int flen = op_to_sizeof_fixedlen_msg(CACHE_REMOVE); + int len = host_len; + + if ((flen + len) > DEFAULT_MAX_BUFFER_SIZE) // Bound marshalled data + goto err_exit; + + char *msg = (char *) ALLOCA_DOUBLE(flen + len); + memcpy((msg + flen), hostname, host_len); + + // Setup args for remote update + CacheOpArgs_General updateArgs; + updateArgs.url_md5 = key; + updateArgs.cfl_flags |= (rm_user_agents ? CFL_REMOVE_USER_AGENTS : 0); + updateArgs.cfl_flags |= (rm_link ? CFL_REMOVE_LINK : 0); + updateArgs.frag_type = frag_type; + return CacheContinuation::do_op(cont, m, (void *) &updateArgs, CACHE_REMOVE, msg, (flen + len)); + } else { + ////////////////////////////////////////////////////////////// + // Create the specified down rev version of this message + ////////////////////////////////////////////////////////////// + ink_release_assert(!"CacheOpMsg_short [CACHE_REMOVE] bad msg version"); + return (Action *) 0; + } + +err_exit: + Action a; + a = cont; + return CacheContinuation::callback_failure(&a, CACHE_EVENT_REMOVE_FAILED, 0); +} + +#endif /* __CLUSTERINLINE_H__ */ diff --git a/iocore/cluster/P_ClusterInternal.h b/iocore/cluster/P_ClusterInternal.h new file mode 100644 index 00000000..0dfb1963 --- /dev/null +++ b/iocore/cluster/P_ClusterInternal.h @@ -0,0 +1,523 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterInternal.h +****************************************************************************/ +#include "P_ClusterCache.h" + +#ifndef _P_ClusterInternal_h +#define _P_ClusterInternal_h + +/*************************************************************************/ +// Compilation Options +/*************************************************************************/ +#define CLUSTER_THREAD_STEALING 1 +#define CLUSTER_TOMCAT 1 +#define CLUSTER_STATS 1 + + +#define ALIGN_DOUBLE(_p) ((((uintptr_t) (_p)) + 7) & ~7) +#define ALLOCA_DOUBLE(_sz) ALIGN_DOUBLE(alloca((_sz) + 8)) + +/*************************************************************************/ +// Configuration Parameters +/*************************************************************************/ +// Note: MAX_TCOUNT must be power of 2 +#define MAX_TCOUNT 128 +#define CONTROL_DATA (128*1024) +#define READ_BANK_BUF_SIZE DEFAULT_MAX_BUFFER_SIZE +#define READ_BANK_BUF_INDEX (DEFAULT_BUFFER_SIZES-1) +#define ALLOC_DATA_MAGIC 0xA5 // 8 bits in size +#define READ_LOCK_SPIN_COUNT 1 +#define WRITE_LOCK_SPIN_COUNT 1 + +// Unix specific optimizations +// #define CLUSTER_IMMEDIATE_NETIO 1 + + // (see ClusterHandler::mainClusterEvent) + // this is equivalent to a max of 0.7 seconds +#define CLUSTER_BUCKETS 64 +#define CLUSTER_PERIOD HRTIME_MSECONDS(10) + + // Per instance maximum time allotted to cluster thread +#define CLUSTER_MAX_RUN_TIME HRTIME_MSECONDS(100) + // Per instance maximum time allotted to thread stealing +#define CLUSTER_MAX_THREAD_STEAL_TIME HRTIME_MSECONDS(10) + + // minimum number of channels to allocate +#define MIN_CHANNELS 4096 +#define MAX_CHANNELS ((32*1024) - 1) // 15 bits in Descriptor + +#define CLUSTER_CONTROL_CHANNEL 0 +#define LAST_DEDICATED_CHANNEL 0 + +#define CLUSTER_PHASES 1 + +#define CLUSTER_INITIAL_PRIORITY CLUSTER_PHASES + // how often to retry connect to machines which are supposed to be in the + // cluster +#define CLUSTER_BUMP_LENGTH 1 +#define CLUSTER_MEMBER_DELAY HRTIME_SECONDS(1) + // How long to leave an unconnected ClusterVConnection waiting + // Note: assumes (CLUSTER_CONNECT_TIMEOUT == 2 * CACHE_CLUSTER_TIMEOUT) +#ifdef CLUSTER_TEST_DEBUG +#define CLUSTER_CONNECT_TIMEOUT HRTIME_SECONDS(65536) +#else +#define CLUSTER_CONNECT_TIMEOUT HRTIME_SECONDS(10) +#endif +#define CLUSTER_CONNECT_RETRY HRTIME_MSECONDS(20) +#define CLUSTER_RETRY HRTIME_MSECONDS(10) +#define CLUSTER_DELAY_BETWEEN_WRITES HRTIME_MSECONDS(10) + + // Force close on cluster channel if no activity detected in this interval +#ifdef CLUSTER_TEST_DEBUG +#define CLUSTER_CHANNEL_INACTIVITY_TIMEOUT (65536 * HRTIME_SECONDS(60)) +#else +#define CLUSTER_CHANNEL_INACTIVITY_TIMEOUT (10 * HRTIME_SECONDS(60)) +#endif + + // Defines for work deferred to ET_NET threads +#define COMPLETION_CALLBACK_PERIOD HRTIME_MSECONDS(10) +#define MAX_COMPLETION_CALLBACK_EVENTS 16 + + // ClusterHandler::mainClusterEvent() thread active state +#define CLUSTER_ACTIVE 1 +#define CLUSTER_NOT_ACTIVE 0 + + // defines for ClusterHandler::remote_closed +#define FORCE_CLOSE_ON_OPEN_CHANNEL -2 + + // defines for machine_config_change() +#define MACHINE_CONFIG 0 +#define CLUSTER_CONFIG 1 + +// Debug interface category definitions +#define CL_NOTE "cluster_note" +#define CL_WARN "cluster_warn" +#define CL_PROTO "cluster_proto" +#define CL_TRACE "cluster_trace" + +/*************************************************************************/ +// Constants +/*************************************************************************/ +#define MAX_FAST_CONTROL_MESSAGE 504 // 512 - 4 (cluster func #) - 4 align +#define SMALL_CONTROL_MESSAGE MAX_FAST_CONTROL_MESSAGE // copied instead + // of vectored +#define WRITE_MESSAGE_ALREADY_BUILT -1 + +#define MAGIC_COUNT(_x) \ +(0xBADBAD ^ ~(uint32_t)_x.msg.count \ + ^ ~(uint32_t)_x.msg.descriptor_cksum \ + ^ ~(uint32_t)_x.msg.control_bytes_cksum \ + ^ ~(uint32_t)_x.msg.unused \ + ^ ~((uint32_t)_x.msg.control_bytes << 16) ^_x.sequence_number) + +#define DOUBLE_ALIGN(_x) ((((uintptr_t)_x)+7)&~7) + +/*************************************************************************/ +// Testing Defines +/*************************************************************************/ +#define MISS_TEST 0 +#define TEST_PARTIAL_WRITES 0 +#define TEST_PARTIAL_READS 0 +#define TEST_TIMING 0 +#define TEST_READ_LOCKS_MISSED 0 +#define TEST_WRITE_LOCKS_MISSED 0 +#define TEST_ENTER_EXIT 0 +#define TEST_ENTER_EXIT 0 + +// +// Timing testing +// +#if TEST_TIMING +#define TTTEST(_x) \ +fprintf(stderr, _x " at: %u\n", \ + ((unsigned int)(ink_get_hrtime()/HRTIME_MSECOND)) % 1000) +#define TTEST(_x) \ +fprintf(stderr, _x " for: %d at: %u\n", vc->channel, \ + ((unsigned int)(ink_get_hrtime()/HRTIME_MSECOND)) % 1000) +#define TIMEOUT_TESTS(_s,_d) \ + if (*(int*)_d == 8) \ + fprintf(stderr,_s" lookup %d\n", *(int*)(_d+20)); \ + else if (*(int*)_d == 10) \ + fprintf(stderr,_s" op %d %d\n", *(int*)(_d+36), \ + *(int*)(_d+40)); \ + else if (*(int*)_d == 11) \ + fprintf(stderr,_s" rop %d %d\n", *(int*)(_d+4), \ + *(int*)(_d+8)) +#else +#define TTTEST(_x) +#define TTEST(_x) +#define TIMEOUT_TESTS(_x,_y) +#endif + +#if (TEST_READ_LOCKS_MISSED || TEST_WRITE_LOCKS_MISSED) +static unsigned int test_cluster_locks_missed = 0; +static +test_cluster_lock_might_fail() +{ + return (!(rand_r(&test_cluster_locks_missed) % 13)); +} +#endif +#if TEST_READ_LOCKS_MISSED +#define TEST_READ_LOCK_MIGHT_FAIL test_cluster_lock_might_fail() +#else +#define TEST_READ_LOCK_MIGHT_FAIL false +#endif +#if TEST_WRITE_LOCKS_MISSED +#define TEST_WRITE_LOCK_MIGHT_FAIL test_cluster_lock_might_fail() +#else +#define TEST_WRITE_LOCK_MIGHT_FAIL false +#endif + +#if TEST_ENTER_EXIT +struct enter_exit_class +{ + int *outv; + enter_exit_class(int *in, int *out):outv(out) + { + (*in)++; + } + ~enter_exit_class() + { + (*outv)++; + } +}; + +#define enter_exit(_x,_y) enter_exit_class a(_x,_y) +#else +#define enter_exit(_x,_y) +#endif + +#define DOT_SEPARATED(_x) \ +((unsigned char*)&(_x))[0], ((unsigned char*)&(_x))[1], \ + ((unsigned char*)&(_x))[2], ((unsigned char*)&(_x))[3] + +// +// RPC message for CLOSE_CHANNEL_CLUSTER_FUNCTION +// +struct CloseMessage:public ClusterMessageHeader +{ + uint32_t channel; + int32_t status; + int32_t lerrno; + uint32_t sequence_number; + + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + CLOSE_CHAN_MESSAGE_VERSION = MAX_VERSION + }; + + CloseMessage(uint16_t vers = CLOSE_CHAN_MESSAGE_VERSION) +: ClusterMessageHeader(vers), channel(0), status(0), lerrno(0), sequence_number(0) { + } + //////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return CLOSE_CHAN_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + return sizeof(CloseMessage); + } + void init(uint16_t vers = CLOSE_CHAN_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + swap32(&channel); + swap32((uint32_t *) & status); + swap32((uint32_t *) & lerrno); + swap32(&sequence_number); + } + } + //////////////////////////////////////////////////////////////////////////// +}; + +// +// RPC message for MACHINE_LIST_CLUSTER_FUNCTION +// +struct MachineListMessage:public ClusterMessageHeader +{ + uint32_t n_ip; // Valid entries in ip[] + uint32_t ip[CLUSTER_MAX_MACHINES]; // variable length data + + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + MACHINE_LIST_MESSAGE_VERSION = MAX_VERSION + }; + + MachineListMessage():ClusterMessageHeader(MACHINE_LIST_MESSAGE_VERSION), n_ip(0) + { + memset(ip, 0, sizeof(ip)); + } + //////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return MACHINE_LIST_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + return sizeof(ClusterMessageHeader); + } + void init(uint16_t vers = MACHINE_LIST_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + swap32(&n_ip); + } + //////////////////////////////////////////////////////////////////////////// +}; + +// +// RPC message for SET_CHANNEL_DATA_CLUSTER_FUNCTION +// +struct SetChanDataMessage:public ClusterMessageHeader +{ + uint32_t channel; + uint32_t sequence_number; + uint32_t data_type; // enum CacheDataType + char data[4]; + + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + SET_CHANNEL_DATA_MESSAGE_VERSION = MAX_VERSION + }; + + SetChanDataMessage(uint16_t vers = SET_CHANNEL_DATA_MESSAGE_VERSION) +: ClusterMessageHeader(vers), channel(0), sequence_number(0), data_type(0) { + memset(data, 0, sizeof(data)); + } + //////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return SET_CHANNEL_DATA_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + SetChanDataMessage *p = 0; + return (int) DOUBLE_ALIGN((int64_t) ((char *) &p->data[0] - (char *) p)); + } + void init(uint16_t vers = SET_CHANNEL_DATA_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + swap32(&channel); + swap32(&sequence_number); + swap32(&data_type); + } + } + //////////////////////////////////////////////////////////////////////////// +}; + +// +// RPC message for SET_CHANNEL_PIN_CLUSTER_FUNCTION +// +struct SetChanPinMessage:public ClusterMessageHeader +{ + uint32_t channel; + uint32_t sequence_number; + uint32_t pin_time; + + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + SET_CHANNEL_PIN_MESSAGE_VERSION = MAX_VERSION + }; + + SetChanPinMessage(uint16_t vers = SET_CHANNEL_PIN_MESSAGE_VERSION) +: ClusterMessageHeader(vers), channel(0), sequence_number(0), pin_time(0) { + } + //////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return SET_CHANNEL_PIN_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + return (int) sizeof(SetChanPinMessage); + } + void init(uint16_t vers = SET_CHANNEL_PIN_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + swap32(&channel); + swap32(&sequence_number); + swap32(&pin_time); + } + } + //////////////////////////////////////////////////////////////////////////// +}; + +// +// RPC message for SET_CHANNEL_PRIORITY_CLUSTER_FUNCTION +// +struct SetChanPriorityMessage:public ClusterMessageHeader +{ + uint32_t channel; + uint32_t sequence_number; + uint32_t disk_priority; + + enum + { + MIN_VERSION = 1, + MAX_VERSION = 1, + SET_CHANNEL_PRIORITY_MESSAGE_VERSION = MAX_VERSION + }; + + SetChanPriorityMessage(uint16_t vers = SET_CHANNEL_PRIORITY_MESSAGE_VERSION) +: ClusterMessageHeader(vers), channel(0), sequence_number(0), disk_priority(0) { + } + //////////////////////////////////////////////////////////////////////////// + static int protoToVersion(int protoMajor) + { + (void) protoMajor; + return SET_CHANNEL_PRIORITY_MESSAGE_VERSION; + } + static int sizeof_fixedlen_msg() + { + return (int) sizeof(SetChanPriorityMessage); + } + void init(uint16_t vers = SET_CHANNEL_PRIORITY_MESSAGE_VERSION) { + _init(vers); + } + inline void SwapBytes() + { + if (NeedByteSwap()) { + swap32(&channel); + swap32(&sequence_number); + swap32(&disk_priority); + } + } + //////////////////////////////////////////////////////////////////////////// +}; + +inline void +SetHighBit(int *val) +{ + *val |= (1 << ((sizeof(int) * 8) - 1)); +} + +inline void +ClearHighBit(int *val) +{ + *val &= ~(1 << ((sizeof(int) * 8) - 1)); +} + +inline int +IsHighBitSet(int *val) +{ + return (*val & (1 << ((sizeof(int) * 8) - 1))); +} + +///////////////////////////////////////////////////////////////// +// ClusterAccept -- Handle cluster connect events from peer +// cluster nodes. +///////////////////////////////////////////////////////////////// +class ClusterAccept:public Continuation +{ +public: + ClusterAccept(int *, int, int); + void Init(); + void ShutdownDelete(); + int ClusterAcceptEvent(int, void *); + int ClusterAcceptMachine(NetVConnection *); + + ~ClusterAccept(); +private: + + int *p_cluster_port; + int socket_send_bufsize; + int socket_recv_bufsize; + unsigned long socket_opt_flags; + int current_cluster_port; + Action *accept_action; + Event *periodic_event; +}; + +// VC++ 5.0 special +struct ClusterHandler; +typedef int (ClusterHandler::*ClusterContHandler) (int, void *); + +struct OutgoingControl; +typedef int (OutgoingControl::*OutgoingCtrlHandler) (int, void *); + +struct ClusterVConnection; +typedef int (ClusterVConnection::*ClusterVConnHandler) (int, void *); + +typedef struct iovec IOVec; + +// Library declarations +extern void cluster_set_priority(ClusterHandler *, ClusterVConnState *, int); +extern void cluster_lower_priority(ClusterHandler *, ClusterVConnState *); +extern void cluster_raise_priority(ClusterHandler *, ClusterVConnState *); +extern void cluster_schedule(ClusterHandler *, ClusterVConnection *, ClusterVConnState *); +extern void cluster_reschedule(ClusterHandler *, ClusterVConnection *, ClusterVConnState *); +extern void cluster_disable(ClusterHandler *, ClusterVConnection *, ClusterVConnState *); +extern void cluster_update_priority(ClusterHandler *, ClusterVConnection *, ClusterVConnState *, int64_t, int64_t); +#define CLUSTER_BUMP_NO_REMOVE -1 +extern void cluster_bump(ClusterHandler *, ClusterVConnectionBase *, ClusterVConnState *, int); +extern int iov_memcpy(IOVec *, int, int, char *); + +extern IOBufferBlock *clone_IOBufferBlockList(IOBufferBlock *, int, int, IOBufferBlock **); +extern IOBufferBlock *consume_IOBufferBlockList(IOBufferBlock *, int64_t); +extern int64_t bytes_IOBufferBlockList(IOBufferBlock *, int64_t); + +// ClusterVConnection declarations +extern void clusterVCAllocator_free(ClusterVConnection * vc); +extern ClassAllocator clusterVCAllocator; +extern ClassAllocator byteBankAllocator; + +// Cluster configuration declarations +extern int cluster_port; +// extern void * machine_config_change(void *, void *); +int machine_config_change(const char *, RecDataT, RecData, void *); +extern void do_machine_config_change(void *, const char *); + +#ifdef NON_MODULAR +// Cluster API support functions +extern void clusterAPI_init(); +extern void machine_online_APIcallout(int); +extern void machine_offline_APIcallout(int); +#endif +#endif /* _ClusterInternal_h */ diff --git a/iocore/cluster/P_ClusterLib.h b/iocore/cluster/P_ClusterLib.h new file mode 100644 index 00000000..9aaceeb1 --- /dev/null +++ b/iocore/cluster/P_ClusterLib.h @@ -0,0 +1,72 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ClusterLib.h + + +****************************************************************************/ + +#ifndef _P_ClusterLib_h +#define _P_ClusterLib_h + +#include "P_Cluster.h" + +extern void cluster_set_priority(ClusterHandler *, ClusterVConnState *, int); +extern void cluster_lower_priority(ClusterHandler *, ClusterVConnState *); +extern void cluster_raise_priority(ClusterHandler *, ClusterVConnState *); +extern void cluster_schedule(ClusterHandler *, ClusterVConnection *, ClusterVConnState *); +extern void cluster_reschedule(ClusterHandler *, ClusterVConnection *, ClusterVConnState *); +extern void cluster_disable(ClusterHandler *, ClusterVConnection *, ClusterVConnState *); +extern void cluster_update_priority(ClusterHandler *, ClusterVConnection *, ClusterVConnState *, int64_t, int64_t); +extern void cluster_bump(ClusterHandler *, ClusterVConnectionBase *, ClusterVConnState *, int); +extern int iov_memcpy(IOVec *, int, int, char *); + +#if TEST_PARTIAL_READS +extern int partial_readv(int, IOVec *, int, int); +#endif + +#if TEST_PARTIAL_WRITES +extern int partial_writev(int, IOVec *, int, int); +#endif + +extern void dump_time_buckets(); + +struct GlobalClusterPeriodicEvent; +typedef int (GlobalClusterPeriodicEvent::*GClusterPEHandler) (int, void *); + +struct GlobalClusterPeriodicEvent:public Continuation +{ + GlobalClusterPeriodicEvent(); + ~GlobalClusterPeriodicEvent(); + void init(); + int calloutEvent(Event * e, void *data); + + // Private data + Event *_thisCallout; +}; + +#endif /* _ClusterLib_h */ + +// End of ClusterLib.h diff --git a/iocore/cluster/P_ClusterLoadMonitor.h b/iocore/cluster/P_ClusterLoadMonitor.h new file mode 100644 index 00000000..46f98063 --- /dev/null +++ b/iocore/cluster/P_ClusterLoadMonitor.h @@ -0,0 +1,118 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + ClusterLoadMonitor.h +****************************************************************************/ + +#ifndef _P_ClusterLoadMonitor_h +#define _P_ClusterLoadMonitor_h + +#include "P_Cluster.h" + +//*************************************************************************** +// ClusterLoadMonitor class -- Compute cluster interconnect load metric +//*************************************************************************** +class ClusterLoadMonitor:public Continuation +{ +public: + ///////////////////////////////////// + // Defined by records.config + ///////////////////////////////////// + static int cf_monitor_enabled; + static int cf_ping_message_send_msec_interval; + static int cf_num_ping_response_buckets; + static int cf_msecs_per_ping_response_bucket; + static int cf_ping_latency_threshold_msecs; + static int cf_cluster_load_compute_msec_interval; + static int cf_cluster_periodic_msec_interval; + static int cf_ping_history_buf_length; + static int cf_cluster_load_clear_duration; + static int cf_cluster_load_exceed_duration; + + struct cluster_load_ping_msg + { + int magicno; + int version; + int sequence_number; + ink_hrtime send_time; + ClusterLoadMonitor *monitor; + + enum + { + CL_MSG_MAGICNO = 0x12ABCDEF, + CL_MSG_VERSION = 1 + }; + cluster_load_ping_msg(ClusterLoadMonitor * m = 0) + : magicno(CL_MSG_MAGICNO), version(CL_MSG_VERSION), sequence_number(0), send_time(0), monitor(m) { + } + }; + + static void cluster_load_ping_rethandler(ClusterMachine *, void *, int); + +public: + ClusterLoadMonitor(ClusterMachine * m); + void init(); + ~ClusterLoadMonitor(); + void cancel_monitor(); + bool is_cluster_overloaded(); + +private: + void compute_cluster_load(); + void note_ping_response_time(ink_hrtime, int); + void recv_cluster_load_msg(cluster_load_ping_msg *); + void send_cluster_load_msg(ink_hrtime); + int cluster_load_periodic(int, Event *); + +private: + //////////////////////////////////////////////////// + // Copy of global configuration (records.config) + //////////////////////////////////////////////////// + int ping_message_send_msec_interval; + int num_ping_response_buckets; + int msecs_per_ping_response_bucket; + int ping_latency_threshold_msecs; + int cluster_load_compute_msec_interval; + int cluster_periodic_msec_interval; + int ping_history_buf_length; + int cluster_load_clear_duration; + int cluster_load_exceed_duration; + + // Class specific data + ClusterMachine *machine; + int *ping_response_buckets; + ink_hrtime *ping_response_history_buf; + int ping_history_buf_head; + Action *periodic_action; + + int cluster_overloaded; + int cancel_periodic; + ink_hrtime last_ping_message_sent; + ink_hrtime last_cluster_load_compute; + int cluster_load_msg_sequence_number; + int cluster_load_msg_start_sequence_number; +}; + +#endif /* _ClusterLoadMonitor_h */ diff --git a/iocore/cluster/P_ClusterMachine.h b/iocore/cluster/P_ClusterMachine.h new file mode 100644 index 00000000..a69227df --- /dev/null +++ b/iocore/cluster/P_ClusterMachine.h @@ -0,0 +1,131 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Machine.h + ****************************************************************************/ + + +// +// The Machine is the set of processes which share part of an +// address space. +// + +#ifndef _P_ClusterMachine_h +#define _P_ClusterMachine_h + +// +// Timeout the Machine * this amount of time after they +// fall out of the current configuration that are deleted. +// +#define MACHINE_TIMEOUT (HRTIME_DAY*2) + + +// +// This is the time processors should delay before freeing up resouces +// which are shared with other threads in non-long running operations. +// For example, a Machine * is returned by the hash and used to do +// a remote invoke. For the pointer to remain valid (or be recognized as +// invalid) he resource should not be raclaimed for NO_RACE_DELAY. +// +// Long running operations should use more sophisticated synchronization. +// +#define NO_RACE_DELAY HRTIME_HOUR // a long long time + +struct ClusterHandler; // Leave this a class - VC++ gets very anal ~SR -- which version of VC++? ~igalic + +struct ClusterMachine: public Server +{ + bool dead; + char *hostname; + int hostname_len; + // + // The network address of the current machine, + // stored in network byte order + // + unsigned int ip; + int cluster_port; + + Link link; + + // default for localhost + ClusterMachine(char *hostname = NULL, unsigned int ip = 0, int acluster_port = 0); + ~ClusterMachine(); + + // Cluster message protocol version + uint16_t msg_proto_major; + uint16_t msg_proto_minor; + + // Private data for ClusterProcessor + // + ClusterHandler *clusterHandler; +}; + +struct MachineListElement +{ + unsigned int ip; + int port; +}; +struct MachineList +{ + int n; + MachineListElement machine[1]; + MachineListElement *find(unsigned int ip, int port = 0) { + for (int i = 0; i < n; i++) + if (machine[i].ip == ip && (!port || machine[i].port == port)) + return &machine[i]; + return NULL; + } +}; + +MachineList *read_MachineList(char *filename, int test_fd = -1); +void free_MachineList(MachineList * l); + +struct clusterConfigFile +{ +#ifndef INK_NO_CLUSTER + char *parseFile(int fd) + { + return (char *) read_MachineList(NULL, fd); + } +#endif +}; + +inkcoreapi ClusterMachine *this_cluster_machine(); +void create_this_cluster_machine(); + +void free_ClusterMachine(ClusterMachine * m); + +MachineList *the_cluster_machines_config(); +MachineList *the_cluster_config(); +extern ProxyMutex *the_cluster_config_mutex; + +// +// Private +// +extern MachineList *machines_config; +extern MachineList *cluster_config; + + +#endif /* _Machine_h */ diff --git a/iocore/cluster/P_TimeTrace.h b/iocore/cluster/P_TimeTrace.h new file mode 100644 index 00000000..e4f3796a --- /dev/null +++ b/iocore/cluster/P_TimeTrace.h @@ -0,0 +1,83 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + TimeTrace.h + ****************************************************************************/ + +#ifndef _P_TimeTrace_h_ +#define _P_TimeTrace_h_ + +// #define ENABLE_TIME_TRACE + +#define TIME_DIST_BUCKETS 500 +#define TIME_DIST_BUCKETS_SIZE TIME_DIST_BUCKETS+1 + +#ifdef ENABLE_TIME_TRACE +extern int cdb_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cdb_cache_callbacks; + +extern int callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cache_callbacks; + +extern int rmt_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int rmt_cache_callbacks; + +extern int lkrmt_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int lkrmt_cache_callbacks; + +extern int cntlck_acquire_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cntlck_acquire_events; + +extern int immediate_events_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cnt_immediate_events; + +extern int inmsg_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int inmsg_events; + +extern int open_delay_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int open_delay_events; + +extern int cluster_send_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cluster_send_events; +#endif // ENABLE_TIME_TRACE + +#ifdef ENABLE_TIME_TRACE +#define LOG_EVENT_TIME(_start_time, _time_dist, _time_cnt) do { \ + ink_hrtime now = ink_get_hrtime(); \ + unsigned int bucket = (now - _start_time) / HRTIME_MSECONDS(10); \ + if (bucket > TIME_DIST_BUCKETS) \ + bucket = TIME_DIST_BUCKETS; \ + ink_atomic_increment(&_time_dist[bucket], 1); \ + ink_atomic_increment(&_time_cnt, 1); \ +} while(0) + +#else // !ENABLE_TIME_TRACE +#define LOG_EVENT_TIME(_start_time, _time_dist, _time_cnt) +#endif // !ENABLE_TIME_TRACE + +#endif // _TimeTrace_h_ + +// End of TimeTrace.h diff --git a/iocore/cluster/test_I_Cluster.cc b/iocore/cluster/test_I_Cluster.cc new file mode 100644 index 00000000..0f3a733e --- /dev/null +++ b/iocore/cluster/test_I_Cluster.cc @@ -0,0 +1,147 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + This is a bogus test file because it does not need any cluster + functions : the actual test file is in the cache directory. + This file is a placeholder because each module is supposed to + have a test file + */ + +#include "P_Cluster.h" +#include +#include + +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// + // XXX: HP-UX ??? +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + + +int +main(int argc, char *argv[]) +{ + int i; + int num_net_threads = ink_number_of_processors(); + init_diags("", NULL); + RecProcessInit(RECM_STAND_ALONE); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(num_net_threads); + RecProcessStart(); + // ink_aio_init(AIO_MODULE_VERSION); + + this_thread()->execute(); +} diff --git a/iocore/cluster/test_P_Cluster.cc b/iocore/cluster/test_P_Cluster.cc new file mode 100644 index 00000000..0f3a733e --- /dev/null +++ b/iocore/cluster/test_P_Cluster.cc @@ -0,0 +1,147 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + This is a bogus test file because it does not need any cluster + functions : the actual test file is in the cache directory. + This file is a placeholder because each module is supposed to + have a test file + */ + +#include "P_Cluster.h" +#include +#include + +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// + // XXX: HP-UX ??? +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + + +int +main(int argc, char *argv[]) +{ + int i; + int num_net_threads = ink_number_of_processors(); + init_diags("", NULL); + RecProcessInit(RECM_STAND_ALONE); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(num_net_threads); + RecProcessStart(); + // ink_aio_init(AIO_MODULE_VERSION); + + this_thread()->execute(); +} diff --git a/iocore/dns/DNS.cc b/iocore/dns/DNS.cc new file mode 100644 index 00000000..af8f9dd8 --- /dev/null +++ b/iocore/dns/DNS.cc @@ -0,0 +1,1585 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_DNS.h" /* MAGIC_EDITING_TAG */ + +#ifdef SPLIT_DNS +#include "I_SplitDNS.h" +#endif + +#define SRV_COST (RRFIXEDSZ+0) +#define SRV_WEIGHT (RRFIXEDSZ+2) +#define SRV_PORT (RRFIXEDSZ+4) +#define SRV_SERVER (RRFIXEDSZ+6) +#define SRV_FIXEDSZ (RRFIXEDSZ+6) + +EventType ET_DNS = ET_CALL; + +// +// Config +// +int dns_timeout = DEFAULT_DNS_TIMEOUT; +int dns_retries = DEFAULT_DNS_RETRIES; +int dns_search = DEFAULT_DNS_SEARCH; +int dns_failover_number = DEFAULT_FAILOVER_NUMBER; +int dns_failover_period = DEFAULT_FAILOVER_PERIOD; +int dns_failover_try_period = DEFAULT_FAILOVER_TRY_PERIOD; +int dns_max_dns_in_flight = MAX_DNS_IN_FLIGHT; +int dns_validate_qname = 0; +unsigned int dns_handler_initialized = 0; +int dns_ns_rr = 0; +int dns_ns_rr_init_down = 1; +char *dns_ns_list = NULL; +char *dns_resolv_conf = NULL; +int dns_thread = 0; + +DNSProcessor dnsProcessor; +ClassAllocator dnsEntryAllocator("dnsEntryAllocator"); +// Users are expected to free these entries in short order! +// We could page align this buffer to enable page flipping for recv... +ClassAllocator dnsBufAllocator("dnsBufAllocator", 2); + + +// +// Function Prototypes +// +static bool dns_process(DNSHandler *h, HostEnt *ent, int len); +static DNSEntry *get_dns(DNSHandler *h, uint16_t id); +// returns true when e is done +static void dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry); +static void write_dns(DNSHandler *h); +static bool write_dns_event(DNSHandler *h, DNSEntry *e); + +// "reliable" name to try. need to build up first. +static int try_servers = 0; +static int local_num_entries = 1; +static int attempt_num_entries = 1; +char try_server_names[DEFAULT_NUM_TRY_SERVER][MAXDNAME]; + + +static inline char * +strnchr(char *s, char c, int len) { + while (*s && *s != c && len) + ++s, --len; + return *s == c ? s : (char *) NULL; +} + +static inline uint16_t +ink_get16(const uint8_t *src) { + uint16_t dst; + + NS_GET16(dst, src); + return dst; +} + +void HostEnt::free() { + dnsBufAllocator.free(this); +} + +// +// Public functions +// +// See documentation is header files and Memos +// +int +DNSProcessor::start(int) { + // + // Read configuration + // + IOCORE_EstablishStaticConfigInt32(dns_retries, "proxy.config.dns.retries"); + IOCORE_EstablishStaticConfigInt32(dns_timeout, "proxy.config.dns.lookup_timeout"); + IOCORE_EstablishStaticConfigInt32(dns_search, "proxy.config.dns.search_default_domains"); + IOCORE_EstablishStaticConfigInt32(dns_failover_number, "proxy.config.dns.failover_number"); + IOCORE_EstablishStaticConfigInt32(dns_failover_period, "proxy.config.dns.failover_period"); + IOCORE_EstablishStaticConfigInt32(dns_max_dns_in_flight, "proxy.config.dns.max_dns_in_flight"); + IOCORE_EstablishStaticConfigInt32(dns_validate_qname, "proxy.config.dns.validate_query_name"); + IOCORE_EstablishStaticConfigInt32(dns_ns_rr, "proxy.config.dns.round_robin_nameservers"); + IOCORE_ReadConfigStringAlloc(dns_ns_list, "proxy.config.dns.nameservers"); + IOCORE_ReadConfigStringAlloc(dns_resolv_conf, "proxy.config.dns.resolv_conf"); + IOCORE_EstablishStaticConfigInt32(dns_thread, "proxy.config.dns.dedicated_thread"); + + if (dns_thread > 0) { + ET_DNS = eventProcessor.spawn_event_threads(1, "ET_DNS"); // TODO: Hmmm, should we just get a single thread some other way? + initialize_thread_for_net(eventProcessor.eventthread[ET_DNS][0], 0); + } else { + // Initialize the first event thread for DNS. + ET_DNS = ET_CALL; + } + thread = eventProcessor.eventthread[ET_DNS][0]; + + dns_failover_try_period = dns_timeout + 1; // Modify the "default" accordingly + + if (SplitDNSConfig::gsplit_dns_enabled) { + //reconfigure after threads start + SplitDNSConfig::reconfigure(); + } + + // Setup the default DNSHandler, it's used both by normal DNS, and SplitDNS (for PTR lookups etc.) + dns_init(); + open(); + + return 0; +} + +void +DNSProcessor::open(unsigned int aip, int aport, int aoptions) +{ + DNSHandler *h = NEW(new DNSHandler); + + h->options = aoptions; + h->mutex = thread->mutex; + h->m_res = &l_res; + h->ip = aip; + h->port = aport; + + if (!dns_handler_initialized) + handler = h; + + SET_CONTINUATION_HANDLER(h, &DNSHandler::startEvent); + thread->schedule_imm(h); +} + +// +// Initialization +// +void +DNSProcessor::dns_init() +{ + gethostname(try_server_names[0], 255); + Debug("dns", "localhost=%s\n", try_server_names[0]); + Debug("dns", "Round-robin nameservers = %d\n", dns_ns_rr); + + if (dns_ns_list) { + Debug("dns", "Nameserver list specified \"%s\"\n", dns_ns_list); + uint32_t nameserver_ip[MAX_NAMED]; + int nameserver_port[MAX_NAMED]; + int i, j; + char *last, *ndx; + char *ns_list = xstrdup(dns_ns_list); + char *ns = (char *) ink_strtok_r(ns_list, " ,;\t\r", &last); + + for (i = 0, j = 0; (i < MAX_NAMED) && ns; i++) { + Debug("dns", "Nameserver list - parsing \"%s\"\n", ns); + int err = 0; + int prt = DOMAIN_SERVICE_PORT; + if ((ndx = strchr(ns, ':'))) { + *ndx = '\0'; + // coverity[secure_coding] + if (sscanf(ndx + 1, "%d%*s", &prt) != 1) { + Debug("dns", "Unable to parse port number '%s' for nameserver '%s', discarding", ndx + 1, ns); + Warning("Unable to parse port number '%s' for nameserver '%s', discarding", ndx + 1, ns); + err = 1; + } + } + nameserver_ip[j] = ink_inet_addr(ns); + nameserver_port[j] = prt; + if ((int) nameserver_ip[j] == -1) { + Debug("dns", "Invalid IP address given for nameserver '%s', discarding", ns); + Warning("Invalid IP address given for nameserver '%s', discarding", ns); + err = 1; + } + + if (!err) { + Debug("dns", "Adding nameserver %d.%d.%d.%d:%d to nameserver list", + DOT_SEPARATED(nameserver_ip[j]), nameserver_port[j]); + ++j; + } else + nameserver_ip[j] = 0; + + ns = (char *) ink_strtok_r(NULL, " ,;\t\r", &last); + } + xfree(ns_list); + // Terminate the list for ink_res_init + nameserver_ip[j] = 0; + + // The default domain (4th param) and search list (5th param) will + // come from /etc/resolv.conf. + if (ink_res_init(&l_res, &nameserver_ip[0], &nameserver_port[0], NULL, NULL, dns_resolv_conf) < 0) + Warning("Failed to build DNS res records for the servers (%s). Using resolv.conf.", dns_ns_list); + } else { + if (ink_res_init(&l_res, NULL, NULL, NULL, NULL, dns_resolv_conf) < 0) + Warning("Failed to build DNS res records for the servers (%s). Using resolv.conf.", dns_ns_list); + } +} + +/** + Inter-OS portability for dn_expand. dn_expand() expands the compressed + domain name comp_dn to a full domain name. Expanded names are converted + to upper case. msg is a pointer to the beginning of the message, + exp_dn is a pointer to a buffer of size length for the result. The + size of compressed name is returned or -1 if there was an error. + +*/ +inline int +ink_dn_expand(const u_char *msg, const u_char *eom, const u_char *comp_dn, u_char *exp_dn, int length) +{ + return::dn_expand((unsigned char *) msg, (unsigned char *) eom, (unsigned char *) comp_dn, (char *) exp_dn, length); +} + +DNSProcessor::DNSProcessor() + : thread(NULL), handler(NULL) +{ + memset(&l_res, 0, sizeof(l_res)); +} + +void +DNSEntry::init(const char *x, int len, int qtype_arg, + Continuation *acont, DNSHandler *adnsH, int dns_lookup_timeout) +{ + qtype = qtype_arg; + submit_time = ink_get_hrtime(); + action = acont; + submit_thread = acont->mutex->thread_holding; + +#ifdef SPLIT_DNS + if (SplitDNSConfig::gsplit_dns_enabled) { + dnsH = adnsH ? adnsH : dnsProcessor.handler; + } else { + dnsH = dnsProcessor.handler; + } +#else + INK_NOWARN(adnsH); + dnsH = dnsProcessor.handler; +#endif // SPLIT_DNS + + dnsH->txn_lookup_timeout = dns_lookup_timeout; + + mutex = dnsH->mutex; + + if (qtype == T_A || qtype == T_SRV) { + if (len) { + len = len > (MAXDNAME - 1) ? (MAXDNAME - 1) : len; + memcpy(qname, x, len); + qname_len = len; + qname[len] = 0; + } else { + strncpy(qname, x, MAXDNAME); + qname[MAXDNAME - 1] = '\0'; + qname_len = strlen(qname); + } + } else { //T_PTR + char *p = qname; + unsigned char *u = (unsigned char *) x; + + if (u[3] > 99) + *p++ = (u[3] / 100) + '0'; + if (u[3] > 9) + *p++ = ((u[3] / 10) % 10) + '0'; + *p++ = u[3] % 10 + '0'; + *p++ = '.'; + if (u[2] > 99) + *p++ = (u[2] / 100) + '0'; + if (u[2] > 9) + *p++ = ((u[2] / 10) % 10) + '0'; + *p++ = u[2] % 10 + '0'; + *p++ = '.'; + if (u[1] > 99) + *p++ = (u[1] / 100) + '0'; + if (u[1] > 9) + *p++ = ((u[1] / 10) % 10) + '0'; + *p++ = u[1] % 10 + '0'; + *p++ = '.'; + if (u[0] > 99) + *p++ = (u[0] / 100) + '0'; + if (u[0] > 9) + *p++ = ((u[0] / 10) % 10) + '0'; + *p++ = u[0] % 10 + '0'; + *p++ = '.'; + ink_strncpy(p, "in-addr.arpa", MAXDNAME - (p - qname + 1)); + } + + SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent); +} + +/** + Open (and close) connections as necessary and also assures that the + epoll fd struct is properly updated. + +*/ +void +DNSHandler::open_con(unsigned int aip, int aport, bool failed, int icon) +{ + PollDescriptor *pd = get_PollDescriptor(dnsProcessor.thread); + + Debug("dns", "open_con: opening connection %d.%d.%d.%d:%d", DOT_SEPARATED(aip), aport); + + if (!icon) { + ip = aip; + port = aport; + } + + if (con[icon].fd != NO_FD) { // Remove old FD from epoll fd + con[icon].eio.stop(); + con[icon].close(); + } + + if (con[icon].connect(aip, aport, NON_BLOCKING_CONNECT, CONNECT_WITH_UDP, NON_BLOCKING, BIND_RANDOM_PORT) < 0) { + Debug("dns", "opening connection %d.%d.%d.%d:%d FAILED for %d", DOT_SEPARATED(aip), aport, icon); + if (!failed) { + if (dns_ns_rr) + rr_failure(icon); + else + failover(); + } + return; + } else { + ns_down[icon] = 0; + if (con[icon].eio.start(pd, &con[icon], EVENTIO_READ) < 0) { + Error("[iocore_dns] open_con: Failed to add %d server to epoll list\n", icon); + } else { + con[icon].num = icon; + Debug("dns", "opening connection %d.%d.%d.%d:%d SUCCEEDED for %d", DOT_SEPARATED(aip), aport, icon); + } + } +} + +/** + Initial state of the DNSHandler. Can reinitialize the running DNS + handler to a new nameserver. + +*/ +int +DNSHandler::startEvent(int event, Event *e) +{ + NOWARN_UNUSED(event); + // + // If this is for the default server, get it + // + Debug("dns", "DNSHandler::startEvent: on thread %d\n", e->ethread->id); + if (ip == DEFAULT_DOMAIN_NAME_SERVER) { + // seems that res_init always sets m_res.nscount to at least 1! + if (!m_res->nscount) + Warning("bad configurations: no nameservers given"); + struct sockaddr_in *sa = &m_res->nsaddr_list[0].sin; + ip = sa->sin_addr.s_addr; + if (!ip) + ip = ink_inet_addr("127.0.0.1"); + port = ntohs(sa->sin_port); + } + + if (!dns_handler_initialized) { + // + // If we are THE handler, open connection and configure for + // periodic execution. + // + dns_handler_initialized = 1; + SET_HANDLER(&DNSHandler::mainEvent); + if (dns_ns_rr) { + int max_nscount = m_res->nscount; + if (max_nscount > MAX_NAMED) + max_nscount = MAX_NAMED; + n_con = 0; + for (int i = 0; i < max_nscount; i++) { + struct sockaddr_in *sa = &m_res->nsaddr_list[i].sin; + ip = sa->sin_addr.s_addr; + if (ip) { + port = ntohs(sa->sin_port); + open_con(ip, port, false, n_con); + ++n_con; + Debug("dns_pas", "opened connection to %d.%d.%d.%d:%d, n_con = %d", DOT_SEPARATED(ip), port, n_con); + } + } + dns_ns_rr_init_down = 0; + } else { + open_con(ip, port); + n_con = 1; + } + e->ethread->schedule_every(this, DNS_PERIOD); + + return EVENT_CONT; + } else { + ink_assert(false); // I.e. this should never really happen + return EVENT_DONE; + } +} + +/** + Initial state of the DSNHandler. Can reinitialize the running DNS + hander to a new nameserver. +*/ +int +DNSHandler::startEvent_sdns(int event, Event *e) +{ + NOWARN_UNUSED(event); + Debug("dns", "DNSHandler::startEvent_sdns: on thread %d\n", e->ethread->id); + + if (ip == DEFAULT_DOMAIN_NAME_SERVER) { + // seems that res_init always sets m_res.nscount to at least 1! + if (!m_res->nscount) + Warning("bad nameserver config, fallback to 127.0.0.1"); + struct sockaddr_in *sa = &m_res->nsaddr_list[0].sin; + ip = sa->sin_addr.s_addr; + if (!ip) + ip = ink_inet_addr("127.0.0.1"); + port = ntohs(sa->sin_port); + } + + SET_HANDLER(&DNSHandler::mainEvent); + open_con(ip, port, false, n_con); + ++n_con; // TODO should n_con be zeroed? + + e->schedule_every(DNS_PERIOD); + return EVENT_CONT; +} + +static inline int +_ink_res_mkquery(ink_res_state res, char *qname, int qtype, char *buffer) +{ + int r = ink_res_mkquery(res, QUERY, qname, C_IN, qtype, + NULL, 0, NULL, (unsigned char *) buffer, + MAX_DNS_PACKET_LEN); + return r; +} + +void +DNSHandler::recover() +{ + Warning("connection to DNS server %d.%d.%d.%d restored", DOT_SEPARATED(ip)); + name_server = 0; + switch_named(name_server); +} + +void +DNSHandler::retry_named(int ndx, ink_hrtime t, bool reopen) +{ + if (reopen && ((t - last_primary_reopen) > DNS_PRIMARY_REOPEN_PERIOD)) { + Debug("dns", "retry_named: reopening DNS connection for index %d", ndx); + last_primary_reopen = t; + con[ndx].close(); + struct sockaddr_in *sa; + sa = &m_res->nsaddr_list[ndx].sin; + ip = sa->sin_addr.s_addr; + port = ntohs(sa->sin_port); + + open_con(ip, port, true, ndx); + } + + char buffer[MAX_DNS_PACKET_LEN]; + Debug("dns", "trying to resolve '%s' from DNS connection, ndx %d", try_server_names[try_servers], ndx); + int r = _ink_res_mkquery(m_res, try_server_names[try_servers], T_A, buffer); + try_servers = (try_servers + 1) % SIZE(try_server_names); + ink_assert(r >= 0); + if (r >= 0) { // looking for a bounce + int res = socketManager.send(con[ndx].fd, buffer, r, 0); + Debug("dns", "ping result = %d", res); + } +} + +void +DNSHandler::try_primary_named(bool reopen) +{ + ink_hrtime t = ink_get_hrtime(); + if (reopen && ((t - last_primary_reopen) > DNS_PRIMARY_REOPEN_PERIOD)) { + Debug("dns", "try_primary_named: reopening primary DNS connection"); + last_primary_reopen = t; + open_con(ip, port, true, 0); + } + if ((t - last_primary_retry) > DNS_PRIMARY_RETRY_PERIOD) { + char buffer[MAX_DNS_PACKET_LEN]; + + last_primary_retry = t; + Debug("dns", "trying to resolve '%s' from primary DNS connection", try_server_names[try_servers]); + int r = _ink_res_mkquery(m_res, try_server_names[try_servers], T_A, buffer); + // if try_server_names[] is not full, round-robin within the + // filled entries. + if (local_num_entries < DEFAULT_NUM_TRY_SERVER) + try_servers = (try_servers + 1) % local_num_entries; + else + try_servers = (try_servers + 1) % SIZE(try_server_names); + ink_assert(r >= 0); + if (r >= 0) { // looking for a bounce + int res = socketManager.send(con[0].fd, buffer, r, 0); + Debug("dns", "ping result = %d", res); + } + } +} + + +void +DNSHandler::switch_named(int ndx) +{ + for (DNSEntry *e = entries.head; e; e = (DNSEntry *) e->link.next) { + e->written_flag = 0; + if (e->retries < dns_retries) + ++(e->retries); // give them another chance + } + in_flight = 0; + received_one(ndx); // reset failover counters +} + +/** Fail over to another name server. */ +void +DNSHandler::failover() +{ + Debug("dns", "failover: initiating failover attempt, current name_server=%d", name_server); + // no hope, if we have only one server + if (m_res->nscount > 1) { + int max_nscount = m_res->nscount; + + if (max_nscount > MAX_NAMED) + max_nscount = MAX_NAMED; + unsigned int old_ip = m_res->nsaddr_list[name_server].sin.sin_addr.s_addr; + name_server = (name_server + 1) % max_nscount; + Debug("dns", "failover: failing over to name_server=%d", name_server); + + struct sockaddr_in *sa = &m_res->nsaddr_list[name_server].sin; + + Warning("failover: connection to DNS server %d.%d.%d.%d lost, move to %d.%d.%d.%d", + DOT_SEPARATED(old_ip), DOT_SEPARATED(sa->sin_addr.s_addr)); + + unsigned int tip = sa->sin_addr.s_addr; + + if (!tip) + tip = ink_inet_addr("127.0.0.1"); + open_con(tip, ntohs(sa->sin_port), true, name_server); + if (n_con <= name_server) + n_con = name_server + 1; + switch_named(name_server); + } else + Warning("failover: connection to DNS server %d.%d.%d.%d lost, retrying", DOT_SEPARATED(ip)); +} + +/** Mark one of the nameservers as down. */ +void +DNSHandler::rr_failure(int ndx) +{ + // no hope, if we have only one server + if (!ns_down[ndx]) { + // mark this nameserver as down + Debug("dns", "rr_failure: Marking nameserver %d as down", ndx); + ns_down[ndx] = 1; + + struct sockaddr_in *sa = &m_res->nsaddr_list[ndx].sin; + unsigned int tip = sa->sin_addr.s_addr; + Warning("connection to DNS server %d.%d.%d.%d lost, marking as down", DOT_SEPARATED(tip)); + } + + int nscount = m_res->nscount; + if (nscount > MAX_NAMED) + nscount = MAX_NAMED; + + // See if all nameservers are down + int all_down = 1; + + for (int i = 0; i < nscount && all_down; i++) { + Debug("dns", "nsdown[%d]=%d", i, ns_down[i]); + if (!ns_down[i]) { + all_down = 0; + } + } + + if (all_down && !dns_ns_rr_init_down) { + Warning("connection to all DNS servers lost, retrying"); + // actual retries will be done in retry_named called from mainEvent + // mark any outstanding requests as not sent for later retry + for (DNSEntry *e = entries.head; e; e = (DNSEntry *) e->link.next) { + e->written_flag = 0; + if (e->retries < dns_retries) + ++(e->retries); // give them another chance + --in_flight; + DNS_DECREMENT_DYN_STAT(dns_in_flight_stat); + } + } else { + // move outstanding requests that were sent to this nameserver to another + for (DNSEntry *e = entries.head; e; e = (DNSEntry *) e->link.next) { + if (e->which_ns == ndx) { + e->written_flag = 0; + if (e->retries < dns_retries) + ++(e->retries); // give them another chance + --in_flight; + DNS_DECREMENT_DYN_STAT(dns_in_flight_stat); + } + } + } +} + +static bool +good_rcode(char *buf) +{ + HEADER *h = (HEADER *) buf; + switch (h->rcode) { + default: + return false; + case NOERROR: + case NXDOMAIN: + return true; + } +} + + +void +DNSHandler::recv_dns(int event, Event *e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + DNSConnection *dnsc = NULL; + + while ((dnsc = (DNSConnection *) triggered.dequeue())) { + while (1) { + struct sockaddr_in sa_from; + socklen_t sa_length = sizeof(sa_from); // TODO: I'm guessing when we support IPv6,this will have to change. + + if (!hostent_cache) + hostent_cache = dnsBufAllocator.alloc(); + HostEnt *buf = hostent_cache; + + int res = socketManager.recvfrom(dnsc->fd, buf->buf, MAX_DNS_PACKET_LEN, 0, (struct sockaddr *) &sa_from, &sa_length); + + if (res == -EAGAIN) + break; + if (res <= 0) { + Debug("dns", "named error: %d", res); + if (dns_ns_rr) + rr_failure(dnsc->num); + else if (dnsc->num == name_server) + failover(); + break; + } + + // verify that this response came from the correct server + if (dnsc->sa.sin_addr.s_addr != sa_from.sin_addr.s_addr) { + Warning("received DNS response from unexpected named %d.%d.%d.%d", DOT_SEPARATED(sa_from.sin_addr.s_addr)); + continue; + } + hostent_cache = 0; + buf->packet_size = res; + Debug("dns", "received packet size = %d", res); + if (dns_ns_rr) { + Debug("dns", "round-robin: nameserver %d DNS response code = %d", dnsc->num, ((HEADER *) buf->buf)->rcode); + if (good_rcode(buf->buf)) { + received_one(dnsc->num); + if (ns_down[dnsc->num]) { + struct sockaddr_in *sa = &m_res->nsaddr_list[dnsc->num].sin; + + Warning("connection to DNS server %d.%d.%d.%d restored", DOT_SEPARATED(sa->sin_addr.s_addr)); + ns_down[dnsc->num] = 0; + } + } + } else { + if (!dnsc->num) { + Debug("dns", "primary DNS response code = %d", ((HEADER *) buf->buf)->rcode); + if (good_rcode(buf->buf)) { + if (name_server) + recover(); + else + received_one(name_server); + } + } + } + Ptr protect_hostent = buf; + if (dns_process(this, buf, res)) { + if (dnsc->num == name_server) + received_one(name_server); + } + hostent_cache = protect_hostent.to_ptr(); + } + } +} + +/** Main event for the DNSHandler. Attempt to read from and write to named. */ +int +DNSHandler::mainEvent(int event, Event *e) +{ + recv_dns(event, e); + if (dns_ns_rr) { + ink_hrtime t = ink_get_hrtime(); + if (t - last_primary_retry > DNS_PRIMARY_RETRY_PERIOD) { + for (int i = 0; i < n_con; i++) { + if (ns_down[i]) { + Debug("dns", "mainEvent: nameserver = %d is down", i); + retry_named(i, t, true); + } + } + last_primary_retry = t; + } + for (int i = 0; i < n_con; i++) { + if (!ns_down[i] && failover_soon(i)) { + Debug("dns", "mainEvent: nameserver = %d failover soon", name_server); + if (failover_now(i)) + rr_failure(i); + else { + Debug("dns", "mainEvent: nameserver = %d no failover now - retrying", i); + retry_named(i, t, false); + ++failover_soon_number[i]; + } + } + } + } else { + if (failover_soon(name_server)) { + Debug("dns", "mainEvent: will failover soon"); + if (failover_now(name_server)) { + Debug("dns", "mainEvent: failing over now to another nameserver"); + failover(); + } else { + try_primary_named(false); + ++failover_soon_number[name_server]; + } + } else if (name_server) // not on the primary named + try_primary_named(true); + } + + if (entries.head) + write_dns(this); + + return EVENT_CONT; +} + +/** Find a DNSEntry by id. */ +inline static DNSEntry * +get_dns(DNSHandler *h, uint16_t id) +{ + for (DNSEntry *e = h->entries.head; e; e = (DNSEntry *) e->link.next) { + if (e->once_written_flag) { + for (int j = 0; j < MAX_DNS_RETRIES; j++) { + if (e->id[j] == id) { + return e; + } else if (e->id[j] < 0) { + goto Lnext; + } + } + } + Lnext:; + } + return NULL; +} + +/** Find a DNSEntry by query name and type. */ +inline static DNSEntry * +get_entry(DNSHandler *h, char *qname, int qtype) +{ + for (DNSEntry *e = h->entries.head; e; e = (DNSEntry *) e->link.next) { + if (e->qtype == qtype) { + if (qtype == T_A) { + if (!strcmp(qname, e->qname)) + return e; + } else if (*(unsigned int *) qname == *(unsigned int *) e->qname) + return e; + } + } + return NULL; +} + +/** Write up to dns_max_dns_in_flight entries. */ +static void +write_dns(DNSHandler *h) +{ + ProxyMutex *mutex = h->mutex; + DNS_INCREMENT_DYN_STAT(dns_total_lookups_stat); + int max_nscount = h->m_res->nscount; + if (max_nscount > MAX_NAMED) + max_nscount = MAX_NAMED; + + if (h->in_write_dns) + return; + h->in_write_dns = true; + // Debug("dns", "in_flight: %d, dns_max_dns_in_flight: %d", h->in_flight, dns_max_dns_in_flight); + if (h->in_flight < dns_max_dns_in_flight) { + DNSEntry *e = h->entries.head; + while (e) { + DNSEntry *n = (DNSEntry *) e->link.next; + if (!e->written_flag) { + if (dns_ns_rr) { + int ns_start = h->name_server; + do { + h->name_server = (h->name_server + 1) % max_nscount; + } while (h->ns_down[h->name_server] && h->name_server != ns_start); + } + if (!write_dns_event(h, e)) + break; + } + if (h->in_flight >= dns_max_dns_in_flight) + break; + e = n; + } + } + h->in_write_dns = false; +} + +uint16_t +DNSHandler::get_query_id() +{ + uint16_t q1, q2; + q2 = q1 = (uint16_t)(generator.random() & 0xFFFF); + if (query_id_in_use(q2)) { + uint16_t i = q2>>6; + while (qid_in_flight[i] == INTU64_MAX) { + if (++i == sizeof(qid_in_flight)/sizeof(uint64_t)) { + i = 0; + } + if (i == q1>>6) { + Error("[iocore_dns] get_query_id: Exhausted all DNS query ids"); + return q1; + } + } + i <<= 6; + q2 &= 0x3F; + while (query_id_in_use(i+q2)) { + ++q2; + q2 &= 0x3F; + if (q2 == (q1 & 0x3F)) { + Error("[iocore_dns] get_query_id: Exhausted all DNS query ids"); + return q1; + } + } + q2 += i; + } + + set_query_id_in_use(q2); + return q2; +} + +/** + Construct and Write the request for a single entry (using send(3N)). + + @return true = keep going, false = give up for now. + +*/ +static bool +write_dns_event(DNSHandler *h, DNSEntry *e) +{ + ProxyMutex *mutex = h->mutex; + char buffer[MAX_DNS_PACKET_LEN]; + int r = 0; + + if ((r = _ink_res_mkquery(h->m_res, e->qname, e->qtype, buffer)) <= 0) { + Debug("dns", "cannot build query: %s", e->qname); + dns_result(h, e, NULL, false); + return true; + } + + uint16_t i = h->get_query_id(); + ((HEADER *) (buffer))->id = htons(i); + if (e->id[dns_retries - e->retries] >= 0) { + //clear previous id in case named was switched or domain was expanded + h->release_query_id(e->id[dns_retries - e->retries]); + } + e->id[dns_retries - e->retries] = i; + Debug("dns", "send query for %s to fd %d", e->qname, h->con[h->name_server].fd); + + int s = socketManager.send(h->con[h->name_server].fd, buffer, r, 0); + if (s != r) { + Debug("dns", "send() failed: qname = %s, %d != %d, nameserver= %d", e->qname, s, r, h->name_server); + // changed if condition from 'r < 0' to 's < 0' - 8/2001 pas + if (s < 0) { + if (dns_ns_rr) + h->rr_failure(h->name_server); + else + h->failover(); + } + return false; + } + + e->written_flag = true; + e->which_ns = h->name_server; + e->once_written_flag = true; + ++h->in_flight; + DNS_INCREMENT_DYN_STAT(dns_in_flight_stat); + + e->send_time = ink_get_hrtime(); + + if (e->timeout) + e->timeout->cancel(); + + if (h->txn_lookup_timeout) { + e->timeout = h->mutex->thread_holding->schedule_in(e, HRTIME_MSECONDS(h->txn_lookup_timeout)); //this is in msec + } else { + e->timeout = h->mutex->thread_holding->schedule_in(e, HRTIME_SECONDS(dns_timeout)); + } + + Debug("dns", "sent qname = %s, id = %u, nameserver = %d", e->qname, e->id[dns_retries - e->retries], h->name_server); + h->sent_one(); + return true; +} + + +int +DNSEntry::delayEvent(int event, Event *e) +{ + (void) event; + if (dnsProcessor.handler) { + SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent); + return handleEvent(EVENT_IMMEDIATE, e); + } + e->schedule_in(DNS_DELAY_PERIOD); + return EVENT_CONT; +} + +/** Handle timeout events. */ +int +DNSEntry::mainEvent(int event, Event *e) +{ + switch (event) { + default: + ink_assert(!"bad case"); + return EVENT_DONE; + case EVENT_IMMEDIATE:{ + if (!dnsH) + dnsH = dnsProcessor.handler; + if (!dnsH) { + Debug("dns", "handler not found, retrying..."); + SET_HANDLER((DNSEntryHandler) & DNSEntry::delayEvent); + return handleEvent(event, e); + } + //if (dns_search && !strnchr(qname,'.',MAXDNAME)){ + if (dns_search) + domains = dnsH->m_res->dnsrch; + if (domains && !strnchr(qname, '.', MAXDNAME)) { + qname[qname_len] = '.'; + ink_strncpy(qname + qname_len + 1, *domains, MAXDNAME - (qname_len + 1)); + qname_len = strlen(qname); + ++domains; + } + Debug("dns", "enqueing query %s", qname); + DNSEntry *dup = get_entry(dnsH, qname, qtype); + if (dup) { + Debug("dns", "collapsing NS request"); + dup->dups.enqueue(this); + } else { + Debug("dns", "adding first to collapsing queue"); + dnsH->entries.enqueue(this); + write_dns(dnsH); + } + return EVENT_DONE; + } + case EVENT_INTERVAL: + Debug("dns", "timeout for query %s", qname); + if (dnsH->txn_lookup_timeout) { + timeout = NULL; + dns_result(dnsH, this, result_ent, false); //do not retry -- we are over TXN timeout on DNS alone! + return EVENT_DONE; + } + if (written_flag) { + Debug("dns", "marking %s as not-written", qname); + written_flag = false; + --(dnsH->in_flight); + DNS_DECREMENT_DYN_STAT(dns_in_flight_stat); + } + timeout = NULL; + dns_result(dnsH, this, result_ent, true); + return EVENT_DONE; + } +} + +Action * +DNSProcessor::getby(const char *x, int len, int type, Continuation *cont, DNSHandler *adnsH, int timeout) { + Debug("dns", "received query %s type = %d, timeout = %d", x, type, timeout); + if (type == T_SRV) { + Debug("dns_srv", "DNSProcessor::getby attempting an SRV lookup for %s, timeout = %d", x, timeout); + } + DNSEntry *e = dnsEntryAllocator.alloc(); + e->retries = dns_retries; + e->init(x, len, type, cont, adnsH, timeout); + MUTEX_TRY_LOCK(lock, e->mutex, this_ethread()); + if (!lock) + thread->schedule_imm(e); + else + e->handleEvent(EVENT_IMMEDIATE, 0); + return &e->action; +} + +/** + We have a result for an entry, return it to the user or retry if it + is a retry-able and we have retries left. +*/ +static void +dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry) { + ProxyMutex *mutex = h->mutex; + bool cancelled = (e->action.cancelled ? true : false); + + if (!ent && !cancelled) { + // try to retry operation + if (retry && e->retries) { + Debug("dns", "doing retry for %s", e->qname); + + DNS_INCREMENT_DYN_STAT(dns_retries_stat); + + --(e->retries); + write_dns(h); + return; + } else if (e->domains && *e->domains) { + do { + Debug("dns", "domain extending %s", e->qname); + //int l = _strlen(e->qname); + char *dot = strchr(e->qname, '.'); + if (dot) { + if (e->qname_len + strlen(*e->domains) + 2 > MAXDNAME) { + Debug("dns", "domain too large %s + %s", e->qname, *e->domains); + goto LnextDomain; + } + if (e->qname[e->qname_len - 1] != '.') { + e->qname[e->qname_len] = '.'; + ink_strncpy(e->qname + e->qname_len + 1, *e->domains, MAXDNAME - (e->qname_len + 1)); + e->qname_len = strlen(e->qname); + } else { + ink_strncpy(e->qname + e->qname_len, *e->domains, MAXDNAME - e->qname_len); + e->qname_len = strlen(e->qname); + } + } else { + if (e->qname_len + strlen(*e->domains) + 2 > MAXDNAME) { + Debug("dns", "domain too large %s + %s", e->qname, *e->domains); + goto LnextDomain; + } + e->qname[e->qname_len] = '.'; + ink_strncpy(e->qname + e->qname_len + 1, *e->domains, MAXDNAME - (e->qname_len + 1)); + e->qname_len = strlen(e->qname); + } + ++(e->domains); + e->retries = dns_retries; + Debug("dns", "new name = %s retries = %d", e->qname, e->retries); + write_dns(h); + return; + LnextDomain: + ++(e->domains); + } while (*e->domains); + } else { + e->qname[e->qname_len] = 0; + if (!strchr(e->qname, '.') && !e->last) { + e->last = true; + write_dns(h); + return; + } + } + if (retry) { + DNS_INCREMENT_DYN_STAT(dns_max_retries_exceeded_stat); + } + } + if (ent == BAD_DNS_RESULT) + ent = NULL; + if (!cancelled) { + if (!ent) { + DNS_SUM_DYN_STAT(dns_fail_time_stat, ink_get_hrtime() - e->submit_time); + } else { + DNS_SUM_DYN_STAT(dns_success_time_stat, ink_get_hrtime() - e->submit_time); + } + } + h->entries.remove(e); + + if (e->qtype == T_A) { + unsigned int tip = ent != NULL ? *(unsigned int *) ent->ent.h_addr_list[0] : 0; + Debug("dns", "%s result for %s = %d.%d.%d.%d retry %d", + ent ? "SUCCESS" : "FAIL", e->qname, DOT_SEPARATED(tip), retry); + } else { + Debug("dns", "%s result for %s = %s retry %d", + ent ? "SUCCESS" : "FAIL", e->qname, (ent != NULL ? ent->ent.h_name : ""), retry); + } + + if (ent) { + DNS_INCREMENT_DYN_STAT(dns_lookup_success_stat); + } else { + DNS_INCREMENT_DYN_STAT(dns_lookup_fail_stat); + } + + DNSEntry *dup = NULL; + while ((dup = e->dups.dequeue())) { + if (dup->post(h, ent)) { + e->dups.enqueue(dup); + goto Lretry; + } + } + if (!e->post(h, ent)) { + for (int i = 0; i < MAX_DNS_RETRIES; i++) { + if (e->id[i] < 0) + break; + h->release_query_id(e->id[i]); + } + return; + } +Lretry: + e->result_ent = ent; + e->retries = 0; + if (e->timeout) + e->timeout->cancel(); + e->timeout = h->mutex->thread_holding->schedule_in(e, DNS_PERIOD); +} + +int +DNSEntry::post(DNSHandler *h, HostEnt *ent) +{ + if (timeout) { + timeout->cancel(this); + timeout = NULL; + } + result_ent = ent; + if (h->mutex->thread_holding == submit_thread) { + MUTEX_TRY_LOCK(lock, action.mutex, h->mutex->thread_holding); + if (!lock) { + Debug("dns", "failed lock for result %s", qname); + return 1; + } + postEvent(0, 0); + } else { + mutex = action.mutex; + SET_HANDLER(&DNSEntry::postEvent); + submit_thread->schedule_imm_signal(this); + } + return 0; +} + +int +DNSEntry::postEvent(int event, Event *e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + if (!action.cancelled) { + Debug("dns", "called back continuation for %s", qname); + action.continuation->handleEvent(DNS_EVENT_LOOKUP, result_ent); + } + result_ent = NULL; + action.mutex = NULL; + mutex = NULL; + dnsEntryAllocator.free(this); + return EVENT_DONE; +} + +/** Decode the reply from "named". */ +static bool +dns_process(DNSHandler *handler, HostEnt *buf, int len) +{ + ProxyMutex *mutex = handler->mutex; + HEADER *h = (HEADER *) (buf->buf); + DNSEntry *e = get_dns(handler, (uint16_t) ntohs(h->id)); + bool retry = false; + bool server_ok = true; + uint32_t temp_ttl = 0; + + // + // Do we have an entry for this id? + // + if (!e || !e->written_flag) { + Debug("dns", "unknown DNS id = %u", (uint16_t) ntohs(h->id)); + return false; // cannot count this as a success + } + // + // It is no longer in flight + // + e->written_flag = false; + --(handler->in_flight); + DNS_DECREMENT_DYN_STAT(dns_in_flight_stat); + + DNS_SUM_DYN_STAT(dns_response_time_stat, ink_get_hrtime() - e->send_time); + + if (h->rcode != NOERROR || !h->ancount) { + Debug("dns", "received rcode = %d", h->rcode); + switch (h->rcode) { + default: + Warning("Unknown DNS error %d for [%s]", h->rcode, e->qname); + retry = true; + server_ok = false; // could be server problems + goto Lerror; + case SERVFAIL: // recoverable error + retry = true; + case FORMERR: // unrecoverable errors + case REFUSED: + case NOTIMP: + Debug("dns", "DNS error %d for [%s]", h->rcode, e->qname); + server_ok = false; // could be server problems + goto Lerror; + case NOERROR: + case NXDOMAIN: + case 6: // YXDOMAIN + case 7: // YXRRSET + case 8: // NOTAUTH + case 9: // NOTAUTH + case 10: // NOTZONE + Debug("dns", "DNS error %d for [%s]", h->rcode, e->qname); + goto Lerror; + } + } else { + + // + // Initialize local data + // + // struct in_addr host_addr; unused + u_char tbuf[MAXDNAME + 1]; + buf->ent.h_name = NULL; + + int ancount = ntohs(h->ancount); + unsigned char *bp = buf->hostbuf; + int buflen = sizeof(buf->hostbuf); + u_char *cp = ((u_char *) h) + HFIXEDSZ; + u_char *eom = (u_char *) h + len; + int n; + unsigned char *srv[50]; + int num_srv = 0; + int rname_len = -1; + + // + // Expand name + // + if ((n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen)) < 0) + goto Lerror; + + // Should we validate the query name? + if (dns_validate_qname) { + int qlen = e->qname_len; + int rlen = strlen((char *)bp); + + rname_len = rlen; // Save for later use + if ((qlen > 0) && ('.' == e->qname[qlen-1])) + --qlen; + if ((rlen > 0) && ('.' == bp[rlen-1])) + --rlen; + // TODO: At some point, we might want to care about the case here, and use an algorithm + // to randomly pick upper case characters in the query, and validate the response with + // case sensitivity. + if ((qlen != rlen) || (strncasecmp(e->qname, (const char*)bp, qlen) != 0)) { + // Bad mojo, forged? + Warning("received DNS response with query name of '%s', but response query name is '%s'", e->qname, bp); + goto Lerror; + } else { + Debug("dns", "query name validated properly for %s", e->qname); + } + } + + cp += n + QFIXEDSZ; + if (e->qtype == T_A) { + if (-1 == rname_len) + n = strlen((char *)bp) + 1; + else + n = rname_len + 1; + buf->ent.h_name = (char *) bp; + bp += n; + buflen -= n; + } + // + // Configure HostEnt data structure + // + u_char **ap = buf->host_aliases; + buf->ent.h_aliases = (char **) buf->host_aliases; + u_char **hap = (u_char **) buf->h_addr_ptrs; + *hap = NULL; + buf->ent.h_addr_list = (char **) buf->h_addr_ptrs; + + // + // INKqa10938: For customer (i.e. USPS) with closed environment, need to + // build up try_server_names[] with names already successfully resolved. + // try_server_names[] gets filled up with every success dns response. + // Once it's full, a new entry get inputted into try_server_names round- + // robin style every 50 success dns response. + + // TODO: Why do we do strlen(e->qname) ? That should be available in + // e->qname_len, no ? + if (local_num_entries >= DEFAULT_NUM_TRY_SERVER) { + if ((attempt_num_entries % 50) == 0) { + try_servers = (try_servers + 1) % SIZE(try_server_names); + strncpy(try_server_names[try_servers], e->qname, strlen(e->qname)); + memset(&try_server_names[try_servers][strlen(e->qname)], 0, 1); + attempt_num_entries = 0; + } + ++attempt_num_entries; + } else { + // fill up try_server_names for try_primary_named + try_servers = local_num_entries++; + strncpy(try_server_names[try_servers], e->qname, strlen(e->qname)); + memset(&try_server_names[try_servers][strlen(e->qname)], 0, 1); + } + + /* added for SRV support [ebalsa] + this skips the query section (qdcount) + */ + unsigned char *here = (unsigned char *) buf->buf + HFIXEDSZ; + if (e->qtype == T_SRV) { + for (int ctr = ntohs(h->qdcount); ctr > 0; ctr--) { + int strlen = dn_skipname(here, eom); + here += strlen + QFIXEDSZ; + } + } + // + // Decode each answer + // + int answer = false, error = false; + + while (ancount-- > 0 && cp < eom && !error) { + n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen); + if (n < 0) { + ++error; + break; + } + cp += n; + short int type; + GETSHORT(type, cp); + cp += NS_INT16SZ; // GETSHORT(cls, cp); + GETLONG(temp_ttl, cp); // NOTE: this is not a "long" but 32-bits (from nameser_compat.h) + if ((temp_ttl < buf->ttl) || (buf->ttl == 0)) + buf->ttl = temp_ttl; + GETSHORT(n, cp); + + // + // Decode cname + // + if (e->qtype == T_A && type == T_CNAME) { + if (ap >= &buf->host_aliases[DNS_MAX_ALIASES - 1]) + continue; + n = ink_dn_expand((u_char *) h, eom, cp, tbuf, sizeof(tbuf)); + if (n < 0) { + ++error; + break; + } + cp += n; + *ap++ = (unsigned char *) bp; + n = strlen((char *) bp) + 1; + bp += n; + buflen -= n; + n = strlen((char *) tbuf) + 1; + if (n > buflen) { + ++error; + break; + } + ink_strncpy((char *) bp, (char *) tbuf, buflen); + bp += n; + buflen -= n; + Debug("dns", "received cname = %s", tbuf); + continue; + } + if (e->qtype != type) { + ++error; + break; + } + // + // Decode names + // + if (type == T_PTR) { + n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen); + if (n < 0) { + ++error; + break; + } + cp += n; + if (!answer) { + buf->ent.h_name = (char *) bp; + Debug("dns", "received PTR name = %s", bp); + n = strlen((char *) bp) + 1; + bp += n; + buflen -= n; + } else if (ap < &buf->host_aliases[DNS_MAX_ALIASES - 1]) { + *ap++ = bp; + Debug("dns", "received PTR alias = %s", bp); + n = strlen((char *) bp) + 1; + bp += n; + buflen -= n; + } + } else if (type == T_SRV) { + cp = here; /* hack */ + int strlen = dn_skipname(cp, eom); + cp += strlen; + srv[num_srv] = cp; + cp += SRV_FIXEDSZ; + cp += dn_skipname(cp, eom); + here = cp; /* hack */ + char srvname[MAXDNAME]; + int r = ink_ns_name_ntop(srv[num_srv] + SRV_SERVER, srvname, MAXDNAME); + if (r <= 0) { + /* FIXME: is this really an error? or just a continue; */ + ++error; + goto Lerror; + } + Debug("dns_srv", "Discovered SRV record [from NS lookup] with cost:%d weight:%d port:%d with host:%s", + ink_get16(srv[num_srv] + SRV_COST), + ink_get16(srv[num_srv] + SRV_WEIGHT), ink_get16(srv[num_srv] + SRV_PORT), srvname); + + SRV *s = SRVAllocator.alloc(); + s->setPort(ink_get16(srv[num_srv] + SRV_PORT)); + s->setPriority(ink_get16(srv[num_srv] + SRV_COST)); + s->setWeight(ink_get16(srv[num_srv] + SRV_WEIGHT)); + s->setHost(srvname); + + buf->srv_hosts.insert(s); + ++num_srv; + } else if (type == T_A) { + if (answer) { + if (n != buf->ent.h_length) { + cp += n; + continue; + } + } else { + int nn; + buf->ent.h_length = n; + buf->ent.h_addrtype = C_IN; + buf->ent.h_name = (char *) bp; + nn = strlen((char *) bp) + 1; + Debug("dns", "received A name = %s", bp); + bp += nn; + buflen -= nn; + } + // attempt to use the original buffer (if it is word aligned) + if (!(((uintptr_t) cp) % sizeof(unsigned int))) { + *hap++ = cp; + cp += n; + } else { + bp = (unsigned char *) align_pointer_forward(bp, sizeof(int)); + if (bp + n >= buf->hostbuf + DNS_HOSTBUF_SIZE) { + ++error; + break; + } + memcpy((*hap++ = bp), cp, n); + Debug("dns", "received A = %d.%d.%d.%d", DOT_SEPARATED(*(unsigned int *) bp)); + bp += n; + cp += n; + } + } else + goto Lerror; + ++answer; + } + if (answer) { + *ap = NULL; + *hap = NULL; + // + // If the named didn't send us the name, insert the one + // the user gave us... + // + if (!buf->ent.h_name) { + Debug("dns", "inserting name = %s", e->qname); + ink_strncpy((char *) bp, e->qname, sizeof(buf->hostbuf) - (bp - buf->hostbuf)); + buf->ent.h_name = (char *) bp; + } + dns_result(handler, e, buf, retry); + return server_ok; + } + } +Lerror:; + DNS_INCREMENT_DYN_STAT(dns_lookup_fail_stat); + dns_result(handler, e, NULL, retry); + return server_ok; +} + + +RecRawStatBlock *dns_rsb; + +void +ink_dns_init(ModuleVersion v) +{ + static int init_called = 0; + + Debug("dns", "ink_dns_init: called with init_called = %d", init_called); + + ink_release_assert(!checkModuleVersion(v, HOSTDB_MODULE_VERSION)); + if (init_called) + return; + + init_called = 1; + // do one time stuff + // create a stat block for HostDBStats + dns_rsb = RecAllocateRawStatBlock((int) DNS_Stat_Count); + + // + // Register statistics callbacks + // + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.total_dns_lookups", + RECD_INT, RECP_NULL, (int) dns_total_lookups_stat, RecRawStatSyncSum); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.lookup_avg_time", + RECD_INT, RECP_NULL, (int) dns_response_time_stat, RecRawStatSyncHrTimeAvg); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.success_avg_time", + RECD_INT, RECP_NON_PERSISTENT, (int) dns_success_time_stat, RecRawStatSyncHrTimeAvg); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.lookup_successes", + RECD_INT, RECP_NULL, (int) dns_lookup_success_stat, RecRawStatSyncSum); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.fail_avg_time", + RECD_INT, RECP_NULL, (int) dns_fail_time_stat, RecRawStatSyncHrTimeAvg); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.lookup_failures", + RECD_INT, RECP_NULL, (int) dns_lookup_fail_stat, RecRawStatSyncSum); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.retries", RECD_INT, RECP_NULL, (int) dns_retries_stat, RecRawStatSyncSum); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.max_retries_exceeded", + RECD_INT, RECP_NULL, (int) dns_max_retries_exceeded_stat, RecRawStatSyncSum); + + RecRegisterRawStat(dns_rsb, RECT_PROCESS, + "proxy.process.dns.in_flight", + RECD_INT, RECP_NON_PERSISTENT, (int) dns_in_flight_stat, RecRawStatSyncSum); + +} + + +#ifdef TS_HAS_TESTS +struct DNSRegressionContinuation; +typedef int (DNSRegressionContinuation::*DNSRegContHandler) (int, void *); + +struct DNSRegressionContinuation: public Continuation +{ + int hosts; + const char **hostnames; + int type; + int *status; + int found; + int tofind; + int i; + RegressionTest *test; + + int mainEvent(int event, HostEnt *he) + { + (void) event; + if (event == DNS_EVENT_LOOKUP) { + if (he) { + struct in_addr in; + ++found; + in.s_addr = *(unsigned int *) he->ent.h_addr_list[0]; + rprintf(test, "host %s [%s] = %s\n", hostnames[i - 1], he->ent.h_name, inet_ntoa(in)); + } else { + rprintf(test, "host %s not found\n", hostnames[i - 1]); + } + } + if (i < hosts) { + dnsProcessor.gethostbyname(this, hostnames[i]); + ++i; + return EVENT_CONT; + } else { + if (found == tofind) + *status = REGRESSION_TEST_PASSED; + else + *status = REGRESSION_TEST_FAILED; + return EVENT_DONE; + } + } + + DNSRegressionContinuation(int ahosts, int atofind, const char **ahostnames, RegressionTest *t, int atype, int *astatus) + : Continuation(new_ProxyMutex()), hosts(ahosts), hostnames(ahostnames), type(atype), + status(astatus), found(0), tofind(atofind), i(0), test(t) { + SET_HANDLER((DNSRegContHandler) & DNSRegressionContinuation::mainEvent); + } +}; + +static const char *dns_test_hosts[] = { + "www.apple.com", + "www.ibm.com", + "www.microsoft.com", + "www.coke.com" +}; + +REGRESSION_TEST(DNS) (RegressionTest *t, int atype, int *pstatus) { + eventProcessor.schedule_in(NEW(new DNSRegressionContinuation(4, 4, dns_test_hosts, t, atype, pstatus)), + HRTIME_SECONDS(1)); +} + +#endif diff --git a/iocore/dns/DNSConnection.cc b/iocore/dns/DNSConnection.cc new file mode 100644 index 00000000..bc5a267f --- /dev/null +++ b/iocore/dns/DNSConnection.cc @@ -0,0 +1,161 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + Connections + + Commonality across all platforms -- move out as required. + +**************************************************************************/ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "P_DNS.h" +#include "P_DNSConnection.h" +#include "P_DNSProcessor.h" + +#define SET_TCP_NO_DELAY +#define SET_NO_LINGER +// set in the OS +// #define RECV_BUF_SIZE (1024*64) +// #define SEND_BUF_SIZE (1024*64) +#define FIRST_RANDOM_PORT (16000) +#define LAST_RANDOM_PORT (60000) + +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) + +// +// Functions +// + +DNSConnection::DNSConnection(): + fd(NO_FD), num(0), generator((uint32_t)((uintptr_t)time(NULL) ^ (uintptr_t) this)), handler(NULL) +{ + memset(&sa, 0, sizeof(struct sockaddr_in)); +} + +DNSConnection::~DNSConnection() +{ + close(); +} + +int +DNSConnection::close() +{ + // don't close any of the standards + if (fd >= 2) { + int fd_save = fd; + fd = NO_FD; + return socketManager.close(fd_save); + } else { + fd = NO_FD; + return -EBADF; + } +} + +void +DNSConnection::trigger() +{ + handler->triggered.enqueue(this); +} + +int +DNSConnection::connect(unsigned int ip, int port, + bool non_blocking_connect, bool use_tcp, bool non_blocking, bool bind_random_port) +{ + ink_assert(fd == NO_FD); + + int res = 0; + short Proto; + + if (use_tcp) { + Proto = IPPROTO_TCP; + if ((res = socketManager.socket(AF_INET, SOCK_STREAM, 0)) < 0) + goto Lerror; + } else { + Proto = IPPROTO_UDP; + if ((res = socketManager.socket(AF_INET, SOCK_DGRAM, 0)) < 0) + goto Lerror; + } + + fd = res; + + if (bind_random_port) { + int retries = 0; + while (retries++ < 10000) { + struct sockaddr_in bind_sa; + memset(&sa, 0, sizeof(bind_sa)); + bind_sa.sin_family = AF_INET; + bind_sa.sin_addr.s_addr = INADDR_ANY; + uint32_t p = generator.random(); + p = (uint16_t)((p % (LAST_RANDOM_PORT - FIRST_RANDOM_PORT)) + FIRST_RANDOM_PORT); + bind_sa.sin_port = htons(p); + Debug("dns", "random port = %u\n", p); + if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &bind_sa, sizeof(bind_sa), Proto)) < 0) { + continue; + } + goto Lok; + } + Warning("unable to bind random DNS port"); + Lok:; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = ip; + memset(&sa.sin_zero, 0, 8); + + if (non_blocking_connect) + if ((res = safe_nonblocking(fd)) < 0) + goto Lerror; + + // cannot do this after connection on non-blocking connect +#ifdef SET_TCP_NO_DELAY + if (use_tcp) + if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0) + goto Lerror; +#endif +#ifdef RECV_BUF_SIZE + socketManager.set_rcvbuf_size(fd, RECV_BUF_SIZE); +#endif +#ifdef SET_SO_KEEPALIVE + // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0) + goto Lerror; +#endif + + res =::connect(fd, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)); + + if (!res || ((res < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK))) { + if (!non_blocking_connect && non_blocking) + if ((res = safe_nonblocking(fd)) < 0) + goto Lerror; + } else + goto Lerror; + + return 0; + +Lerror: + if (fd != NO_FD) + close(); + return res; +} diff --git a/iocore/dns/I_DNS.h b/iocore/dns/I_DNS.h new file mode 100644 index 00000000..52ab535a --- /dev/null +++ b/iocore/dns/I_DNS.h @@ -0,0 +1,44 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + DNS.h + + + ****************************************************************************/ + + +#ifndef _I_DNS_h_ +#define _I_DNS_h_ + +#ifndef TS_INLINE +#define TS_INLINE +#endif + +#include "I_EventSystem.h" +#include "I_HostDB.h" +#include "I_Net.h" +#include "I_DNSProcessor.h" + +#endif //_I_DNS_h_ diff --git a/iocore/dns/I_DNSProcessor.h b/iocore/dns/I_DNSProcessor.h new file mode 100644 index 00000000..cac7c9b9 --- /dev/null +++ b/iocore/dns/I_DNSProcessor.h @@ -0,0 +1,140 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_DNSProcessor_h_ +#define _I_DNSProcessor_h_ + +#include "SRV.h" + +#define MAX_DNS_PACKET_LEN 8192 +#define DNS_MAX_ALIASES 35 +#define DNS_MAX_ADDRS 35 +#define DNS_HOSTBUF_SIZE 8192 +#define DOMAIN_SERVICE_PORT 53 +#define DEFAULT_DOMAIN_NAME_SERVER 0 // use the default server + + +/** + All buffering required to handle a DNS receipt. For asynchronous DNS, + only one HostEntBuf will exist in the system. For synchronous DNS, + one will exist per call until the user deletes them. + +*/ +struct HostEnt : RefCountObj { + struct hostent ent; + uint32_t ttl; + int packet_size; + char buf[MAX_DNS_PACKET_LEN]; + u_char *host_aliases[DNS_MAX_ALIASES]; + u_char *h_addr_ptrs[DNS_MAX_ADDRS + 1]; + u_char hostbuf[DNS_HOSTBUF_SIZE]; + + SRVHosts srv_hosts; + + virtual void free(); + + HostEnt() { + size_t base = sizeof(force_VFPT_to_top); // preserve VFPT + memset(((char*)this) + base, 0, sizeof(*this) - base); + } +}; + +extern EventType ET_DNS; + +struct DNSHandler; + +struct DNSProcessor: public Processor +{ + // Public Interface + // + + // DNS lookup + // calls: cont->handleEvent( DNS_EVENT_LOOKUP, HostEnt *ent) on success + // cont->handleEvent( DNS_EVENT_LOOKUP, NULL) on failure + // NOTE: the HostEnt *block is freed when the function returns + // + + Action *gethostbyname(Continuation *cont, const char *name, DNSHandler *adnsH = 0, int timeout = 0); + Action *getSRVbyname(Continuation *cont, const char *name, DNSHandler *adnsH = 0, int timeout = 0); + Action *gethostbyname(Continuation *cont, const char *name, int len, int timeout = 0); + Action *gethostbyaddr(Continuation *cont, unsigned int ip, int timeout = 0); + + + // Processor API + // + /* currently dns system uses event threads + * dont pass any value to the call */ + int start(int no_of_extra_dns_threads = 0); + + // Open/close a link to a 'named' (done in start()) + // + void open(unsigned int ip = DEFAULT_DOMAIN_NAME_SERVER, int port = DOMAIN_SERVICE_PORT, int options = _res.options); + + DNSProcessor(); + + // private: + // + EThread *thread; + DNSHandler *handler; + __ink_res_state l_res; + Action *getby(const char *x, int len, int type, Continuation *cont, DNSHandler *adnsH = NULL, int timeout = 0); + void dns_init(); +}; + + +// +// Global data +// +extern DNSProcessor dnsProcessor; + +// +// Inline Functions +// + +inline Action * +DNSProcessor::getSRVbyname(Continuation *cont, const char *name, DNSHandler *adnsH, int timeout) +{ + return getby(name, 0, T_SRV, cont, adnsH, timeout); +} + +inline Action * +DNSProcessor::gethostbyname(Continuation *cont, const char *name, DNSHandler *adnsH, int timeout) +{ + return getby(name, 0, T_A, cont, adnsH, timeout); +} + +inline Action * +DNSProcessor::gethostbyname(Continuation *cont, const char *name, int len, int timeout) +{ + return getby(name, len, T_A, cont, NULL, timeout); +} + +inline Action * +DNSProcessor::gethostbyaddr(Continuation *cont, unsigned int addr, int timeout) +{ + return getby((char *) &addr, sizeof(addr), T_PTR, cont, NULL, timeout); +} + +void ink_dns_init(ModuleVersion version); + +#endif diff --git a/iocore/dns/I_SplitDNS.h b/iocore/dns/I_SplitDNS.h new file mode 100644 index 00000000..11cad06a --- /dev/null +++ b/iocore/dns/I_SplitDNS.h @@ -0,0 +1,43 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * I_SplitDNS.h - Interface to DNS server selection + * + * + ****************************************************************************/ + +#ifndef _I_SPLIT_DNS_H_ +#define _I_SPLIT_DNS_H_ + +#include "I_SplitDNSProcessor.h" + +#define SPLITDNS_MODULE_MAJOR_VERSION 1 +#define SPLITDNS_MODULE_MINOR_VERSION 0 +#define SPLITDNS_MODULE_VERSION makeModuleVersion( \ + SPLITDNS_MODULE_MAJOR_VERSION, \ + SPLITDNS_MODULE_MINOR_VERSION, \ + PUBLIC_MODULE_HEADER) + +#endif //_I_SPLIT_DNS_H_ diff --git a/iocore/dns/I_SplitDNSProcessor.h b/iocore/dns/I_SplitDNSProcessor.h new file mode 100644 index 00000000..a2bf094e --- /dev/null +++ b/iocore/dns/I_SplitDNSProcessor.h @@ -0,0 +1,59 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * I_SplitDNSProcessor.h - Interface to DNS server selection + * + * + ****************************************************************************/ + +#ifndef _I_SPLIT_DNSProcessor_H_ +#define _I_SPLIT_DNSProcessor_H_ + +struct SplitDNS; + +/* -------------------------------------------------------------- + ** struct SplitDNSConfig + -------------------------------------------------------------- */ + + +struct SplitDNSConfig +{ + + static void startup(); + + static bool isSplitDNSEnabled(); + + static void reconfigure(); + static SplitDNS *acquire(); + static void release(SplitDNS * params); + static void print(); + + static int m_id; + static Ptr dnsHandler_mutex; + + static int gsplit_dns_enabled; +}; + +#endif diff --git a/iocore/dns/Inline.cc b/iocore/dns/Inline.cc new file mode 100644 index 00000000..faf6903b --- /dev/null +++ b/iocore/dns/Inline.cc @@ -0,0 +1,33 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Inline Functions as globals for users using the public interface + * + */ +#define TS_INLINE +#define INLINE_CC + +#include "P_DNS.h" + + diff --git a/iocore/dns/Makefile.am b/iocore/dns/Makefile.am new file mode 100644 index 00000000..bb403325 --- /dev/null +++ b/iocore/dns/Makefile.am @@ -0,0 +1,55 @@ +# Makefile.am for the traffic/iocore/net hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if STANDALONE_IOCORE +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records +else +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/http \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/mgmt/preparse +endif + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +noinst_LIBRARIES = libinkdns.a + +libinkdns_a_SOURCES = \ + DNS.cc \ + DNSConnection.cc \ + I_DNS.h \ + I_DNSProcessor.h \ + I_SplitDNS.h \ + I_SplitDNSProcessor.h \ + P_DNS.h \ + P_DNSConnection.h \ + P_DNSProcessor.h \ + P_SplitDNS.h \ + P_SplitDNSProcessor.h \ + SplitDNS.cc \ + SRV.cc \ + SRV.h \ + Inline.cc + diff --git a/iocore/dns/Makefile.in b/iocore/dns/Makefile.in new file mode 100644 index 00000000..6f3104a6 --- /dev/null +++ b/iocore/dns/Makefile.in @@ -0,0 +1,726 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/net hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = iocore/dns +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinkdns_a_AR = $(AR) $(ARFLAGS) +libinkdns_a_LIBADD = +am_libinkdns_a_OBJECTS = DNS.$(OBJEXT) DNSConnection.$(OBJEXT) \ + SplitDNS.$(OBJEXT) SRV.$(OBJEXT) Inline.$(OBJEXT) +libinkdns_a_OBJECTS = $(am_libinkdns_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinkdns_a_SOURCES) +DIST_SOURCES = $(libinkdns_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +@STANDALONE_IOCORE_FALSE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_FALSE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/lib/records \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/http \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/hdrs \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/utils \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/preparse + +@STANDALONE_IOCORE_TRUE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_TRUE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_TRUE@ -I$(top_srcdir)/lib/records + +noinst_LIBRARIES = libinkdns.a +libinkdns_a_SOURCES = \ + DNS.cc \ + DNSConnection.cc \ + I_DNS.h \ + I_DNSProcessor.h \ + I_SplitDNS.h \ + I_SplitDNSProcessor.h \ + P_DNS.h \ + P_DNSConnection.h \ + P_DNSProcessor.h \ + P_SplitDNS.h \ + P_SplitDNSProcessor.h \ + SplitDNS.cc \ + SRV.cc \ + SRV.h \ + Inline.cc + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/dns/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/dns/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinkdns.a: $(libinkdns_a_OBJECTS) $(libinkdns_a_DEPENDENCIES) + -rm -f libinkdns.a + $(libinkdns_a_AR) libinkdns.a $(libinkdns_a_OBJECTS) $(libinkdns_a_LIBADD) + $(RANLIB) libinkdns.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DNS.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DNSConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SRV.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SplitDNS.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/dns/P_DNS.h b/iocore/dns/P_DNS.h new file mode 100644 index 00000000..b1bd47bf --- /dev/null +++ b/iocore/dns/P_DNS.h @@ -0,0 +1,47 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_DNS.h + + + ****************************************************************************/ +#if !defined (_P_DNS_h_) +#define _P_DNS_h_ + +#ifndef INLINE_CC +#undef TS_INLINE +#define TS_INLINE inline +#endif + +#include "libts.h" +#include "I_DNS.h" +#include "P_EventSystem.h" +#include "I_Cache.h" +#include "P_Net.h" +#include "P_DNSConnection.h" +#include "P_DNSProcessor.h" +#include "SRV.h" + +#endif // _P_DNS_h_ diff --git a/iocore/dns/P_DNSConnection.h b/iocore/dns/P_DNSConnection.h new file mode 100644 index 00000000..ada1b0df --- /dev/null +++ b/iocore/dns/P_DNSConnection.h @@ -0,0 +1,80 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + + P_DNSConnection.h + Description: + struct DNSConnection + **************************************************************************/ + +#ifndef __P_DNSCONNECTION_H__ +#define __P_DNSCONNECTION_H__ + +#include "I_EventSystem.h" + +// +// Defines +// + +#define NON_BLOCKING_CONNECT true +#define BLOCKING_CONNECT false +#define CONNECT_WITH_TCP true +#define CONNECT_WITH_UDP false +#define NON_BLOCKING true +#define BLOCKING false +#define BIND_RANDOM_PORT true +#define BIND_ANY_PORT false +#define ENABLE_MC_LOOPBACK true +#define DISABLE_MC_LOOPBACK false +#define BC_NO_CONNECT true +#define BC_CONNECT false +#define BC_NO_BIND true +#define BC_BIND false + +// +// Connection +// +struct DNSHandler; + +struct DNSConnection +{ + int fd; + struct sockaddr_in sa; + int num; + LINK(DNSConnection, link); + EventIO eio; + InkRand generator; + DNSHandler* handler; + + int connect(unsigned int ip, int port, + bool non_blocking_connect = NON_BLOCKING_CONNECT, + bool use_tcp = CONNECT_WITH_TCP, bool non_blocking = NON_BLOCKING, bool bind_random_port = BIND_ANY_PORT); + int close(); + void trigger(); + + virtual ~DNSConnection(); + DNSConnection(); +}; + +#endif /*_P_DNSConnection_h*/ diff --git a/iocore/dns/P_DNSProcessor.h b/iocore/dns/P_DNSProcessor.h new file mode 100644 index 00000000..cb9d179f --- /dev/null +++ b/iocore/dns/P_DNSProcessor.h @@ -0,0 +1,311 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#if !defined (_P_DNSProcessor_h_) +#define _P_DNSProcessor_h_ + +/* + #include "I_DNS.h" + #include "libts.h" + #include + #include "I_Cache.h" + #include "P_Net.h" +*/ +#include "I_EventSystem.h" + +#define MAX_NAMED 32 +#define DEFAULT_DNS_RETRIES 5 +#define MAX_DNS_RETRIES 9 +#define DEFAULT_DNS_TIMEOUT 30 +#define MAX_DNS_IN_FLIGHT 2048 +#define DEFAULT_FAILOVER_NUMBER (DEFAULT_DNS_RETRIES + 1) +#define DEFAULT_FAILOVER_PERIOD (DEFAULT_DNS_TIMEOUT + 30) +// how many seconds before FAILOVER_PERIOD to try the primary with +// a well known address +#define DEFAULT_FAILOVER_TRY_PERIOD (DEFAULT_DNS_TIMEOUT + 1) +#define DEFAULT_DNS_SEARCH 1 +#define FAILOVER_SOON_RETRY 5 +#define NO_NAMESERVER_SELECTED -1 + +// +// Config +// +extern int dns_timeout; +extern int dns_retries; +extern int dns_search; +extern int dns_failover_number; +extern int dns_failover_period; +extern int dns_failover_try_period; +extern int dns_max_dns_in_flight; +extern unsigned int dns_sequence_number; + +// +// Constants +// + +#define DNS_PERIOD HRTIME_MSECONDS(-100) +#define DNS_DELAY_PERIOD HRTIME_MSECONDS(10) +#define DNS_SEQUENCE_NUMBER_RESTART_OFFSET 4000 +#define DNS_PRIMARY_RETRY_PERIOD HRTIME_SECONDS(5) +#define DNS_PRIMARY_REOPEN_PERIOD HRTIME_SECONDS(60) +#define BAD_DNS_RESULT ((HostEnt*)(uintptr_t)-1) +#define DEFAULT_NUM_TRY_SERVER 8 + +// these are from nameser.h +#ifndef HFIXEDSZ +#define HFIXEDSZ 12 +#endif +#ifndef QFIXEDSZ +#define QFIXEDSZ 4 +#endif + + +// Events + +#define DNS_EVENT_LOOKUP DNS_EVENT_EVENTS_START + +extern int dns_fd; + +void *dns_udp_receiver(void *arg); + + +//Stats +enum DNS_Stats +{ + dns_total_lookups_stat, + dns_response_time_stat, + dns_success_time_stat, + dns_lookup_success_stat, + dns_lookup_fail_stat, + dns_fail_time_stat, + dns_retries_stat, + dns_max_retries_exceeded_stat, + dns_sequence_number_stat, + dns_in_flight_stat, + DNS_Stat_Count +}; + +struct HostEnt; +struct DNSHandler; + +struct RecRawStatBlock; +extern RecRawStatBlock *dns_rsb; + +// Stat Macros + +#define DNS_DEBUG_COUNT_DYN_STAT(_x, _y) \ + RecIncrRawStatCount(dns_rsb, mutex->thread_holding, (int)_x, _y) + +#define DNS_INCREMENT_DYN_STAT(_x) \ + RecIncrRawStatSum(dns_rsb, mutex->thread_holding, (int)_x, 1) + +#define DNS_DECREMENT_DYN_STAT(_x) \ + RecIncrRawStatSum(dns_rsb, mutex->thread_holding, (int)_x, -1) + +#define DNS_SUM_DYN_STAT(_x, _r) \ + RecIncrRawStatSum(dns_rsb, mutex->thread_holding, (int)_x, _r) + +#define DNS_READ_DYN_STAT(_x, _count, _sum) do { \ + RecGetRawStatSum(dns_rsb, (int)_x, &_sum); \ + RecGetRawStatCount(dns_rsb, (int)_x, &_count); \ + } while (0) + +#define DNS_SET_DYN_COUNT(_x, _count) \ + RecSetRawStatCount(dns_rsb, _x, _count); + +#define DNS_INCREMENT_THREAD_DYN_STAT(_s, _t) \ + RecIncrRawStatSum(dns_rsb, _t, (int) _s, 1); + +#define DNS_DECREMENT_THREAD_DYN_STAT(_s, _t) \ + RecIncrRawStatSum(dns_rsb, _t, (int) _s, -1); + +/** + One DNSEntry is allocated per outstanding request. This continuation + handles TIMEOUT events for the request as well as storing all + information about the request and its status. + +*/ +struct DNSEntry: public Continuation +{ + int id[MAX_DNS_RETRIES]; + int qtype; + int retries; + int which_ns; + ink_hrtime submit_time; + ink_hrtime send_time; + char qname[MAXDNAME]; + int qname_len; + char **domains; + EThread *submit_thread; + Action action; + Event *timeout; + Ptr result_ent; + DNSHandler *dnsH; + bool written_flag; + bool once_written_flag; + bool last; + LINK(DNSEntry, dup_link); + Que(DNSEntry, dup_link) dups; + + int mainEvent(int event, Event *e); + int delayEvent(int event, Event *e); + int post(DNSHandler *h, HostEnt *ent); + int postEvent(int event, Event *e); + void init(const char *x, int len, int qtype_arg, Continuation *acont, DNSHandler *adnsH, int timeout); + + DNSEntry() + : Continuation(NULL), + qtype(0), + retries(DEFAULT_DNS_RETRIES), + which_ns(NO_NAMESERVER_SELECTED), submit_time(0), send_time(0), qname_len(0), domains(0), + timeout(0), result_ent(0), dnsH(0), written_flag(false), once_written_flag(false), last(false) + { + for (int i = 0; i < MAX_DNS_RETRIES; i++) + id[i] = -1; + memset(qname, 0, MAXDNAME); + } +}; + + +typedef int (DNSEntry::*DNSEntryHandler) (int, void *); + +struct DNSEntry; + +/** + One DNSHandler is allocated to handle all DNS traffic by polling a + UDP port. + +*/ +struct DNSHandler: public Continuation +{ + unsigned int ip; + int port; + int ifd[MAX_NAMED]; + int n_con; + DNSConnection con[MAX_NAMED]; + int options; + Queue entries; + Queue triggered; + int in_flight; + int name_server; + int in_write_dns; + HostEnt *hostent_cache; + + int ns_down[MAX_NAMED]; + int failover_number[MAX_NAMED]; + int failover_soon_number[MAX_NAMED]; + ink_hrtime crossed_failover_number[MAX_NAMED]; + ink_hrtime last_primary_retry; + ink_hrtime last_primary_reopen; + + ink_res_state m_res; + int txn_lookup_timeout; + + InkRand generator; + // bitmap of query ids in use + uint64_t qid_in_flight[(USHRT_MAX+1)/64]; + + + void received_one(int i) + { + failover_number[i] = failover_soon_number[i] = crossed_failover_number[i] = 0; + } + + void sent_one() + { + ++failover_number[name_server]; + Debug("dns", "sent_one: failover_number for resolver %d is %d", name_server, failover_number[name_server]); + if (failover_number[name_server] >= dns_failover_number && !crossed_failover_number[name_server]) + crossed_failover_number[name_server] = ink_get_hrtime(); + } + + bool failover_now(int i) + { + if (is_debug_tag_set("dns")) { + Debug("dns", "failover_now: Considering immediate failover, target time is %" PRId64 "", + HRTIME_SECONDS(dns_failover_period)); + Debug("dns", "\tdelta time is %" PRId64 "", (ink_get_hrtime() - crossed_failover_number[i])); + } + return (crossed_failover_number[i] && + ((ink_get_hrtime() - crossed_failover_number[i]) > HRTIME_SECONDS(dns_failover_period))); + } + + bool failover_soon(int i) { + return (crossed_failover_number[i] && + ((ink_get_hrtime() - crossed_failover_number[i]) > + (HRTIME_SECONDS(dns_failover_try_period + failover_soon_number[i] * FAILOVER_SOON_RETRY)))); + } + + void recv_dns(int event, Event *e); + int startEvent(int event, Event *e); + int startEvent_sdns(int event, Event *e); + int mainEvent(int event, Event *e); + + void open_con(unsigned int aip, int aport, bool failed = false, int icon = 0); + void failover(); + void rr_failure(int ndx); + void recover(); + void retry_named(int ndx, ink_hrtime t, bool reopen = true); + void try_primary_named(bool reopen = true); + void switch_named(int ndx); + uint16_t get_query_id(); + + void release_query_id(uint16_t qid) { + qid_in_flight[qid >> 6] &= (uint64_t)~(0x1ULL << (qid & 0x3F)); + }; + + void set_query_id_in_use(uint16_t qid) { + qid_in_flight[qid >> 6] |= (uint64_t)(0x1ULL << (qid & 0x3F)); + }; + + bool query_id_in_use(uint16_t qid) { + return (qid_in_flight[(uint16_t)(qid) >> 6] & (uint64_t)(0x1ULL << ((uint16_t)(qid) & 0x3F))) != 0; + }; + + DNSHandler(); +}; + + +TS_INLINE DNSHandler::DNSHandler() + : Continuation(NULL), ip(0), port(0), n_con(0), options(0), in_flight(0), name_server(0), in_write_dns(0), + hostent_cache(0), last_primary_retry(0), last_primary_reopen(0), + m_res(0), txn_lookup_timeout(0), generator((uint32_t)((uintptr_t)time(NULL) ^ (uintptr_t)this)) +{ + for (int i = 0; i < MAX_NAMED; i++) { + ifd[i] = -1; + failover_number[i] = 0; + failover_soon_number[i] = 0; + crossed_failover_number[i] = 0; + ns_down[i] = 1; + con[i].handler = this; + } + memset(&qid_in_flight, 0, sizeof(qid_in_flight)); + SET_HANDLER(&DNSHandler::startEvent); + Debug("net_epoll", "inline DNSHandler::DNSHandler()"); +} + +#define DOT_SEPARATED(_x) \ + ((unsigned char*)&(_x))[0], ((unsigned char*)&(_x))[1], \ + ((unsigned char*)&(_x))[2], ((unsigned char*)&(_x))[3] + +#endif diff --git a/iocore/dns/P_SplitDNS.h b/iocore/dns/P_SplitDNS.h new file mode 100644 index 00000000..d63c1d5b --- /dev/null +++ b/iocore/dns/P_SplitDNS.h @@ -0,0 +1,48 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * P_SplitDNS.h - Interface to DNS server selection + * + * + ****************************************************************************/ + +#ifndef _P_SPLIT_DNS_H_ +#define _P_SPLIT_DNS_H_ + +#include "P_DNS.h" +#include "I_SplitDNS.h" +#include "I_Lock.h" +#include "ControlBase.h" +#include "ControlMatcher.h" +#include "P_SplitDNSProcessor.h" + +#undef SPLITDNS_MODULE_VERSION +#define SPLITDNS_MODULE_VERSION makeModuleVersion( \ + SPLITDNS_MODULE_MAJOR_VERSION, \ + SPLITDNS_MODULE_MINOR_VERSION, \ + PRIVATE_MODULE_HEADER) + + +#endif /* _P_SPLIT_DNS_H_ */ diff --git a/iocore/dns/P_SplitDNSProcessor.h b/iocore/dns/P_SplitDNSProcessor.h new file mode 100644 index 00000000..a0d21df3 --- /dev/null +++ b/iocore/dns/P_SplitDNSProcessor.h @@ -0,0 +1,343 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * P_SplitDNSProcessor.h - Interface to DNS server selection + * + * + ****************************************************************************/ + +#ifndef _P_SPLIT_DNSProcessor_H_ +#define _P_SPLIT_DNSProcessor_H_ + +/* +#include "P_DNS.h" +#include "I_SplitDNS.h" +#include "I_Lock.h" +#include "ControlBase.h" +#include "ControlMatcher.h" +*/ + +/* --------------------------- + forward declarations ... + --------------------------- */ +void ink_split_dns_init(ModuleVersion version); + +#define MAX_CONFIGS 100 +struct RequestData; +typedef RequestData RD; + +struct matcher_line; + +class SplitDNSRecord; +struct SplitDNSResult; + +struct DNSServer; + +enum DNSResultType +{ DNS_SRVR_UNDEFINED = 0, + DNS_SRVR_SPECIFIED, + DNS_SRVR_FAIL +}; + +typedef ControlMatcher DNS_table; + + +/* -------------------------------------------------------------- + ** struct SplitDNSResult + -------------------------------------------------------------- */ +struct SplitDNSResult +{ + SplitDNSResult(); + + /* ------------ + public + ------------ */ + DNSResultType r; + + DNSServer *get_dns_record(); + int get_dns_srvr_count(); + + /* ------------ + private + ------------ */ + int m_line_number; + + SplitDNSRecord *m_rec; + bool m_wrap_around; +}; + + +struct SplitDNSConfigInfo +{ + volatile int m_refcount; + + virtual ~SplitDNSConfigInfo() + { } +}; + + +class SplitDNSConfigProcessor +{ +public: + SplitDNSConfigProcessor(); + + unsigned int set(unsigned int id, SplitDNSConfigInfo * info); + SplitDNSConfigInfo *get(unsigned int id); + void release(unsigned int id, SplitDNSConfigInfo * data); + +public: + volatile SplitDNSConfigInfo *infos[MAX_CONFIGS]; + volatile int ninfos; +}; + + +extern SplitDNSConfigProcessor SplitDNSconfigProcessor; + +/* -------------------------------------------------------------- + ** struct SplitDNS + -------------------------------------------------------------- */ +struct SplitDNS:public SplitDNSConfigInfo +{ + SplitDNS(); + ~SplitDNS(); + + void *getDNSRecord(const char *hostname); + void findServer(RD * rdata, SplitDNSResult * result); + + + DNS_table *m_DNSSrvrTable; + + int32_t m_SplitDNSlEnable; + + /* ---------------------------- + required by the alleged fast + path + ---------------------------- */ + bool m_bEnableFastPath; + void *m_pxLeafArray; + int m_numEle; +}; + + +/* -------------------------------------------------------------- + SplitDNSConfig::isSplitDNSEnabled() + -------------------------------------------------------------- */ +TS_INLINE bool SplitDNSConfig::isSplitDNSEnabled() +{ + return (gsplit_dns_enabled ? true : false); +} + + +// +// End API to outside world +// + + +/* -------------------------------------------------------------- + ** struct DNSServer + + A record for an single server + -------------------------------------------------------------- */ +struct DNSServer +{ + unsigned int x_server_ip[MAXNS]; + char x_dns_ip_line[MAXDNAME * 2]; + + char x_def_domain[MAXDNAME]; + char x_domain_srch_list[MAXDNAME]; + int x_dns_server_port[MAXNS]; + + DNSHandler *x_dnsH; + + DNSServer() + : x_dnsH(NULL) + { + memset(x_server_ip, 0, sizeof(x_server_ip)); + memset(x_dns_server_port, 0, sizeof(x_dns_server_port)); + + memset(x_def_domain, 0, MAXDNAME); + memset(x_domain_srch_list, 0, MAXDNAME); + memset(x_dns_ip_line, 0, MAXDNAME * 2); + } +}; + + +/* -------------------------------------------------------------- + ** class DNSRequestData + + A record for an single server + -------------------------------------------------------------- */ +class DNSRequestData: public RequestData +{ +public: + + DNSRequestData(); + + char *get_string(); + + const char *get_host(); + + ip_addr_t get_ip(); + ip_addr_t get_client_ip(); + + const char *m_pHost; +}; + + +/* -------------------------------------------------------------- + DNSRequestData::get_string() + -------------------------------------------------------------- */ +TS_INLINE DNSRequestData::DNSRequestData() +: m_pHost(0) +{ +} + + +/* -------------------------------------------------------------- + DNSRequestData::get_string() + -------------------------------------------------------------- */ +TS_INLINE char * +DNSRequestData::get_string() +{ + return xstrdup((char *) m_pHost); +} + + +/* -------------------------------------------------------------- + DNSRequestData::get_host() + -------------------------------------------------------------- */ +TS_INLINE const char * +DNSRequestData::get_host() +{ + return m_pHost; +} + + +/* -------------------------------------------------------------- + DNSRequestData::get_ip() + -------------------------------------------------------------- */ +TS_INLINE ip_addr_t DNSRequestData::get_ip() +{ + return (ip_addr_t) 0; +} + + +/* -------------------------------------------------------------- + DNSRequestData::get_client_ip() + -------------------------------------------------------------- */ +TS_INLINE ip_addr_t DNSRequestData::get_client_ip() +{ + return (ip_addr_t) 0; +} + +/* -------------------------------------------------------------- + * class SplitDNSRecord + + A record for a configuration line in the splitdns.config file + -------------------------------------------------------------- */ +class SplitDNSRecord: public ControlBase +{ +public: + + SplitDNSRecord(); + ~SplitDNSRecord(); + + char *Init(matcher_line * line_info); + + const char *ProcessDNSHosts(char *val); + const char *ProcessDomainSrchList(char *val); + const char *ProcessDefDomain(char *val); + + void UpdateMatch(SplitDNSResult * result, RD * rdata); + void Print(); + + DNSServer m_servers; + int m_dnsSrvr_cnt; + int m_domain_srch_list; +}; + + +/* -------------------------------------------------------------- + SplitDNSRecord::SplitDNSRecord() + -------------------------------------------------------------- */ +TS_INLINE SplitDNSRecord::SplitDNSRecord() +: m_dnsSrvr_cnt(0), m_domain_srch_list(0) +{ } + + +/* -------------------------------------------------------------- + SplitDNSRecord::~SplitDNSRecord() + -------------------------------------------------------------- */ +TS_INLINE SplitDNSRecord::~SplitDNSRecord() +{ } + + +/* -------------------------------------------------------------- + struct SDNS_UpdateContinuation + Used to handle parent.conf or default parent updates after the + manager signals a change + -------------------------------------------------------------- */ +struct SDNS_UpdateContinuation: public Continuation +{ + int handle_event(int event, void *data); + SDNS_UpdateContinuation(ProxyMutex * m); + +}; + + +/* -------------------------------------------------------------- + SDNS_UpdateContinuation::SDNS_UpdateContinuation() + -------------------------------------------------------------- */ +TS_INLINE SDNS_UpdateContinuation::SDNS_UpdateContinuation(ProxyMutex * m) +: Continuation(m) +{ + SET_HANDLER(&SDNS_UpdateContinuation::handle_event); +} + + +/* -------------------------------------------------------------- + SDNS_UpdateContinuation::handle_event() + -------------------------------------------------------------- */ +TS_INLINE int +SDNS_UpdateContinuation::handle_event(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + + SplitDNSConfig::reconfigure(); + delete this; + + return EVENT_DONE; +} + +/* ------------------ + Helper Functions + ------------------ */ + +SplitDNSRecord *createDefaultServer(); +void reloadDefaultParent(char *val); +void reloadParentFile(); + +#endif diff --git a/iocore/dns/SRV.cc b/iocore/dns/SRV.cc new file mode 100644 index 00000000..00629291 --- /dev/null +++ b/iocore/dns/SRV.cc @@ -0,0 +1,166 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + + indent -ncs -nut -npcs -l 132 -br SRV.cc + + Support for SRV records + + http://www.faqs.org/rfcs/rfc2782.html + http://www.nongnu.org/ruli/ + http://libsrv.cvs.sourceforge.net/libsrv/libsrv/src/libsrv.c + +*/ + +#include "P_DNS.h" + +struct HostDBRoundRobin; + +ClassAllocator SRVAllocator("SRVAllocator"); + +/* +To select a target to be contacted next, arrange all SRV RRs +(that have not been ordered yet) in any order, except that all +those with weight 0 are placed at the beginning of the list. + +Compute the sum of the weights of those RRs, and with each RR +associate the running sum in the selected order. Then choose a +uniform random number between 0 and the sum computed +(inclusive), and select the RR whose running sum value is the +first in the selected order which is greater than or equal to +the random number selected. The target host specified in the +selected SRV RR is the next one to be contacted by the client. +Remove this SRV RR from the set of the unordered SRV RRs and +apply the described algorithm to the unordered SRV RRs to select +the next target host. Continue the ordering process until there +are no unordered SRV RRs. This process is repeated for each +Priority. +*/ + +static InkRand SRVRand(55378008); + +void +SRVHosts::getWeightedHost(char *ret_val) +{ + int a_prev; + int k = 0; + int accum = 0; + unsigned int pri = 0; + SRV *i; + //InkRand x(time(NULL)); + int tmp[1024]; + int j = 0; + int v; + uint32_t xx; + + if (hosts.empty() || getCount() == 0) { + goto err; + } + + /* Step 1/2 Sort based on 'priority': handled by operator< + */ + + hosts.sort(); + + /* + * Step 2/2: Select SRV RRs by random weighted order + */ + + //get lowest priority (now sorted) + i = hosts.head; + + if (!i) { + goto err; + } + //Get current priority + pri = i->getPriority(); + //Accumulate weight sum for priority + + while (i != NULL && pri == i->getPriority()) { + a_prev = accum; + accum += i->getWeight(); + for (j = a_prev; j < accum; j++) { + tmp[j] = k; + } + i = i->link.next; + k++; + } + + Debug("dns_srv", "accum=%d for priority=%d", accum, pri); + + if (!accum) { + Debug("dns_srv", "Accumulator was 0. eek."); + goto err; + } + //Pick random number: 0..accum + xx = SRVRand.random() % accum; + + Debug("dns_srv", "picked %d as a random number", xx); + + i = hosts.head; + v = tmp[xx]; + j = 0; + while (j < v) { + i = i->link.next; + j++; + } + Debug("dns_srv", "using SRV record of: pri: %d, wei: %d, port: %d, host: %s", + i->getPriority(), i->getWeight(), i->getPort(), i->getHost()); + + ink_strncpy(ret_val, i->getHost(), MAXDNAME); + ret_val[MAXDNAME - 1] = '\0'; + if (strcmp(ret_val, "") == 0 || strcmp(ret_val, ".") == 0) { + goto err; + } + return; +err: + Debug("dns_srv", "there was a problem figuring out getWeightedHost() -- we are returning a blank SRV host"); + ret_val[0] = '\0'; + return; +} + +SRVHosts::SRVHosts(HostDBInfo * info) +{ + hosts.clear(); + srv_host_count = 0; + if (!info) + return; + HostDBRoundRobin *rr_data = info->rr(); + + if (!rr_data) { + return; + } + + for (unsigned int i = 0; i < info->srv_count; i++) { + /* get the RR data */ + SRV *s = SRVAllocator.alloc(); + HostDBInfo nfo = rr_data->info[i]; + s->setPort(nfo.srv_port); + s->setPriority(nfo.srv_priority); + s->setWeight(nfo.srv_weight); + s->setHost(&rr_data->rr_srv_hosts[i][0]); + insert(s); + } + return; +} diff --git a/iocore/dns/SRV.h b/iocore/dns/SRV.h new file mode 100644 index 00000000..2013ecd1 --- /dev/null +++ b/iocore/dns/SRV.h @@ -0,0 +1,157 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _SRV_h_ +#define _SRV_h_ + +#include "libts.h" +#include "I_HostDBProcessor.h" + +struct HostDBInfo; + +#define RAND_INV_RANGE(r) ((int) ((RAND_MAX + 1) / (r))) + +class SRV +{ +private: + unsigned int weight; + unsigned int port; + unsigned int priority; + unsigned int ttl; + char host[MAXDNAME]; + +public: + LINK(SRV, link); + SRV():weight(0), port(0), priority(0), ttl(0) + { + memset(host, 0, MAXDNAME); + } + + unsigned int getWeight() + { + return weight; + } + unsigned int getPriority() const + { + return priority; + } + unsigned int getPort() + { + return port; + } + unsigned int getTTL() + { + return ttl; + } + char *getHost() + { + return &host[0]; + } + + void setWeight(int w) + { + weight = w; + } + void setTTL(int t) + { + ttl = t; + } + void setPort(int p) + { + port = p; + } + void setPriority(int p) + { + priority = p; + } + void setHost(const char *h) + { + if (!h) { + Debug("dns_srv", "SRV::setHost() was passed a NULL host -- better check your code)"); + host[0] = '\0'; + return; + } + if (*h == '\0') { + Debug("dns_srv", "SRV::setHost() was passed a blank host -- better check what might have happened."); + host[0] = '\0'; + return; + } + strncpy(host, (char *) h, MAXDNAME); + host[MAXDNAME - 1] = '\0'; /* just in case */ + } + +}; + +TS_INLINE bool +operator<(const SRV & left, const SRV & right) +{ + return (left.getPriority() < right.getPriority()); /* lower priorities first :) */ +} + +extern ClassAllocator SRVAllocator; + +class SRVHosts +{ +private: + SortableQueue hosts; + int srv_host_count; + +public: + ~SRVHosts() + { + SRV *i; + while ((i = hosts.dequeue())) { + Debug("dns_srv", "freeing srv entry inside SRVHosts::~SRVHosts"); + SRVAllocator.free(i); + } + } + + SRVHosts():srv_host_count(0) + { + hosts.clear(); + } + + SortableQueue *getHosts() { + return &hosts; + } + + void getWeightedHost(char *); + + bool insert(SRV * rec) + { + hosts.enqueue(rec); + srv_host_count++; + return true; + } + + int getCount() + { + return srv_host_count; + } + + /* convert this HostDBInfo to an SRVHosts */ + SRVHosts(HostDBInfo * info); + +}; + +#endif diff --git a/iocore/dns/SplitDNS.cc b/iocore/dns/SplitDNS.cc new file mode 100644 index 00000000..86df7d9e --- /dev/null +++ b/iocore/dns/SplitDNS.cc @@ -0,0 +1,709 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * SplitDNS.cc - Implementation of "split" DNS (as the name says) + * + * + ****************************************************************************/ + +#include "libts.h" + +#ifdef SPLIT_DNS +#include +#include "P_SplitDNS.h" +#include "MatcherUtils.h" +#include "HostLookup.h" + +SplitDNSConfigProcessor SplitDNSconfigProcessor; + + +/* -------------------------------------------------------------- + this file is built using "ParentSelection.cc as a template. + ------------- ------------------------------------------------- */ + +/* -------------------------------------------------------------- + globals + -------------------------------------------------------------- */ +static const char modulePrefix[] = "[SplitDNS]"; +static Ptr reconfig_mutex = NULL; + +static ClassAllocator DNSReqAllocator("DNSRequestDataAllocator"); + +/* -------------------------------------------------------------- + used by a lot of protocols. We do not have dest ip in most + cases. + -------------------------------------------------------------- */ +const matcher_tags sdns_dest_tags = { + "dest_host", "dest_domain", NULL, "url_regex", NULL, true +}; + + +/* -------------------------------------------------------------- + config Callback Prototypes + -------------------------------------------------------------- */ +enum SplitDNSCB_t +{ + SDNS_FILE_CB, + SDNS_ENABLE_CB +}; + + +static const char *SDNSResultStr[] = { + "DNSServer_Undefined", + "DNSServer_Specified", + "DNSServer_Failed" +}; + + +int SplitDNSConfig::m_id = 0; +int SplitDNSConfig::gsplit_dns_enabled = 0; +Ptr SplitDNSConfig::dnsHandler_mutex = 0; + + +/* -------------------------------------------------------------- + SplitDNSResult::SplitDNSResult() + -------------------------------------------------------------- */ +inline SplitDNSResult::SplitDNSResult() + : r(DNS_SRVR_UNDEFINED), m_line_number(0), m_rec(0), m_wrap_around(false) +{ +} + + +/* -------------------------------------------------------------- + SplitDNS::SplitDNS() + -------------------------------------------------------------- */ +SplitDNS::SplitDNS() +: m_DNSSrvrTable(NULL), m_SplitDNSlEnable(0), + m_bEnableFastPath(false), m_pxLeafArray(NULL), m_numEle(0) +{ +} + + +SplitDNS::~SplitDNS() +{ + if (m_DNSSrvrTable) { + delete m_DNSSrvrTable; + } +} + + +/* -------------------------------------------------------------- + SplitDNSConfig::acquire() + -------------------------------------------------------------- */ +SplitDNS * +SplitDNSConfig::acquire() +{ + return (SplitDNS *) SplitDNSconfigProcessor.get(SplitDNSConfig::m_id); +} + + +/* -------------------------------------------------------------- + SplitDNSConfig::release() + -------------------------------------------------------------- */ +void +SplitDNSConfig::release(SplitDNS * params) +{ + SplitDNSconfigProcessor.release(SplitDNSConfig::m_id, params); +} + +/* -------------------------------------------------------------- + SplitDNSConfig::startup() + -------------------------------------------------------------- */ +void +SplitDNSConfig::startup() +{ + reconfig_mutex = new_ProxyMutex(); + dnsHandler_mutex = new_ProxyMutex(); + + //startup just check gsplit_dns_enabled + IOCORE_ReadConfigInt32(gsplit_dns_enabled, "proxy.config.dns.splitDNS.enabled"); +} + + +/* -------------------------------------------------------------- + SplitDNSConfig::reconfigure() + -------------------------------------------------------------- */ +void +SplitDNSConfig::reconfigure() +{ + if (0 == gsplit_dns_enabled) + return; + + SplitDNS *params = NEW(new SplitDNS); + + params->m_SplitDNSlEnable = gsplit_dns_enabled; + params->m_DNSSrvrTable = NEW(new DNS_table("proxy.config.dns.splitdns.filename", modulePrefix, &sdns_dest_tags)); + + params->m_numEle = params->m_DNSSrvrTable->getEntryCount(); + if (0 == params->m_DNSSrvrTable || (0 == params->m_numEle)) { + Warning("No NAMEDs provided! Disabling SplitDNS"); + gsplit_dns_enabled = 0; + delete params; + return; + } + + if (0 != params->m_DNSSrvrTable->getHostMatcher() && + 0 == params->m_DNSSrvrTable->getReMatcher() && + 0 == params->m_DNSSrvrTable->getIPMatcher() && 4 >= params->m_numEle) { + + HostLookup *pxHL = params->m_DNSSrvrTable->getHostMatcher()->getHLookup(); + params->m_pxLeafArray = (void *) pxHL->getLArray(); + params->m_bEnableFastPath = true; + } + + m_id = SplitDNSconfigProcessor.set(m_id, params); + + if (is_debug_tag_set("splitdns_config")) { + SplitDNSConfig::print(); + } +} + + +/* -------------------------------------------------------------- + SplitDNSConfig::print() + -------------------------------------------------------------- */ +void +SplitDNSConfig::print() +{ + SplitDNS *params = SplitDNSConfig::acquire(); + + Debug("splitdns_config", "DNS Server Selection Config\n"); + Debug("splitdns_config", "\tEnabled \n", params->m_SplitDNSlEnable); + + params->m_DNSSrvrTable->Print(); + SplitDNSConfig::release(params); +} + + +/* -------------------------------------------------------------- + SplitDNS::getDNSRecord() + -------------------------------------------------------------- */ +void * +SplitDNS::getDNSRecord(const char *hostname) +{ + Debug("splitdns", "Called SplitDNS::getDNSRecord(%s)", hostname); + + DNSRequestData *pRD = DNSReqAllocator.alloc(); + pRD->m_pHost = hostname; + + SplitDNSResult res; + findServer(pRD, &res); + + DNSReqAllocator.free(pRD); + + if (DNS_SRVR_SPECIFIED == res.r) { + return (void *) &(res.m_rec->m_servers); + } + + Debug("splitdns", "Fail to match a valid splitdns rule, fallback to default dns resolver"); + return NULL; +} + + +/* -------------------------------------------------------------- + SplitDNS::findServer() + -------------------------------------------------------------- */ +void +SplitDNS::findServer(RD * rdata, SplitDNSResult * result) +{ + DNS_table *tablePtr = m_DNSSrvrTable; + SplitDNSRecord *rec; + + ink_assert(result->r == DNS_SRVR_UNDEFINED); + + if (m_SplitDNSlEnable == 0) { + result->r = DNS_SRVR_UNDEFINED; + return; + } + + result->m_rec = NULL; + result->m_line_number = 0xffffffff; + result->m_wrap_around = false; + + /* --------------------------- + the 'alleged' fast path ... + --------------------------- */ + if (m_bEnableFastPath) { + SplitDNSRecord *data_ptr = 0; + char *pHost = (char *) rdata->get_host(); + if (0 == pHost) { + Warning("SplitDNS: No host to match !"); + return; + } + + int len = strlen(pHost); + HostLeaf *pxHL = (HostLeaf *) m_pxLeafArray; + for (int i = 0; i < m_numEle; i++) { + if (0 == pxHL) + break; + + if (false == pxHL[i].isNot && pxHL[i].len > len) + continue; + + int idx = len - pxHL[i].len; + char *pH = &pHost[idx]; + char *pMatch = (char *) pxHL[i].match; + char cNot = *pMatch; + + if ('!' == cNot) + pMatch++; + + int res = memcmp(pH, pMatch, pxHL[i].len); + + if ((0 != res && '!' == cNot) || (0 == res && '!' != cNot)) { + data_ptr = (SplitDNSRecord *) pxHL[i].opaque_data; + data_ptr->UpdateMatch(result, rdata); + break; + } + } + } else { + tablePtr->Match(rdata, result); + } + + rec = result->m_rec; + if (rec == NULL) { + result->r = DNS_SRVR_UNDEFINED; + return; + } else { + result->r = DNS_SRVR_SPECIFIED; + } + + if (is_debug_tag_set("splitdns_config")) { + const char *host = rdata->get_host(); + + switch (result->r) { + case DNS_SRVR_FAIL: + Debug("splitdns_config", "Result for %s was %s", host, SDNSResultStr[result->r]); + break; + case DNS_SRVR_SPECIFIED: + Debug("splitdns_config", "Result for %s was dns servers \n", host); + result->m_rec->Print(); + break; + default: + // DNS_SRVR_UNDEFINED + break; + } + } +} + + +/* -------------------------------------------------------------- + SplitDNSRecord::ProcessDNSHosts() + -------------------------------------------------------------- */ +const char * +SplitDNSRecord::ProcessDNSHosts(char *val) +{ + Tokenizer pTok(",; \t\r"); + int numTok; + const char *current; + int port = 0; + char *tmp; + int totsz = 0, sz = 0; + + numTok = pTok.Initialize(val, SHARE_TOKS); + if (MAXNS < numTok) { + numTok = MAXNS; + Warning("Only first %d DNS servers are tracked", numTok); + } + if (numTok == 0) { + return "No servers specified"; + } + + /* ------------------------------------------------ + Allocate the servers array and Loop through the + set of servers specified + ------------------------------------------------ */ + for (int i = 0; i < numTok; i++) { + current = pTok[i]; + tmp = (char *) strchr(current, ':'); + // coverity[secure_coding] + if (tmp != NULL && sscanf(tmp + 1, "%d", &port) != 1) { + return "Malformed DNS port"; + } + + /* ---------------------------------------- + Make sure that is no garbage beyond the + server port + ---------------------------------------- */ + if (tmp) { + char *scan = tmp + 1; + for (; *scan != '\0' && ParseRules::is_digit(*scan); scan++); + for (; *scan != '\0' && ParseRules::is_wslfcr(*scan); scan++); + + if (*scan != '\0') { + return "Garbage trailing entry or invalid separator"; + } + + if (tmp - current > (MAXDNAME - 1)) { + return "DNS server name (ip) is too long"; + } else if (tmp - current == 0) { + return "server string is emtpy"; + } + *tmp = 0; + } + + unsigned int addr = inet_addr(current); + + if (((uint32_t)-1) == htonl(addr)) { + return "invalid IP address given for a DNS server"; + } + + m_servers.x_server_ip[i] = addr; + m_servers.x_dns_server_port[i] = port ? port : NAMESERVER_PORT; + + if ((MAXDNAME * 2 - 1) > totsz) { + sz = strlen(current); + memcpy((m_servers.x_dns_ip_line + totsz), current, sz); + totsz += sz; + } + } + + m_dnsSrvr_cnt = numTok; + return NULL; +} + + +/* -------------------------------------------------------------- + SplitDNSRecord::ProcessDefDomain() + -------------------------------------------------------------- */ +const char * +SplitDNSRecord::ProcessDefDomain(char *val) +{ + Tokenizer pTok(",; \t\r"); + int numTok; + + numTok = pTok.Initialize(val, SHARE_TOKS); + + if (numTok > 1) { + return "more than one default domain name specified"; + } + + if (numTok == 0) { + return "no default domain name specified"; + } + + int len = 0; + if (pTok[0] && 0 != (len = strlen(pTok[0]))) { + memcpy(&m_servers.x_def_domain[0], pTok[0], len); + m_servers.x_def_domain[len] = '\0'; + } + + return NULL; +} + + +/* -------------------------------------------------------------- + SplitDNSRecord::ProcessDomainSrchList() + -------------------------------------------------------------- */ +const char * +SplitDNSRecord::ProcessDomainSrchList(char *val) +{ + Tokenizer pTok(",; \t\r"); + int numTok; + int cnt = 0, sz = 0; + char *pSp = 0; + const char *current; + + numTok = pTok.Initialize(val, SHARE_TOKS); + + if (numTok == 0) { + return "No servers specified"; + } + + pSp = &m_servers.x_domain_srch_list[0]; + + for (int i = 0; i < numTok; i++) { + current = pTok[i]; + cnt = sz += strlen(current); + + if (MAXDNAME - 1 < sz) + break; + + memcpy(pSp, current, cnt); + pSp += (cnt + 1); + } + + m_domain_srch_list = numTok; + return NULL; +} + + +/* -------------------------------------------------------------- + SplitDNSRecord::Init() + + matcher_line* line_info - contains parsed label/value pairs + of the current split.config line + -------------------------------------------------------------- */ +char * +SplitDNSRecord::Init(matcher_line * line_info) +{ + const char *errPtr = NULL; + const int errBufLen = 1024; + char *errBuf = (char *) xmalloc(errBufLen * sizeof(char)); + const char *tmp; + char *label; + char *val; + + this->line_num = line_info->line_num; + for (int i = 0; i < MATCHER_MAX_TOKENS; i++) { + label = line_info->line[0][i]; + val = line_info->line[1][i]; + + if (label == NULL) { + continue; + } + + if (strcasecmp(label, "def_domain") == 0) { + if (NULL != (errPtr = ProcessDefDomain(val))) { + snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num); + return errBuf; + } + line_info->line[0][i] = NULL; + line_info->num_el--; + continue; + } + + if (strcasecmp(label, "search_list") == 0) { + if (NULL != (errPtr = ProcessDomainSrchList(val))) { + snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num); + return errBuf; + } + line_info->line[0][i] = NULL; + line_info->num_el--; + continue; + } + + if (strcasecmp(label, "named") == 0) { + if (NULL != (errPtr = ProcessDNSHosts(val))) { + snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num); + return errBuf; + } + line_info->line[0][i] = NULL; + line_info->num_el--; + continue; + } + } + + if (this->m_servers.x_server_ip[0] == 0) { + snprintf(errBuf, errBufLen, "%s No server specified in splitdns.config at line %d", modulePrefix, line_num); + return errBuf; + } + + DNSHandler *dnsH = new DNSHandler; + ink_res_state res = new __ink_res_state; + + memset(res, 0, sizeof(__ink_res_state)); + if ((-1 == ink_res_init(res, m_servers.x_server_ip, m_servers.x_dns_server_port, + m_servers.x_def_domain, m_servers.x_domain_srch_list, NULL))) { + snprintf(errBuf, errBufLen, "Failed to build res record for the servers %u ... on port %d", + m_servers.x_server_ip[0], m_servers.x_dns_server_port[0]); + return errBuf; + } + + dnsH->m_res = res; + dnsH->mutex = SplitDNSConfig::dnsHandler_mutex; + dnsH->options = res->options; + dnsH->ip = DEFAULT_DOMAIN_NAME_SERVER; + dnsH->port = DOMAIN_SERVICE_PORT; + + m_servers.x_dnsH = dnsH; + + SET_CONTINUATION_HANDLER(dnsH, &DNSHandler::startEvent_sdns); + (eventProcessor.eventthread[ET_DNS][0])->schedule_imm(dnsH); + + /* ----------------------------------------------------- + Process any modifiers to the directive, if they exist + ----------------------------------------------------- */ + if (line_info->num_el > 0) { + tmp = ProcessModifiers(line_info); + if (tmp != NULL) { + snprintf(errBuf, errBufLen, "%s %s at line %d in splitdns.config", modulePrefix, tmp, line_num); + return errBuf; + } + } + + if (errBuf) + xfree(errBuf); + + return NULL; +} + + +/* -------------------------------------------------------------- + SplitDNSRecord::UpdateMatch() + -------------------------------------------------------------- */ +void +SplitDNSRecord::UpdateMatch(SplitDNSResult * result, RD * rdata) +{ + NOWARN_UNUSED(rdata); + int last_number = result->m_line_number; + + if ((last_number<0) || (last_number> this->line_num)) { + result->m_rec = this; + result->m_line_number = this->line_num; + + Debug("splitdns_config", "Matched with 0x%x dns node from line %d", this, this->line_num); + } +} + + +/* -------------------------------------------------------------- + SplitDNSRecord::Print() + -------------------------------------------------------------- */ +void +SplitDNSRecord::Print() +{ + struct in_addr address; + + for (int i = 0; i < m_dnsSrvr_cnt; i++) { + address.s_addr = m_servers.x_server_ip[i]; + char *pAdr = inet_ntoa(address); + + Debug("splitdns_config", " %s:%d ", pAdr, m_servers.x_dns_server_port[i]); + } +} + + +class SplitDNSConfigInfoReleaser:public Continuation +{ +public: + SplitDNSConfigInfoReleaser(unsigned int id, SplitDNSConfigInfo * info) + : Continuation(new_ProxyMutex()), m_id(id), m_info(info) + { + SET_HANDLER(&SplitDNSConfigInfoReleaser::handle_event); + } + + int handle_event(int event, void *edata) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(edata); + SplitDNSconfigProcessor.release(m_id, m_info); + delete this; + return 0; + } + +public: + unsigned int m_id; + SplitDNSConfigInfo *m_info; +}; + +SplitDNSConfigProcessor::SplitDNSConfigProcessor() + : ninfos(0) +{ + for (int i = 0; i < MAX_CONFIGS; i++) { + infos[i] = NULL; + } +} + +unsigned int +SplitDNSConfigProcessor::set(unsigned int id, SplitDNSConfigInfo * info) +{ + SplitDNSConfigInfo *old_info; + int idx; + + if (id == 0) { + id = ink_atomic_increment((int *) &ninfos, 1) + 1; + ink_assert(id != 0); + ink_assert(id <= MAX_CONFIGS); + } + + info->m_refcount = 1; + + if (id > MAX_CONFIGS) { + // invalid index + Error("[SplitDNSConfigProcessor::set] invalid index"); + return 0; + } + + idx = id - 1; + + do { + old_info = (SplitDNSConfigInfo *) infos[idx]; + } while (!ink_atomic_cas_ptr((pvvoidp) & infos[idx], old_info, info)); + + if (old_info) { + eventProcessor.schedule_in(NEW(new SplitDNSConfigInfoReleaser(id, old_info)), HRTIME_SECONDS(60)); + } + + return id; +} + +SplitDNSConfigInfo * +SplitDNSConfigProcessor::get(unsigned int id) +{ + SplitDNSConfigInfo *info; + int idx; + + ink_assert(id != 0); + ink_assert(id <= MAX_CONFIGS); + + if (id == 0 || id > MAX_CONFIGS) { + // return NULL, because we of an invalid index + return NULL; + } + + idx = id - 1; + info = (SplitDNSConfigInfo *) infos[idx]; + if (ink_atomic_increment((int *) &info->m_refcount, 1) < 0) { + ink_assert(!"not reached"); + } + + return info; +} + +void +SplitDNSConfigProcessor::release(unsigned int id, SplitDNSConfigInfo * info) +{ + int val; + int idx; + + ink_assert(id != 0); + ink_assert(id <= MAX_CONFIGS); + + if (id == 0 || id > MAX_CONFIGS) { + // nothing to delete since we have an invalid index + return; + } + + idx = id - 1; + val = ink_atomic_increment((int *) &info->m_refcount, -1); + if ((infos[idx] != info) && (val == 1)) { + delete info; + } +} + +void +ink_split_dns_init(ModuleVersion v) +{ + static int init_called = 0; + + ink_release_assert(!checkModuleVersion(v, SPLITDNS_MODULE_VERSION)); + if (init_called) + return; + + init_called = 1; +} + +#endif // SPLIT_DNS diff --git a/iocore/dns/test_I_DNS.cc b/iocore/dns/test_I_DNS.cc new file mode 100644 index 00000000..a1edca17 --- /dev/null +++ b/iocore/dns/test_I_DNS.cc @@ -0,0 +1,138 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include "I_DNS.h" +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" +//#define USE_SOCKS + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i, e; + char *p, *dt, *at; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + +main() +{ + init_diags("net_test", NULL); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + + signal(SIGPIPE, SIG_IGN); + eventProcessor.start(2); + netProcessor.start(); + + printf("hello world\n"); + + dnsProcessor.start(); + this_ethread()->execute(); +} diff --git a/iocore/dns/test_P_DNS.cc b/iocore/dns/test_P_DNS.cc new file mode 100644 index 00000000..d340391d --- /dev/null +++ b/iocore/dns/test_P_DNS.cc @@ -0,0 +1,83 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_DNS.h" + +Diags *diags; +struct NetTesterSM:public Continuation +{ + VIO *read_vio; + IOBufferReader *reader; + NetVConnection *vc; + MIOBuffer *buf; + + NetTesterSM(ProxyMutex * _mutex, NetVConnection * _vc):Continuation(_mutex) + { + MUTEX_TRY_LOCK(lock, mutex, _vc->thread); + ink_release_assert(lock); + vc = _vc; + SET_HANDLER(&NetTesterSM::handle_read); + buf = new_MIOBuffer(8); + reader = buf->alloc_reader(); + read_vio = vc->do_io_read(this, INT64_MAX, buf); + } + + + int handle_read(int event, void *data) + { + int r; + char *str; + switch (event) { + case VC_EVENT_READ_READY: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + printf("%s", str); + fflush(stdout); + break; + case VC_EVENT_READ_COMPLETE: + /* FALLSTHROUGH */ + case VC_EVENT_EOS: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + printf("%s", str); + fflush(stdout); + case VC_EVENT_ERROR: + vc->do_io_close(); + // fixme + // handle timeout events + break; + default: + ink_release_assert(!"unknown event"); + + } + return EVENT_CONT; + } + + +}; + +main() +{ +} diff --git a/iocore/eventsystem/EventSystem.cc b/iocore/eventsystem/EventSystem.cc new file mode 100644 index 00000000..70e5136f --- /dev/null +++ b/iocore/eventsystem/EventSystem.cc @@ -0,0 +1,47 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + EventSystem.cc -- + + +****************************************************************************/ + +#include "P_EventSystem.h" + +void +ink_event_system_init(ModuleVersion v) +{ + ink_release_assert(!checkModuleVersion(v, EVENT_SYSTEM_MODULE_VERSION)); + int config_max_iobuffer_size = DEFAULT_MAX_BUFFER_SIZE; + + IOCORE_ReadConfigInteger(config_max_iobuffer_size, "proxy.config.io.max_buffer_size"); + + max_iobuffer_size = buffer_size_to_index(config_max_iobuffer_size, DEFAULT_BUFFER_SIZES - 1); + if (default_small_iobuffer_size > max_iobuffer_size) + default_small_iobuffer_size = max_iobuffer_size; + if (default_large_iobuffer_size > max_iobuffer_size) + default_large_iobuffer_size = max_iobuffer_size; + init_buffer_allocators(); +} diff --git a/iocore/eventsystem/IOBuffer.cc b/iocore/eventsystem/IOBuffer.cc new file mode 100644 index 00000000..e653421a --- /dev/null +++ b/iocore/eventsystem/IOBuffer.cc @@ -0,0 +1,271 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/************************************************************************** + UIOBuffer.cc + +**************************************************************************/ + +#include "P_EventSystem.h" + +// +// General Buffer Allocator +// +inkcoreapi Allocator ioBufAllocator[DEFAULT_BUFFER_SIZES]; +inkcoreapi ClassAllocator ioAllocator("ioAllocator", DEFAULT_BUFFER_NUMBER); +inkcoreapi ClassAllocator ioDataAllocator("ioDataAllocator", DEFAULT_BUFFER_NUMBER); +inkcoreapi ClassAllocator ioBlockAllocator("ioBlockAllocator", DEFAULT_BUFFER_NUMBER); +int64_t default_large_iobuffer_size = DEFAULT_LARGE_BUFFER_SIZE; +int64_t default_small_iobuffer_size = DEFAULT_SMALL_BUFFER_SIZE; +int64_t max_iobuffer_size = DEFAULT_BUFFER_SIZES - 1; + +// +// Initialization +// +void +init_buffer_allocators() +{ + char *name; + + for (int i = 0; i < DEFAULT_BUFFER_SIZES; i++) { + int64_t s = DEFAULT_BUFFER_BASE_SIZE * (((int64_t)1) << i); + int64_t a = DEFAULT_BUFFER_ALIGNMENT; + int n = i <= default_large_iobuffer_size ? DEFAULT_BUFFER_NUMBER : DEFAULT_HUGE_BUFFER_NUMBER; + if (s < a) + a = s; + + name = NEW(new char[64]); + snprintf(name, 64, "ioBufAllocator[%d]", i); + ioBufAllocator[i].re_init(name, s, n, a); + } +} + +int64_t +MIOBuffer::remove_append(IOBufferReader * r) +{ + int64_t l = 0; + while (r->block) { + Ptr b = r->block; + r->block = r->block->next; + b->_start += r->start_offset; + if (b->start() >= b->end()) { + r->start_offset = -r->start_offset; + continue; + } + r->start_offset = 0; + l += b->read_avail(); + append_block(b); + } + r->mbuf->_writer = NULL; + return l; +} + +int64_t +MIOBuffer::write(const void *abuf, int64_t alen) +{ + const char *buf = (const char*)abuf; + int64_t len = alen; + while (len) { + if (!_writer) + add_block(); + int64_t f = _writer->write_avail(); + f = f < len ? f : len; + if (f > 0) { + ::memcpy(_writer->end(), buf, f); + _writer->fill(f); + buf += f; + len -= f; + } + if (len) { + if (!_writer->next) + add_block(); + else + _writer = _writer->next; + } + } + return alen; +} + + +#ifdef WRITE_AND_TRANSFER + /* + * Same functionality as write but for the one small difference. + * The space available in the last block is taken from the original + * and this space becomes available to the copy. + * + */ +int64_t +MIOBuffer::write_and_transfer_left_over_space(IOBufferReader * r, int64_t alen, int64_t offset) +{ + int64_t rval = write(r, alen, offset); + // reset the end markers of the original so that it cannot + // make use of the space in the current block + if (r->mbuf->_writer) + r->mbuf->_writer->_buf_end = r->mbuf->_writer->_end; + // reset the end marker of the clone so that it can make + // use of the space in the current block + if (_writer) { + _writer->_buf_end = _writer->data->data() + _writer->block_size(); + } + return rval; +} + +#endif + + +int64_t +MIOBuffer::write(IOBufferReader * r, int64_t alen, int64_t offset) +{ + int64_t len = alen; + IOBufferBlock *b = r->block; + offset += r->start_offset; + + while (b && len > 0) { + int64_t max_bytes = b->read_avail(); + max_bytes -= offset; + if (max_bytes <= 0) { + offset = -max_bytes; + b = b->next; + continue; + } + int64_t bytes; + if (len<0 || len>= max_bytes) + bytes = max_bytes; + else + bytes = len; + IOBufferBlock *bb = b->clone(); + bb->_start += offset; + bb->_buf_end = bb->_end = bb->_start + bytes; + append_block(bb); + offset = 0; + len -= bytes; + b = b->next; + } + return alen - len; +} + +int64_t +MIOBuffer::puts(char *s, int64_t len) +{ + char *pc = end(); + char *pb = s; + while (pc < buf_end()) { + if (len-- <= 0) + return -1; + if (!*pb || *pb == '\n') { + int64_t n = (int64_t) (pb - s); + memcpy(end(), s, n + 1); // Upto and including '\n' + end()[n + 1] = 0; + fill(n + 1); + return n + 1; + } + pc++; + pb++; + } + return 0; +} + +int64_t +IOBufferReader::read(void *ab, int64_t len) +{ + char *b = (char*)ab; + int64_t max_bytes = read_avail(); + int64_t bytes = len <= max_bytes ? len : max_bytes; + int64_t n = bytes; + + while (n) { + int64_t l = block_read_avail(); + if (n < l) + l = n; + ::memcpy(b, start(), l); + consume(l); + b += l; + n -= l; + } + return bytes; +} + +// TODO: I don't think this method is used anywhere, so perhaps get rid of it ? +int64_t +IOBufferReader::memchr(char c, int64_t len, int64_t offset) +{ + IOBufferBlock *b = block; + offset += start_offset; + int64_t o = offset; + + while (b && len) { + int64_t max_bytes = b->read_avail(); + max_bytes -= offset; + if (max_bytes <= 0) { + offset = -max_bytes; + b = b->next; + continue; + } + int64_t bytes; + if (len<0 || len>= max_bytes) + bytes = max_bytes; + else + bytes = len; + char *s = b->start() + offset; + char *p = (char *) ::memchr(s, c, bytes); + if (p) + return (int64_t) (o - start_offset + p - s); + o += bytes; + len -= bytes; + b = b->next; + offset = 0; + } + + return -1; +} + +char * +IOBufferReader::memcpy(const void *ap, int64_t len, int64_t offset) +{ + char *p = (char*)ap; + IOBufferBlock *b = block; + offset += start_offset; + + while (b && len) { + int64_t max_bytes = b->read_avail(); + max_bytes -= offset; + if (max_bytes <= 0) { + offset = -max_bytes; + b = b->next; + continue; + } + int64_t bytes; + if (len<0 || len>= max_bytes) + bytes = max_bytes; + else + bytes = len; + ::memcpy(p, b->start() + offset, bytes); + p += bytes; + len -= bytes; + b = b->next; + offset = 0; + } + + return p; +} diff --git a/iocore/eventsystem/I_Action.h b/iocore/eventsystem/I_Action.h new file mode 100644 index 00000000..8f256a80 --- /dev/null +++ b/iocore/eventsystem/I_Action.h @@ -0,0 +1,213 @@ +/** @file + + Generic interface which enables any event or async activity to be cancelled + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef _I_Action_h_ +#define _I_Action_h_ + +#include "libts.h" +#include "I_Thread.h" +#include "I_Continuation.h" + +/** + Represents an operation initiated on a Processor. + + The Action class is an abstract representation of an operation + being executed by some Processor. A reference to an Action object + allows you to cancel an ongoing asynchronous operation before it + completes. This means that the Continuation specified for the + operation will not be called back. + + Actions or classes derived from Action are the typical return + type of methods exposed by Processors in the Event System and + throughout the IO Core libraries. + + The canceller of an action must be the state machine that will + be called back by the task and that state machine's lock must be + held while calling cancel. + + Processor implementers: + + You must ensure that no events are sent to the state machine after + the operation has been cancelled appropriately. + + Returning an Action: + + Processor functions that are asynchronous must return actions to + allow the calling state machine to cancel the task before completion. + Because some processor functions are reentrant, they can call + back the state machine before the returning from the call that + creates the actions. To handle this case, special values are + returned in place of an action to indicate to the state machine + that the action is already completed. + + - @b ACTION_RESULT_DONE The processor has completed the task + and called the state machine back inline. + - @b ACTION_RESULT_INLINE Not currently used. + - @b ACTION_RESULT_IO_ERROR Not currently used. + + To make matters more complicated, it's possible if the result is + ACTION_RESULT_DONE that state machine deallocated itself on the + reentrant callback. Thus, state machine implementers MUST either + use a scheme to never deallocate their machines on reentrant + callbacks OR immediately check the returned action when creating + an asynchronous task and if it is ACTION_RESULT_DONE neither read + nor write any state variables. With either method, it's imperative + that the returned action always be checked for special values and + the value handled accordingly. + + Allocation policy: + + Actions are allocated by the Processor performing the actions. + It is the processor's responsbility to handle deallocation once + the action is complete or cancelled. A state machine MUST NOT + access an action once the operation that returned the Action has + completed or it has cancelled the Action. + +*/ +class Action +{ + +public: + + /** + Contination that initiated this action. + + The reference to the initiating continuation is only used to + verify that the action is being cancelled by the correct + continuation. This field should not be accesed or modified + directly by the state machine. + + */ + Continuation * continuation; + + + /** + Reference to the Continuation's lock. + + Keeps a reference to the Continuation's lock to preserve the + access to the cancelled field valid even when the state machine + has been deallocated. This field should not be accesed or + modified directly by the state machine. + + */ + Ptr mutex; + + /** + Internal flag used to indicate whether the action has been + cancelled. + + This flag is set after a call to cancel or cancel_action and + it should not be accesed or modified directly by the state + machine. + + */ + volatile int cancelled; + + /** + Cancels the asynchronous operation represented by this action. + + This method is called by state machines willing to cancel an + ongoing asynchronous operation. Classes derived from Action may + perform additional steps before flagging this action as cancelled. + There are certain rules that must be followed in order to cancel + an action (see the Remarks section). + + @param c Continuation associated with this Action. + + */ + virtual void cancel(Continuation * c = NULL) { + ink_assert(!c || c == continuation); +#ifdef DEBUG + ink_assert(!cancelled); + cancelled = true; +#else + if (!cancelled) + cancelled = true; +#endif + } + + /** + Cancels the asynchronous operation represented by this action. + + This method is called by state machines willing to cancel an + ongoing asynchronous operation. There are certain rules that + must be followed in order to cancel an action (see the Remarks + section). + + @param c Continuation associated with this Action. + + */ + void cancel_action(Continuation * c = NULL) { + ink_assert(!c || c == continuation); +#ifdef DEBUG + ink_assert(!cancelled); + cancelled = true; +#else + if (!cancelled) + cancelled = true; +#endif + } + + Continuation *operator =(Continuation * acont) + { + continuation = acont; + if (acont) + mutex = acont->mutex; + else + mutex = 0; + return acont; + } + + /** + Constructor of the Action object. Processor implementers are + responsible for associating this action with the proper + Continuation. + + */ +Action():continuation(NULL), cancelled(false) { + } + +#if defined(__GNUC__) + virtual ~ Action() { + } +#endif +}; + +#define ACTION_RESULT_NONE MAKE_ACTION_RESULT(0) +#define ACTION_RESULT_DONE MAKE_ACTION_RESULT(1) +#define ACTION_IO_ERROR MAKE_ACTION_RESULT(2) +#define ACTION_RESULT_INLINE MAKE_ACTION_RESULT(3) + +// Use these classes by +// #define ACTION_RESULT_HOST_DB_OFFLINE +// MAKE_ACTION_RESULT(ACTION_RESULT_HOST_DB_BASE + 0) + +#define MAKE_ACTION_RESULT(_x) (Action*)(((uintptr_t)((_x<<1)+1))) + +#define ACTION_RESULT(_x) \ + (int)((((uintptr_t)_x)&1)!=0?(((uintptr_t)>>1):(uintptr_t)0)) + +#define IS_ACTION_RESULT(_x) ((((uintptr_t)_x)&1) != 0) + +#endif /*_Action_h_*/ diff --git a/iocore/eventsystem/I_Continuation.h b/iocore/eventsystem/I_Continuation.h new file mode 100644 index 00000000..e5a8e53a --- /dev/null +++ b/iocore/eventsystem/I_Continuation.h @@ -0,0 +1,200 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Continuations have a handleEvent() method to invoke them. Users + can determine the behavior of a Continuation by suppling a + "ContinuationHandler" (member function name) which is invoked + when events arrive. This function can be changed with the + "setHandler" method. + + Continuations can be subclassed to add additional state and + methods. + + */ + +#ifndef _I_Continuation_h_ +#define _I_Continuation_h_ + +#include "libts.h" +#include "I_Lock.h" + +class Continuation; +class ContinuationQueue; +class Processor; +class ProxyMutex; +class EThread; + +////////////////////////////////////////////////////////////////////////////// +// +// Constants and Type Definitions +// +////////////////////////////////////////////////////////////////////////////// + +#define CONTINUATION_EVENT_NONE 0 + +#define CONTINUATION_DONE 0 +#define CONTINUATION_CONT 1 + +typedef int (Continuation::*ContinuationHandler) (int event, void *data); + +class force_VFPT_to_top +{ +public: + virtual ~force_VFPT_to_top() + { + } +}; + +/** + Base class for all state machines to receive notification of + events. + + The Continuation class represents the main abstraction mechanism + used throughout the IO Core Event System to communicate its users + the occurrence of an event. A Continuation is a lightweight data + structure that implements a single method with which the user is + called back. + + Continuations are typically subclassed in order to implement + event-driven state machines. By including additional state and + methods, continuations can combine state with control flow, and + they are generally used to support split-phase, event-driven + control flow. + + Given the multithreaded nature of the Event System, every + continuation carries a reference to a ProxyMutex object to protect + its state and ensure atomic operations. This ProxyMutex object + must be allocated by continuation-derived classes or by clients + of the IO Core Event System and it is required as a parameter to + the Continuation's class constructor. + +*/ + +class Continuation: private force_VFPT_to_top +{ +public: + + /** + The current continuation handler function. + + The current handler should not be set directly. In order to + change it, first aquire the Continuation's lock and then use + the SET_HANDLER macro which takes care of the type casting + issues. + + */ + ContinuationHandler handler; + +#ifdef DEBUG + const char *handler_name; +#endif + + /** + The Contination's lock. + + A reference counted pointer to the Continuation's lock. This + lock is initialized in the constructor and should not be set + directly. + + */ + ProxyMutexPtr mutex; + + /** + Link to other continuations. + + A doubly-linked element to allow Lists of Continuations to be + assembled. + + */ + LINK(Continuation, link); + + /** + Receives the event code and data for an Event. + + This function receives the event code and data for an event and + forwards them to the current continuation handler. The processor + calling back the continuation is responsible for acquiring its + lock. + + @param event Event code to be passed at callback (Processor specific). + @param data General purpose data related to the event code (Processor specific). + @return State machine and processor specific return code. + + */ + int handleEvent(int event = CONTINUATION_EVENT_NONE, void *data = 0) { + return (this->*handler) (event, data); + } + + /** + Contructor of the Continuation object. It should not be used + directly. Instead create an object of a derived type. + + @param amutex Lock to be set for this Continuation. + + */ + Continuation(ProxyMutex * amutex = NULL); +}; + +/** + Sets the Continuation's handler. The preferred mechanism for + setting the Continuation's handler. + + @param _h Pointer to the function used to callback with events. + +*/ +#ifdef DEBUG +#define SET_HANDLER(_h) \ + (handler = ((ContinuationHandler)_h),handler_name = #_h) +#else +#define SET_HANDLER(_h) \ + (handler = ((ContinuationHandler)_h)) +#endif + +/** + Sets a Continuation's handler. + + The preferred mechanism for setting the Continuation's handler. + + @param _c Pointer to a Continuation whose handler is being set. + @param _h Pointer to the function used to callback with events. + +*/ +#ifdef DEBUG +#define SET_CONTINUATION_HANDLER(_c,_h) \ + (_c->handler = ((ContinuationHandler) _h),_c->handler_name = #_h) +#else +#define SET_CONTINUATION_HANDLER(_c,_h) \ + (_c->handler = ((ContinuationHandler) _h)) +#endif + +inline +Continuation::Continuation(ProxyMutex * amutex) + : handler(NULL), +#ifdef DEBUG + handler_name(NULL), +#endif + mutex(amutex) +{ } + +#endif /*_Continuation_h_*/ diff --git a/iocore/eventsystem/I_EThread.h b/iocore/eventsystem/I_EThread.h new file mode 100644 index 00000000..c735fed8 --- /dev/null +++ b/iocore/eventsystem/I_EThread.h @@ -0,0 +1,373 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef _EThread_h_ +#define _EThread_h_ + +#include "libts.h" +#include "I_Thread.h" +#include "I_PriorityEventQueue.h" +#include "I_ProxyAllocator.h" +#include "I_ProtectedQueue.h" + +// TODO: This would be much nicer to have "run-time" configurable (or something), +// perhaps based on proxy.config.stat_api.max_stats_allowed or other configs. XXX +#define PER_THREAD_DATA (1024*1024) + +// This is not used by the cache anymore, it uses proxy.config.cache.mutex_retry_delay +// instead. +#define MUTEX_RETRY_DELAY HRTIME_MSECONDS(20) + +/** Maximum number of accept events per thread. */ +#define MAX_ACCEPT_EVENTS 20 + +struct UDPNetHandler; +struct DiskHandler; +struct LogConfiguration; +struct LogEventForwarder; +struct EventIO; + +class SessionBucket; +class NetHandler; +class Event; +class Continuation; +class IOBufferData; +class IOBufferBlock; + +enum ThreadType +{ REGULAR = 0, MONITOR, DEDICATED }; +enum teThreadType +{ keAsyncThread = 0, keBoundThread, keSpawnThread }; + +/** + Event System specific type of thread. + + The EThread class is the type of thread created and managed by + the Event System. It is one of the available interfaces for + schedulling events in the event system (another two are the Event + and EventProcessor classes). + + In order to handle events, each EThread object has two event + queues, one external and one internal. The external queue is + provided for users of the EThread (clients) to append events to + that particular thread. Since it can be accessed by other threads + at the same time, operations using it must proceed in an atomic + fashion. + + The internal queue, in the other hand, is used exclusively by the + EThread to process timed events within a certain time frame. These + events are queued internally and they may come from the external + queue as well. + + Scheduling Interface: + + There are eight schedulling functions provided by EThread and + they are a wrapper around their counterparts in EventProcessor. + Those with the 'local' suffix they do the same on NT?????? + + @see EventProcessor + @see Event + +*/ +class EThread:public Thread +{ +public: + + /*-------------------------------------------------------*\ + | Common Interface | + \*-------------------------------------------------------*/ + + /** + Schedules the continuation on this EThread to receive an event + as soon as possible. + + Forwards to the EventProcessor the schedule of the callback to + the continuation 'c' as soon as possible. The event is assigned + to EThread. + + @param c Continuation to be called back as soon as possible. + @param callback_event Event code to be passed back to the + continuation's handler. See the the EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return Reference to an Event object representing the schedulling + of this callback. + + */ + Event * schedule_imm(Continuation * c, int callback_event = EVENT_IMMEDIATE, void *cookie = NULL); + Event * schedule_imm_signal(Continuation * c, int callback_event = EVENT_IMMEDIATE, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + at the given timeout. + + Forwards the request to the EventProcessor to schedule the + callback to the continuation 'c' at the time specified in + 'atimeout_at'. The event is assigned to this EThread. + + @param c Continuation to be called back at the time specified + in 'atimeout_at'. + @param atimeout_at Time value at which to callback. + @param callback_event Event code to be passed back to the + continuation's handler. See the EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_at(Continuation * c, + ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + after the timeout elapses. + + Instructs the EventProcessor to schedule the callback to the + continuation 'c' after the time specified in atimeout_in elapses. + The event is assigned to this EThread. + + @param c Continuation to be called back after the timeout elapses. + @param atimeout_in Amount of time after which to callback. + @param callback_event Event code to be passed back to the + continuation's handler. See the EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_in(Continuation * c, + ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + periodically. + + Schedules the callback to the continuation 'c' in the EventProcessor + to occur every time 'aperiod' elapses. It is scheduled on this + EThread. + + @param c Continuation to call back everytime 'aperiod' elapses. + @param aperiod Duration of the time period between callbacks. + @param callback_event Event code to be passed back to the + continuation's handler. See the Remarks section in the + EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_every(Continuation * c, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + as soon as possible. + + Schedules the callback to the continuation 'c' as soon as + possible. The event is assigned to this EThread. + + @param c Continuation to be called back as soon as possible. + @param callback_event Event code to be passed back to the + continuation's handler. See the EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_imm_local(Continuation * c, int callback_event = EVENT_IMMEDIATE, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + at the given timeout. + + Schedules the callback to the continuation 'c' at the time + specified in 'atimeout_at'. The event is assigned to this + EThread. + + @param c Continuation to be called back at the time specified + in 'atimeout_at'. + @param atimeout_at Time value at which to callback. + @param callback_event Event code to be passed back to the + continuation's handler. See the EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_at_local(Continuation * c, + ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + after the timeout elapses. + + Schedules the callback to the continuation 'c' after the time + specified in atimeout_in elapses. The event is assigned to this + EThread. + + @param c Continuation to be called back after the timeout elapses. + @param atimeout_in Amount of time after which to callback. + @param callback_event Event code to be passed back to the + continuation's handler. See the Remarks section in the + EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_in_local(Continuation * c, + ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on this EThread to receive an event + periodically. + + Schedules the callback to the continuation 'c' to occur every + time 'aperiod' elapses. It is scheduled on this EThread. + + @param c Continuation to call back everytime 'aperiod' elapses. + @param aperiod Duration of the time period between callbacks. + @param callback_event Event code to be passed back to the + continuation's handler. See the Remarks section in the + EventProcessor class. + @param cookie User-defined value or pointer to be passed back + in the Event's object cookie field. + @return A reference to an Event object representing the schedulling + of this callback. + + */ + Event *schedule_every_local(Continuation * c, + ink_hrtime aperiod, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /* private */ + + Event *schedule_local(Event * e); + + InkRand generator; + ProxyAllocator eventAllocator; + ProxyAllocator netVCAllocator; + ProxyAllocator sslNetVCAllocator; + ProxyAllocator inkioNetVCAllocator; + ProxyAllocator httpClientSessionAllocator; + ProxyAllocator httpServerSessionAllocator; + ProxyAllocator cacheVConnectionAllocator; + ProxyAllocator newCacheVConnectionAllocator; + ProxyAllocator openDirEntryAllocator; + ProxyAllocator ramCacheCLFUSEntryAllocator; + ProxyAllocator ramCacheLRUEntryAllocator; + ProxyAllocator evacuationBlockAllocator; + ProxyAllocator ioDataAllocator; + ProxyAllocator ioBlockAllocator; + ProxyAllocator ioBufAllocator[DEFAULT_BUFFER_SIZES]; + +private: + + // prevent unauthorized copies (Not implemented) + EThread(const EThread &); + EThread & operator =(const EThread &); + + /*-------------------------------------------------------*\ + | UNIX Interface | + \*-------------------------------------------------------*/ + +public: + + EThread(); + EThread(ThreadType att, int anid); + EThread(ThreadType att, Event *e, ink_sem *sem); + virtual ~ EThread(); + + Event *schedule_spawn(Continuation *cont); + + Event *schedule(Event *e, bool fast_signal = false); + + /** Block of memory to allocate thread specific data e.g. stat system arrays. */ + char thread_private[PER_THREAD_DATA]; + + // private data for UDP net processor + //UDPNetHandler *udpNetHandler; + + /** Private Data for the Disk Processor. */ + DiskHandler *diskHandler; + + /** Private Data for AIO. */ + Que(Continuation, link) aio_ops; + + ProtectedQueue EventQueueExternal; + PriorityEventQueue EventQueue; + + EThread **ethreads_to_be_signalled; + int n_ethreads_to_be_signalled; + + Event *accept_event[MAX_ACCEPT_EVENTS]; + int main_accept_index; + + int id; + unsigned int event_types; + bool is_event_type(EventType et); + void set_event_type(EventType et); +#if defined(USE_OLD_EVENTFD) + int getEventFd(); +#endif + // Private Interface + + void execute(); + void process_event(Event * e, int calling_code); + void free_event(Event * e); + void (*signal_hook)(EThread *); + +#if TS_HAS_EVENTFD + int evfd; +#else + int evpipe[2]; +#endif + EventIO *ep; + + ThreadType tt; + Event *oneevent; // For dedicated event thread + ink_sem *eventsem; // For dedicated event thread +}; + +/** + This is used so that we dont use up operator new(size_t, void *) + which users might want to define for themselves. + +*/ +class ink_dummy_for_new +{ +}; +inline void *operator +new(size_t, ink_dummy_for_new * p) +{ + return (void *) p; +} +#define ETHREAD_GET_PTR(thread, offset) ((void*)((char*)(thread)+(offset))) + +TS_INLINE EThread *this_ethread(); +#endif /*_EThread_h_*/ diff --git a/iocore/eventsystem/I_Event.h b/iocore/eventsystem/I_Event.h new file mode 100644 index 00000000..13d6800f --- /dev/null +++ b/iocore/eventsystem/I_Event.h @@ -0,0 +1,283 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef _Event_h_ +#define _Event_h_ + +#include "libts.h" +#include "I_Action.h" + +// +// Defines +// + +#define MAX_EVENTS_PER_THREAD 100000 + +// Events + +#define EVENT_NONE CONTINUATION_EVENT_NONE // 0 +#define EVENT_IMMEDIATE 1 +#define EVENT_INTERVAL 2 +#define EVENT_ERROR 3 +#define EVENT_CALL 4 // used internally in state machines +#define EVENT_POLL 5 // negative event; activated on poll or epoll + +// Event callback return functions + +#define EVENT_DONE CONTINUATION_DONE // 0 +#define EVENT_CONT CONTINUATION_CONT // 1 +#define EVENT_RETURN 5 +#define EVENT_RESTART 6 +#define EVENT_RESTART_DELAYED 7 + +// Event numbers block allocation +// ** ALL NEW EVENT TYPES SHOULD BE ALLOCATED FROM BLOCKS LISTED HERE! ** + +#define VC_EVENT_EVENTS_START 100 +#define NET_EVENT_EVENTS_START 200 +#define DISK_EVENT_EVENTS_START 300 +#define CLUSTER_EVENT_EVENTS_START 400 +#define HOSTDB_EVENT_EVENTS_START 500 +#define DNS_EVENT_EVENTS_START 600 +#define CONFIG_EVENT_EVENTS_START 800 +#define LOG_EVENT_EVENTS_START 900 +#define MULTI_CACHE_EVENT_EVENTS_START 1000 +#define CACHE_EVENT_EVENTS_START 1100 +#define CACHE_DIRECTORY_EVENT_EVENTS_START 1200 +#define CACHE_DB_EVENT_EVENTS_START 1300 +#define HTTP_NET_CONNECTION_EVENT_EVENTS_START 1400 +#define HTTP_NET_VCONNECTION_EVENT_EVENTS_START 1500 +#define GC_EVENT_EVENTS_START 1600 +#define ICP_EVENT_EVENTS_START 1800 +#define TRANSFORM_EVENTS_START 2000 +#define STAT_PAGES_EVENTS_START 2100 +#define HTTP_SESSION_EVENTS_START 2200 +#define HTTP_TUNNEL_EVENTS_START 2300 +#define HTTP_SCH_UPDATE_EVENTS_START 2400 +#define NT_ASYNC_CONNECT_EVENT_EVENTS_START 3000 +#define NT_ASYNC_IO_EVENT_EVENTS_START 3100 +#define RAFT_EVENT_EVENTS_START 3200 +#define SIMPLE_EVENT_EVENTS_START 3300 +#define UPDATE_EVENT_EVENTS_START 3500 +#define LOG_COLLATION_EVENT_EVENTS_START 3800 +#define AIO_EVENT_EVENTS_START 3900 +#define BLOCK_CACHE_EVENT_EVENTS_START 4000 +#define UTILS_EVENT_EVENTS_START 5000 +#define CONGESTION_EVENT_EVENTS_START 5100 +#define INK_API_EVENT_EVENTS_START 60000 +#define SRV_EVENT_EVENTS_START 62000 +#define REMAP_EVENT_EVENTS_START 63000 + +//define misc events here +#define ONE_WAY_TUNNEL_EVENT_PEER_CLOSE (SIMPLE_EVENT_EVENTS_START+1) +#define PREFETCH_EVENT_SEND_URL (SIMPLE_EVENT_EVENTS_START+2) + +typedef int EventType; +const int ET_CALL = 0; +const int MAX_EVENT_TYPES = 8; // conservative, these are dynamically allocated + +class EThread; + +/** + A type of Action returned by the EventProcessor. The Event class + is the type of Action returned by the EventProcessor as a result + of scheduling an operation. Unlike asynchronous operations + represented by actions, events never call reentrantly. + + Besides being able to cancel an event (because it is an action), + you can also reschedule it once received. + + Remarks + + When reschedulling an event through any of the Event class + schedulling fuctions, state machines must not make these calls + in other thread other than the one that called them back. They + also must have acquired the continuation's lock before calling + any of the schedulling functions. + + The rules for cancelling an event are the same as those for + actions: + + The canceller of an event must be the state machine that will be + called back by the task and that state machine's lock must be + held while calling cancel. Any reference to that event object + (ie. pointer) held by the state machine must not be used after + the cancellation. + + Event Codes: + + At the completion of an event, state machines use the event code + passed in through the Continuation's handler function to distinguish + the type of event and handle the data parameter accordingly. State + machine implementers should be careful when defining the event + codes since they can impact on other state machines presents. For + this reason, this numbers are usually allocated from a common + pool. + + Time values: + + The schedulling functions use a time parameter typed as ink_hrtime + for specifying the timeouts or periods. This is a nanosecond value + supported by libts and you should use the time functions and + macros defined in ink_hrtime.h. + + The difference between the timeout specified for schedule_at and + schedule_in is that in the former it is an absolute value of time + that is expected to be in the future where in the latter it is + an amount of time to add to the current time (obtained with + ink_get_hrtime). + +*/ +class Event:public Action +{ +public: + + /////////////////////////////////////////////////////////// + // Common Interface // + /////////////////////////////////////////////////////////// + + /** + Reschedules this event immediately. Instructs the event object + to reschedule itself as soon as possible in the EventProcessor. + + @param callback_event Event code to return at the completion + of this event. See the Remarks section. + + */ + void schedule_imm(int callback_event = EVENT_IMMEDIATE); + + /** + Reschedules this event to callback at time 'atimeout_at'. + Instructs the event object to reschedule itself at the time + specified in atimeout_at on the EventProcessor. + + @param atimeout_at Time at which to callcallback. See the Remarks section. + @param callback_event Event code to return at the completion of this event. See the Remarks section. + + */ + void schedule_at(ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL); + + /** + Reschedules this event to callback at time 'atimeout_at'. + Instructs the event object to reschedule itself at the time + specified in atimeout_at on the EventProcessor. + + @param atimeout_in Time at which to callcallback. See the Remarks section. + @param callback_event Event code to return at the completion of this event. See the Remarks section. + + */ + void schedule_in(ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL); + + /** + Reschedules this event to callback every 'aperiod'. Instructs + the event object to reschedule itself to callback every 'aperiod' + from now. + + @param aperiod Time period at which to callcallback. See the Remarks section. + @param callback_event Event code to return at the completion of this event. See the Remarks section. + + */ + void schedule_every(ink_hrtime aperiod, int callback_event = EVENT_INTERVAL); + + // inherited from Action::cancel + // virtual void cancel(Continuation * c = NULL); + + void free(); + + EThread *ethread; + + unsigned int in_the_prot_queue:1; + unsigned int in_the_priority_queue:1; + unsigned int immediate:1; + unsigned int globally_allocated:1; + unsigned int in_heap:4; + int callback_event; + + ink_hrtime timeout_at; + ink_hrtime period; + + /** + This field can be set when an event is created. It is returned + as part of the Event structure to the continuation when handleEvent + is called. + + */ + void *cookie; + + // Private + + Event(); + + + Event *init(Continuation * c, ink_hrtime atimeout_at = 0, ink_hrtime aperiod = 0); + +#ifdef ENABLE_TIME_TRACE + ink_hrtime start_time; +#endif + +private: + void *operator new(size_t size); // use the fast allocators + +private: + // prevent unauthorized copies (Not implemented) + Event(const Event &); + Event & operator =(const Event &); + +public: + LINK(Event, link); + + /*-------------------------------------------------------*\ + | UNIX/non-NT Interface | + \*-------------------------------------------------------*/ + +#ifdef ONLY_USED_FOR_FIB_AND_BIN_HEAP + void *node_pointer; + void set_node_pointer(void *x) + { + node_pointer = x; + } + void *get_node_pointer() + { + return node_pointer; + } +#endif + +#if defined(__GNUC__) + virtual ~ Event() { + } +#endif +}; + +// +// Event Allocator +// +extern ClassAllocator eventAllocator; + +#define EVENT_ALLOC(_a, _t) THREAD_ALLOC(_a, _t) +#define EVENT_FREE(_p, _a, _t) \ + _p->mutex = NULL; \ + if (_p->globally_allocated) ::_a.free(_p); \ + else THREAD_FREE_TO(_p, _a, _t, MAX_EVENTS_PER_THREAD) + +#endif /*_Event_h_*/ diff --git a/iocore/eventsystem/I_EventProcessor.h b/iocore/eventsystem/I_EventProcessor.h new file mode 100644 index 00000000..4cc16b06 --- /dev/null +++ b/iocore/eventsystem/I_EventProcessor.h @@ -0,0 +1,315 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_EventProcessor_h_ +#define _I_EventProcessor_h_ + +#include "libts.h" +#include "I_Continuation.h" +#include "I_Processor.h" +#include "I_Event.h" + +const int MAX_THREADS_IN_EACH_TYPE = 512; +const int MAX_EVENT_THREADS = 512; + +class EThread; + +/** + Main processor for the Event System. The EventProcessor is the core + component of the Event System. Once started, it is responsible for + creating and managing groups of threads that execute user-defined + tasks asynchronously at a given time or periodically. + + The EventProcessor provides a set of scheduling functions through + which you can specify continuations to be called back by one of its + threads. These function calls do not block. Instead they return an + Event object and schedule the callback to the continuation passed in at + a later or specific time, as soon as possible or at certain intervals. + + Singleton model: + + Every executable that imports and statically links against the + EventSystem library is provided with a global instance of the + EventProcessor called eventProcessor. Therefore, it is not necessary to + create instances of the EventProcessor class because it was designed + as a singleton. It is important to note that none of its functions + are reentrant. + + Thread Groups (Event types): + + When the EventProcessor is started, the first group of threads is + spawned and it is assigned the special id ET_CALL. Depending on the + complexity of the state machine or protocol, you may be interested + in creating additional threads and the EventProcessor gives you the + ability to create a single thread or an entire group of threads. In + the former case, you call spawn_thread and the thread is independent + of the thread groups and it exists as long as your continuation handle + executes and there are events to process. In the latter, you call + spawn_event_theads which creates a new thread group and you get an id + or event type with wich you must keep for use later on when scheduling + continuations on that group. + + Callback event codes: + + @b UNIX: For all of the scheduling functions, the callback_event + parameter is not used. On a callback, the event code passed in to + the continuation handler is always EVENT_IMMEDIATE. + + @b NT: The value of the event code passed in to the continuation + handler is the value provided in the callback_event parameter. + + Event allocation policy: + + Events are allocated and deallocated by the EventProcessor. A state + machine may access the returned, non-recurring event until it is + cancelled or the callback from the event is complete. For recurring + events, the Event may be accessed until it is cancelled. Once the event + is complete or cancelled, it's the eventProcessor's responsibility to + deallocate it. + +*/ +class EventProcessor:public Processor +{ +public: + + /** + Spawn an additional thread for calling back the continuation. Spawns + a dedicated thread (EThread) that calls back the continuation passed + in as soon as possible. + + @param cont continuation that the spawn thread will call back + immediately. + @param sem Unix: Event semaphore assigned to the thread. NT: Not used. + @return event object representing the start of the thread. + + */ + Event *spawn_thread(Continuation * cont, const char *thr_name, ink_sem * sem = NULL); + + /** + Spawns a group of threads for an event type. Spawns the number of + event threads passed in (n_threads) creating a thread group and + returns the thread group id (or EventType). See the remarks section + for Thread Groups. + + @return EventType or thread id for the new group of threads. + + */ + EventType spawn_event_threads(int n_threads, const char* et_name); + + + /** + Schedules the continuation on a specific EThread to receive an event + at the given timeout. Requests the EventProcessor to schedule + the callback to the continuation 'c' at the time specified in + 'atimeout_at'. The event is assigned to the specified EThread. + + @param c Continuation to be called back at the time specified in + 'atimeout_at'. + @param atimeout_at time value at which to callback. + @param ethread EThread on which to schedule the event. + @param callback_event code to be passed back to the continuation's + handler. See the Remarks section. + @param cookie user-defined value or pointer to be passed back in + the Event's object cookie field. + @return reference to an Event object representing the scheduling + of this callback. + + */ + Event *schedule_imm(Continuation * c, + EventType event_type = ET_CALL, int callback_event = EVENT_IMMEDIATE, void *cookie = NULL); + /* + provides the same functionality as schedule_imm and also signals the thread immediately + */ + Event *schedule_imm_signal(Continuation * c, + EventType event_type = ET_CALL, int callback_event = EVENT_IMMEDIATE, void *cookie = NULL); + /** + Schedules the continuation on a specific thread group to receive an + event at the given timeout. Requests the EventProcessor to schedule + the callback to the continuation 'c' at the time specified in + 'atimeout_at'. The callback is handled by a thread in the specified + thread group (event_type). + + @param c Continuation to be called back at the time specified in + 'atimeout_at'. + @param atimeout_at Time value at which to callback. + @param event_type thread group id (or event type) specifying the + group of threads on which to schedule the callback. + @param callback_event code to be passed back to the continuation's + handler. See the Remarks section. + @param cookie user-defined value or pointer to be passed back in + the Event's object cookie field. + @return reference to an Event object representing the scheduling of + this callback. + + */ + Event *schedule_at(Continuation * c, + ink_hrtime atimeout_at, + EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on a specific thread group to receive an + event after the specified timeout elapses. Requests the EventProcessor + to schedule the callback to the continuation 'c' after the time + specified in 'atimeout_in' elapses. The callback is handled by a + thread in the specified thread group (event_type). + + @param c Continuation to call back aftert the timeout elapses. + @param atimeout_in amount of time after which to callback. + @param event_type Thread group id (or event type) specifying the + group of threads on which to schedule the callback. + @param callback_event code to be passed back to the continuation's + handler. See the Remarks section. + @param cookie user-defined value or pointer to be passed back in + the Event's object cookie field. + @return reference to an Event object representing the scheduling of + this callback. + + */ + Event *schedule_in(Continuation * c, + ink_hrtime atimeout_in, + EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + /** + Schedules the continuation on a specific thread group to receive + an event periodically. Requests the EventProcessor to schedule the + callback to the continuation 'c' everytime 'aperiod' elapses. The + callback is handled by a thread in the specified thread group + (event_type). + + @param c Continuation to call back everytime 'aperiod' elapses. + @param aperiod duration of the time period between callbacks. + @param event_type thread group id (or event type) specifying the + group of threads on which to schedule the callback. + @param callback_event code to be passed back to the continuation's + handler. See the Remarks section. + @param cookie user-defined value or pointer to be passed back in + the Event's object cookie field. + @return reference to an Event object representing the scheduling of + this callback. + + */ + Event *schedule_every(Continuation * c, + ink_hrtime aperiod, + EventType event_type = ET_CALL, int callback_event = EVENT_INTERVAL, void *cookie = NULL); + + + //////////////////////////////////////////// + // reschedule an already scheduled event. // + // may be called directly or called by // + // schedule_xxx Event member functions. // + // The returned value may be different // + // from the argument e. // + //////////////////////////////////////////// + + Event *reschedule_imm(Event * e, int callback_event = EVENT_IMMEDIATE); + Event *reschedule_at(Event * e, ink_hrtime atimeout_at, int callback_event = EVENT_INTERVAL); + Event *reschedule_in(Event * e, ink_hrtime atimeout_in, int callback_event = EVENT_INTERVAL); + Event *reschedule_every(Event * e, ink_hrtime aperiod, int callback_event = EVENT_INTERVAL); + + EventProcessor(); + + /** + Initializes the EventProcessor and its associated threads. Spawns the + specified number of threads, initializes their state information and + sets them running. It creates the initial thread group, represented + by the event type ET_CALL. + + @return 0 if successful, and a negative value otherwise. + + */ + int start(int n_net_threads); + + /** + Stop the EventProcessor. Attempts to stop the EventProcessor and + all of the threads in each of the thread groups. + + */ + virtual void shutdown(); + + /** + Allocates size bytes on the event threads. This function is thread + safe. + + @param size bytes to be allocated. + + */ + off_t allocate(int size); + + /** + An array of pointers to all of the EThreads handled by the + EventProcessor. An array of pointers to all of the EThreads created + throughout the existence of the EventProcessor instance. + + */ + EThread *all_ethreads[MAX_EVENT_THREADS]; + + /** + An array of pointers, organized by thread group, to all of the + EThreads handled by the EventProcessor. An array of pointers to all of + the EThreads created throughout the existence of the EventProcessor + instance. It is a two-dimensional array whose first dimension is the + thread group id and the second the EThread pointers for that group. + + */ + EThread *eventthread[MAX_EVENT_TYPES][MAX_THREADS_IN_EACH_TYPE]; + + unsigned int next_thread_for_type[MAX_EVENT_TYPES]; + int n_threads_for_type[MAX_EVENT_TYPES]; + + /** + Total number of threads controlled by this EventProcessor. This is + the count of all the EThreads spawn by this EventProcessor, excluding + those created by spawn_thread + + */ + int n_ethreads; + + /** + Total number of thread groups created so far. This is the count of + all the thread groups (event types) created for this EventProcessor. + + */ + int n_thread_groups; + +private: + // prevent unauthorized copies (Not implemented) + EventProcessor(const EventProcessor &); + EventProcessor & operator =(const EventProcessor &); + +public: + + /*------------------------------------------------------*\ + | Unix & non NT Interface | + \*------------------------------------------------------*/ + + Event * schedule(Event * e, EventType etype, bool fast_signal = false); + EThread *assign_thread(EventType etype); + + EThread *dthreads[MAX_EVENT_THREADS]; + int n_dthreads; // No. of dedicated threads + volatile int thread_data_used; +}; + +extern inkcoreapi class EventProcessor eventProcessor; + +#endif /*_EventProcessor_h_*/ diff --git a/iocore/eventsystem/I_EventSystem.h b/iocore/eventsystem/I_EventSystem.h new file mode 100644 index 00000000..4cec28bd --- /dev/null +++ b/iocore/eventsystem/I_EventSystem.h @@ -0,0 +1,61 @@ +/** @file + + Event subsystem + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef _I_EventSystem_h +#define _I_EventSystem_h + +#ifndef TS_INLINE +#define TS_INLINE +#endif + +#include "libts.h" + +#include "I_IOBuffer.h" +#include "I_Action.h" +#include "I_Continuation.h" +#include "I_EThread.h" +#include "I_Event.h" +#include "I_EventProcessor.h" + +#include "I_Lock.h" +#include "I_PriorityEventQueue.h" +#include "I_Processor.h" +#include "I_ProtectedQueue.h" +#include "I_ProxyAllocator.h" +#include "I_Thread.h" +#include "I_VIO.h" +#include "I_VConnection.h" +#include "I_RecProcess.h" +#include "I_SocketManager.h" + +#define EVENT_SYSTEM_MODULE_MAJOR_VERSION 1 +#define EVENT_SYSTEM_MODULE_MINOR_VERSION 0 +#define EVENT_SYSTEM_MODULE_VERSION makeModuleVersion( \ + EVENT_SYSTEM_MODULE_MAJOR_VERSION, \ + EVENT_SYSTEM_MODULE_MINOR_VERSION, \ + PUBLIC_MODULE_HEADER) + +void ink_event_system_init(ModuleVersion version); + +#endif diff --git a/iocore/eventsystem/I_IOBuffer.h b/iocore/eventsystem/I_IOBuffer.h new file mode 100644 index 00000000..dc74ffd7 --- /dev/null +++ b/iocore/eventsystem/I_IOBuffer.h @@ -0,0 +1,1370 @@ +/** @file + + I/O classes + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section watermark Watermark + + Watermarks can be used as an interface between the data transferring + layer (VConnection) and the user layer (a state machine). Watermarks + should be used when you need to have at least a certain amount of data + to make some determination. For example, when parsing a string, one + might wish to ensure that an entire line will come in before consuming + the data. In such a case, the water_mark should be set to the largest + possible size of the string. (appropriate error handling should take + care of exessively long strings). + + In all other cases, especially when all data will be consumed, the + water_mark should be set to 0 (the default). + + */ + +#if !defined (I_IOBuffer_h) +#define I_IOBuffer_h + +#include "libts.h" + +struct MIOBufferAccessor; + +class MIOBuffer; +class IOBufferReader; +class VIO; + +// Removing this optimization since this is breaking WMT over HTTP +//#define WRITE_AND_TRANSFER + +inkcoreapi extern int64_t max_iobuffer_size; +extern int64_t default_small_iobuffer_size; +extern int64_t default_large_iobuffer_size; // matched to size of OS buffers + +#if !defined(PURIFY) +// Define this macro to enable buffer usage tracking. +#define TRACK_BUFFER_USER +#endif + +enum AllocType +{ NO_ALLOC, FAST_ALLOCATED, XMALLOCED, MEMALIGNED, + DEFAULT_ALLOC, CONSTANT +}; +#ifndef TS_MICRO +#define DEFAULT_BUFFER_NUMBER 128 +#define DEFAULT_HUGE_BUFFER_NUMBER 32 +#define MAX_MIOBUFFER_READERS 5 +#define DEFAULT_BUFFER_ALIGNMENT 8192 // should be disk/page size +#define DEFAULT_BUFFER_BASE_SIZE 128 +#else +#define DEFAULT_BUFFER_NUMBER 4 +#define DEFAULT_HUGE_BUFFER_NUMBER 32 +#define MAX_MIOBUFFER_READERS 3 +#define DEFAULT_BUFFER_BASE_SIZE 128 +#define DEFAULT_BUFFER_ALIGNMENT 8 // should be disk/page size +#endif + +//////////////////////////////////////////////// +// These are defines so that code that used 2 // +// for buffer size index when 2 was 2K will // +// still work if it uses BUFFER_SIZE_INDEX_2K // +// instead. // +//////////////////////////////////////////////// +#define BUFFER_SIZE_INDEX_128 0 +#define BUFFER_SIZE_INDEX_256 1 +#define BUFFER_SIZE_INDEX_512 2 +#define BUFFER_SIZE_INDEX_1K 3 +#define BUFFER_SIZE_INDEX_2K 4 +#define BUFFER_SIZE_INDEX_4K 5 +#define BUFFER_SIZE_INDEX_8K 6 +#define BUFFER_SIZE_INDEX_16K 7 +#define BUFFER_SIZE_INDEX_32K 8 +#define BUFFER_SIZE_INDEX_64K 9 +#define BUFFER_SIZE_INDEX_128K 10 +#define BUFFER_SIZE_INDEX_256K 11 +#define BUFFER_SIZE_INDEX_512K 12 +#define BUFFER_SIZE_INDEX_1M 13 +#define BUFFER_SIZE_INDEX_2M 14 +#define MAX_BUFFER_SIZE_INDEX 14 +#define DEFAULT_BUFFER_SIZES (MAX_BUFFER_SIZE_INDEX+1) + +#define BUFFER_SIZE_FOR_INDEX(_i) (DEFAULT_BUFFER_BASE_SIZE * (1 << (_i))) +#define DEFAULT_SMALL_BUFFER_SIZE BUFFER_SIZE_INDEX_512 +#define DEFAULT_LARGE_BUFFER_SIZE BUFFER_SIZE_INDEX_4K +#define DEFAULT_TS_BUFFER_SIZE BUFFER_SIZE_INDEX_8K +#define DEFAULT_MAX_BUFFER_SIZE BUFFER_SIZE_FOR_INDEX(MAX_BUFFER_SIZE_INDEX) +#define MIN_IOBUFFER_SIZE BUFFER_SIZE_INDEX_128 +#define MAX_IOBUFFER_SIZE (DEFAULT_BUFFER_SIZES-1) + + +#define BUFFER_SIZE_ALLOCATED(_i) \ + (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_i) || \ + BUFFER_SIZE_INDEX_IS_XMALLOCED(_i) ) + +#define BUFFER_SIZE_NOT_ALLOCATED DEFAULT_BUFFER_SIZES +#define BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index) (_size_index < 0) +#define BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index) \ + (((uint64_t)_size_index) < DEFAULT_BUFFER_SIZES) +#define BUFFER_SIZE_INDEX_IS_CONSTANT(_size_index) \ + (_size_index >= DEFAULT_BUFFER_SIZES) + +#define BUFFER_SIZE_FOR_XMALLOC(_size) (-(_size)) +#define BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(_size) (-(_size)) + +#define BUFFER_SIZE_FOR_CONSTANT(_size) (_size - DEFAULT_BUFFER_SIZES) +#define BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(_size) (_size+DEFAULT_BUFFER_SIZES) + +inkcoreapi extern Allocator ioBufAllocator[DEFAULT_BUFFER_SIZES]; + +void init_buffer_allocators(); + +/** + A reference counted wrapper around fast allocated or malloced memory. + The IOBufferData class provides two basic services around a portion + of allocated memory. + + First, it is a reference counted object and ... + + @remarks The AllocType enum, is used to define the type of allocation + for the memory this IOBufferData object manages. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AllocTypeMeaning
NO_ALLOC
FAST_ALLOCATED
XMALLOCED
MEMALIGNED
DEFAULT_ALLOC
CONSTANT
+ + */ +class IOBufferData:public RefCountObj +{ +public: + + /** + The size of the memory allocated by this IOBufferData. Calculates + the amount of memory allocated by this IOBufferData. + + @return number of bytes allocated for the '_data' member. + + */ + int64_t block_size(); + + /** + Frees the memory managed by this IOBufferData. Deallocates the + memory previously allocated by this IOBufferData object. It frees + the memory pointed to by '_data' according to the '_mem_type' and + '_size_index' members. + + */ + void dealloc(); + + /** + Allocates memory and sets this IOBufferData to point to it. + Allocates memory according to the size_index and type + parameters. Any previously allocated memory pointed to by + this IOBufferData is deallocated. + + @param size_index + @param type of allocation to use; see remarks section. + */ + void alloc(int64_t size_index, AllocType type = DEFAULT_ALLOC); + + /** + Provides access to the allocated memory. Returns the address of the + allocated memory handled by this IOBufferData. + + @return address of the memory handled by this IOBufferData. + + */ + char *data() + { + return _data; + } + + /** + Cast operator. Provided as a convenience, the cast to a char* applied + to the IOBufferData returns the address of the memory handled by the + IOBuffer data. In this manner, objects of this class can be used as + parameter to functions requiring a char*. + + */ + operator char *() + { + return _data; + } + + /** + Frees the IOBufferData object and its underlying memory. Deallocates + the memory managed by this IOBufferData and then frees itself. You + should not use this object or reference after this call. + + */ + virtual void free(); + + int64_t _size_index; + + /** + Type of allocation used for the managed memory. Stores the type of + allocation used for the memory currently managed by the IOBufferData + object. Do not set or modify this value directly. Instead use the + alloc or dealloc methods. + + */ + AllocType _mem_type; + + /** + Points to the allocated memory. This member stores the address of + the allocated memory. You should not modify its value directly, + instead use the alloc or dealloc methods. + + */ + char *_data; + +#ifdef TRACK_BUFFER_USER + const char *_location; +#endif + + /** + Constructor. Initializes state for a IOBufferData object. Do not use + this method. Use one of the functions with the 'new_' prefix instead. + + */ + IOBufferData() +: _size_index(BUFFER_SIZE_NOT_ALLOCATED), _mem_type(NO_ALLOC), _data(NULL) +#ifdef TRACK_BUFFER_USER + , _location(NULL) +#endif + { + } + +private: + // declaration only + IOBufferData(const IOBufferData &); + IOBufferData & operator =(const IOBufferData &); +}; + +inkcoreapi extern ClassAllocator ioDataAllocator; + +/** + A linkable portion of IOBufferData. IOBufferBlock is a chainable + buffer block descriptor. The IOBufferBlock represents both the used + and available space in the underlying block. The IOBufferBlock is not + sharable between buffers but rather represents what part of the data + block is both in use and usable by the MIOBuffer it is attached to. + +*/ +class IOBufferBlock:public RefCountObj +{ +public: + /** + Access the actual data. Provides access to rhe underlying data + managed by the IOBufferData. + + @return pointer to the underlying data. + + */ + char *buf() + { + return data->_data; + } + + /** + Beginning of the inuse section. Returns the position in the buffer + where the inuse area begins. + + @return pointer to the start of the inuse section. + + */ + char *start() + { + return _start; + } + + /** + End of the used space. Returns a pointer to end of the used space + in the data buffer represented by this block. + + @return pointer to the end of the inuse portion of the block. + + */ + char *end() + { + return _end; + } + + /** + End of the data buffer. Returns a pointer to end of the data buffer + represented by this block. + + */ + char *buf_end() + { + return _buf_end; + } + + /** + Size of the inuse area. Returns the size of the current inuse area. + + @return bytes occupied by the inuse area. + + */ + int64_t size() + { + return (int64_t) (_end - _start); + } + + /** + Size of the data available for reading. Returns the size of the data + available for reading in the inuse area. + + @return bytes available for reading from the inuse area. + + */ + int64_t read_avail() + { + return (int64_t) (_end - _start); + } + + /** + Space available in the buffer. Returns the number of bytes that can + be written to the data buffer. + + @return space available for writing in this IOBufferBlock. + */ + int64_t write_avail() + { + return (int64_t) (_buf_end - _end); + } + + /** + Size of the memory allocated by the underlying IOBufferData. + Computes the size of the entire block, which includes the used and + available areas. It is the memory allocated by the IOBufferData + referenced by this IOBufferBlock. + + @return bytes allocated to the IOBufferData referenced by this + IOBufferBlock. + + */ + int64_t block_size() + { + return data->block_size(); + } + + /** + Decrease the size of the inuse area. Moves forward the start of + the inuse area. This also decreases the number of available bytes + for reading. + + @param len bytes to consume or positions to skip for the start of + the inuse area. + + */ + void consume(int64_t len); + + /** + Increase the inuse area of the block. Adds 'len' bytes to the inuse + area of the block. Data should be copied into the data buffer by + using end() to find the start of the free space in the data buffer + before calling fill() + + @param len bytes to increase the inuse area. It must be less than + or equal to the value of write_avail(). + + */ + void fill(int64_t len); + + /** + Reset the inuse area. The start and end of the inuse area are reset + but the actual IOBufferData referenced by this IOBufferBlock is not + modified. This effectively reduces the number of bytes available + for reading to zero, and the number of bytes available for writing + to the size of the entire buffer. + + */ + void reset(); + + /** + Create a copy of the IOBufferBlock. Creates and returns a copy of this + IOBufferBlock that references the same data that this IOBufferBlock + (it does not allocate an another buffer). The cloned block will not + have a writable space since the original IOBufferBlock mantains the + ownership for writing data to the block. + + @return copy of this IOBufferBlock. + + */ + IOBufferBlock *clone(); + + /** + Clear the IOBufferData this IOBufferBlock handles. Clears this + IOBufferBlock's reference to the data buffer (IOBufferData). You can + use alloc after this call to allocate an IOBufferData associated to + this IOBufferBlock. + + */ + void clear(); + + /** + Allocate a data buffer. Allocates a data buffer for this IOBufferBlock + based on index 'i'. Index values are described in the remarks + section in MIOBuffer. + + */ + void alloc(int64_t i = default_large_iobuffer_size); + + /** + Clear the IOBufferData this IOBufferBlock handles. Clears this + IOBufferBlock's reference to the data buffer (IOBufferData). + + */ + void dealloc(); + + /** + Set or replace this IOBufferBlock's IOBufferData member. Sets this + IOBufferBlock's IOBufferData member to point to the IOBufferData + passed in. You can optionally specify the inuse area with the 'len' + argument and an offset for the start. + + @param d new IOBufferData this IOBufferBlock references. + @param len in use area to set. It must be less than or equal to the + length of the block size *IOBufferData). + @param offset bytes to skip from the beginning of the IOBufferData + and to mark its start. + + */ + void set(IOBufferData * d, int64_t len = 0, int64_t offset = 0); + void set_internal(void *b, int64_t len, int64_t asize_index); + void realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index); + void realloc(void *b, int64_t buf_size); + void realloc(int64_t i); + void realloc_xmalloc(void *b, int64_t buf_size); + void realloc_xmalloc(int64_t buf_size); + + /** + Frees the IOBufferBlock object and its underlying memory. + Removes the reference to the IOBufferData object and then frees + itself. You should not use this object or reference after this + call. + + */ + virtual void free(); + + char *_start; + char *_end; + char *_buf_end; + +#ifdef TRACK_BUFFER_USER + const char *_location; +#endif + + /** + The underlying reference to the allocated memory. A reference to a + IOBufferData representing the memory allocated to this buffer. Do + not set or modify its value directly. + + */ + Ptr data; + + /** + Reference to another IOBufferBlock. A reference to another + IOBufferBlock that allows this object to link to other. + + */ + Ptr next; + + /** + Constructor of a IOBufferBlock. Do not use it to create a new object, + instead call new_IOBufferBlock + + */ + IOBufferBlock(); + +private: + IOBufferBlock(const IOBufferBlock &); + IOBufferBlock & operator =(const IOBufferBlock &); +}; + +extern inkcoreapi ClassAllocator ioBlockAllocator; + +/** + An independent reader from an MIOBuffer. A reader for a set of + IOBufferBlocks. The IOBufferReader represents the place where a given + consumer of buffer data is reading from. It provides a uniform interface + for easily accessing the data contained in a list of IOBufferBlocks + associated with the IOBufferReader. + + IOBufferReaders are the abstraction that determine when data blocks + can be removed from the buffer. + +*/ +class IOBufferReader +{ +public: + + /** + Start of unconsumed data. Returns a pointer to first unconsumed data + on the buffer for this reader. A null pointer indicates no data is + available. It uses the current start_offset value. + + @return pointer to the start of the unconsumed data. + + */ + char *start(); + + /** + End of inuse area of the first block with unconsumed data. Returns a + pointer to the end of the first block with unconsumed data for this + reader. A NULL pointer indicates there are no blocks with unconsumed + data for this reader. + + @return pointer to the end of the first block with unconsumed data. + + */ + char *end(); + + /** + Amount of data available across all of the IOBufferBlocks. Returns the + number of unconsumed bytes of data available to this reader across + all remaining IOBufferBlocks. It subtracts the current start_offset + value from the total. + + @return bytes of data available across all the buffers. + + */ + int64_t read_avail(); + + /** + Number of IOBufferBlocks with data in the block list. Returns the + number of IOBufferBlocks on the block list with data remaining for + this reader. + + @return number of blocks with data for this reader. + + */ + int block_count(); + + /** + Amount of data available in the first buffer with data for this + reader. Returns the number of unconsumed bytes of data available + on the first IOBufferBlock with data for this reader. + + @return number of unconsumed bytes of data available in the first + buffer. + + */ + int64_t block_read_avail(); + + void skip_empty_blocks(); + + /** + Clears all fields in this IOBuffeReader, rendering it unusable. Drops + the reference to the IOBufferBlock list, the accesor, MIOBuffer and + resets this reader's state. You have to set those fields in order + to use this object again. + + */ + void clear(); + + /** + Instruct the reader to reset the IOBufferBlock list. Resets the + reader to the point to the start of the block where new data will + be written. After this call, the start_offset field is set to zero + and the list of IOBufferBlocks is set using the associated MIOBuffer. + + */ + void reset(); + + /** + Consume a number of bytes from this reader's IOBufferBlock + list. Advances the current position in the IOBufferBlock list of + this reader by n bytes. + + @param n number of bytes to consume. It must be less than or equal + to read_avail(). + + */ + void consume(int64_t n); + + /** + Create another reader with access to the same data as this + IOBufferReader. Allocates a new reader with the same state as this + IOBufferReader. This means that the new reader will point to the same + list of IOBufferBlocks and to the same buffer position as this reader. + + @return new reader with the same state as this. + + */ + IOBufferReader *clone(); + + /** + Deallocate this reader. Removes and deallocates this reader from + the underlying MIOBuffer. This IOBufferReader object must not be + used after this call. + + */ + void dealloc(); + + /** + Get a pointer to the first block with data. Returns a pointer to + the first IOBufferBlock in the block chain with data available for + this reader + + @return pointer to the first IOBufferBlock in the list with data + available for this reader. + + */ + IOBufferBlock *get_current_block(); + + /** + Consult this reader's MIOBuffer writable space. Queries the MIOBuffer + associated with this reader about the amount of writable space + available without adding any blocks on the buffer and returns true + if it is less than the water mark. + + @return true if the MIOBuffer associated with this IOBufferReader + returns true in MIOBuffer::current_low_water(). + + */ + bool current_low_water(); + + /** + Queries the underlying MIOBuffer about. Returns true if the amount + of writable space after adding a block on the underlying MIOBuffer + is less than its water mark. This function call may add blocks to + the MIOBuffer (see MIOBuffer::low_water()). + + @return result of MIOBuffer::low_water() on the MIOBuffer for + this reader. + + */ + bool low_water(); + + /** + To see if the amount of data available to the reader is greater than + the MIOBuffer's water mark. Indicates whether the amount of data + available to this reader exceeds the water mark for this reader's + MIOBuffer. + + @return true if the amount of data exceeds the MIOBuffer's water mark. + + */ + bool high_water(); + + /** + Perform a memchr() across the list of IOBufferBlocks. Returns the + offset from the current start point of the reader to the first + occurence of character 'c' in the buffer. + + @param c character to look for. + @param len number of characters to check. If len exceeds the number + of bytes available on the buffer or INT64_MAX is passed in, the + number of bytes available to the reader is used. It is independent + of the offset value. + @param offset number of the bytes to skip over before beginning + the operation. + @return -1 if c is not found, otherwise position of the first + ocurrence. + + */ + inkcoreapi int64_t memchr(char c, int64_t len = INT64_MAX, int64_t offset = 0); + + /** + Copies and consumes data. Copies len bytes of data from the buffer + into the supplied buffer, which must be allocated prior to the call + and it must be at large enough for the requested bytes. Once the + data is copied, it consumed from the reader. + + @param buf in which to place the data. + @param len bytes to copy and consume. If 'len' exceeds the bytes + available to the reader, the number of bytes available is used + instead. + + @return number of bytes copied and consumed. + + */ + inkcoreapi int64_t read(void *buf, int64_t len); + + /** + Copy data but do not consume it. Copies 'len' bytes of data from + the current buffer into the supplied buffer. The copy skips the + number of bytes specified by 'offset' beyond the current point of + the reader. It also takes into account the current start_offset value. + + @param buf in which to place the data. The pointer is modified after + the call and points one position after the end of the data copied. + @param len bytes to copy. If len exceeds the bytes available to the + reader or INT64_MAX is passed in, the number of bytes available is + used instead. No data is consumed from the reader in this operation. + @param offset bytes to skip from the current position. The parameter + is modified after the call. + @return pointer to one position after the end of the data copied. The + parameter buf is set to this value also. + + */ + inkcoreapi char *memcpy(const void *buf, int64_t len = INT64_MAX, int64_t offset = 0); + + /** + Subscript operator. Returns a reference to the character at the + specified position. You must ensure that it is within an appropriate + range. + + @param i positions beyond the current point of the reader. It must + be less than the number of the bytes available to the reader. + + @return reference to the character in that position. + + */ + char &operator[] (int64_t i); + + MIOBuffer *writer() const { return mbuf; } + MIOBuffer *allocated() const { return mbuf; } + + MIOBufferAccessor *accessor; // pointer back to the accessor + + /** + Back pointer to this object's MIOBuffer. A pointer back to the + MIOBuffer this reader is allocated from. + + */ + MIOBuffer *mbuf; + Ptr block; + + /** + Offset beyond the shared start(). The start_offset is used in the + calls that copy or consume data and is an offset at the beginning + of the available data. + + */ + int64_t start_offset; + int64_t size_limit; + + IOBufferReader() + : accessor(NULL), mbuf(NULL), start_offset(0), size_limit(INT64_MAX) + { } +}; + +/** + A multiple reader, single writer memory buffer. MIOBuffers are at + the center of all IOCore data transfer. MIOBuffers are the data + buffers used to transfer data to and from VConnections. A MIOBuffer + points to a list of IOBufferBlocks which in turn point to IOBufferData + stucutres that in turn point to the actual data. MIOBuffer allows one + producer and multiple consumers. The buffer fills up according the + amount of data outstanding for the slowest consumer. Thus, MIOBuffer + implements automatic flow control between readers of different speeds. + Data on IOBuffer is immutable. Once written it cannot be modified, only + deallocated once all consumers have finished with it. Immutability is + necessary since data can be shared between buffers, which means that + multiple IOBufferBlock objects may reference the same data but only + one will have ownership for writing. + +*/ +class MIOBuffer +{ +public: + + /** + Increase writer's inuse area. Instructs the writer associated with + this MIOBuffer to increase the inuse area of the block by as much as + 'len' bytes. + + @param len number of bytes to add to the inuse area of the block. + + */ + void fill(int64_t len); + + /** + Adds a block to the end of the block list. The block added to list + must be writable by this buffer and must not be writable by any + other buffer. + + */ + void append_block(IOBufferBlock * b); + + /** + Adds a new block to the end of the block list. The size is determined + by asize_index. See the remarks section for a mapping of indexes to + buffer block sizes. + + */ + void append_block(int64_t asize_index); + + /** + Adds new block to the end of block list using the block size for + the buffer specified when the buffer was allocated. + + */ + void add_block(); + + /** + Adds by reference len bytes of data pointed to by b to the end + of the buffer. b MUST be a pointer to the beginning of block + allocated from the xmalloc() routine. The data will be deallocated + by the buffer once all readers on the buffer have consumed it. + + */ + void append_xmalloced(void *b, int64_t len); + + /** + Adds by reference len bytes of data pointed to by b to the end of the + buffer. b MUST be a pointer to the beginning of block allocated from + ioBufAllocator of the corresponding index for fast_size_index. The + data will be deallocated by the buffer once all readers on the buffer + have consumed it. + + */ + void append_fast_allocated(void *b, int64_t len, int64_t fast_size_index); + + /** + Adds the nbytes worth of data pointed by rbuf to the buffer. The + data is copied into the buffer. write() does not respect watermarks + or buffer size limits. Users of write must implement their own flow + control. Returns the number of bytes added. + + */ + inkcoreapi int64_t write(const void *rbuf, int64_t nbytes); + +#ifdef WRITE_AND_TRANSFER + /** + Same functionality as write but for the one small difference. The + space available in the last block is taken from the original and + this space becomes available to the copy. + + */ + inkcoreapi int64_t write_and_transfer_left_over_space(IOBufferReader * r, int64_t len = INT64_MAX, int64_t offset = 0); +#endif + + /** + Add by data from IOBufferReader r to the this buffer by reference. If + len is INT64_MAX, all available data on the reader is added. If len is + less than INT64_MAX, the smaller of len or the amount of data on the + buffer is added. If offset is greater than zero, than the offset + bytes of data at the front of the reader are skipped. Bytes skipped + by offset reduce the number of bytes available on the reader used + in the amount of data to add computation. write() does not respect + watermarks or buffer size limits. Users of write must implement + their own flow control. Returns the number of bytes added. Each + write() call creates a new IOBufferBlock, even if it is for one + byte. As such, it's necessary to exercise caution in any code that + repeatedly transfers data from one buffer to another, especially if + the data is being read over the network as it may be coming in very + small chunks. Because deallocation of outstanding buffer blocks is + recursive, it's possible to overrun the stack if too many blocks + have been added to the buffer chain. It's imperative that users + both implement their own flow control to prevent too many bytes + from becoming outstanding on a buffer that the write() call is + being used and that care be taken to ensure the transfers are of a + minimum size. Should it be necessary to make a large number of small + transfers, it's preferable to use a interface that copies the data + rather than sharing blocks to prevent a build of blocks on the buffer. + + */ + inkcoreapi int64_t write(IOBufferReader * r, int64_t len = INT64_MAX, int64_t offset = 0); + + int64_t remove_append(IOBufferReader *); + + /** + Returns a pointer to the first writable block on the block chain. + Returns NULL if there are not currently any writable blocks on the + block list. + + */ + IOBufferBlock *first_write_block() + { + if (_writer) { + if (_writer->next && !_writer->write_avail()) + return _writer->next; + ink_assert(!_writer->next || !_writer->next->read_avail()); + return _writer; + } else + return NULL; + } + + + char *buf() + { + IOBufferBlock *b = first_write_block(); + return b ? b->buf() : 0; + } + char *buf_end() + { + return first_write_block()->buf_end(); + } + char *start() + { + return first_write_block()->start(); + } + char *end() + { + return first_write_block()->end(); + } + + /** + Returns the amount of space of available for writing on the first + writable block on the block chain (the one that would be reutrned + by first_write_block()). + + */ + int64_t block_write_avail(); + + /** + Returns the amount of space of available for writing on all writable + blocks currently on the block chain. Will NOT add blocks to the + block chain. + + */ + int64_t current_write_avail(); + + /** + Adds blocks for writing if the watermark criteria are met. Returns + the amount of space of available for writing on all writable blocks + on the block chain after a block due to the watermark criteria. + + */ + int64_t write_avail(); + + /** + Returns the default data block size for this buffer. + + */ + int64_t block_size(); + + /** + Returns the default data block size for this buffer. + + */ + int64_t total_size() + { + return block_size(); + } + + /** + Returns true if amount of the data outstanding on the buffer exceeds + the watermark. + + */ + bool high_water() + { + return max_read_avail() > water_mark; + } + + /** + Returns true if the amount of writable space after adding a block on + the buffer is less than the water mark. Since this function relies + on write_avail() it may add blocks. + + */ + bool low_water() + { + return write_avail() <= water_mark; + } + + /** + Returns true if amount the amount writable space without adding and + blocks on the buffer is less than the water mark. + + */ + bool current_low_water() + { + return current_write_avail() <= water_mark; + } + void set_size_index(int64_t size); + + /** + Allocates a new IOBuffer reader and sets it's its 'accessor' field + to point to 'anAccessor'. + + */ + IOBufferReader *alloc_accessor(MIOBufferAccessor * anAccessor); + + /** + Allocates an IOBufferReader for this buffer. IOBufferReaders hold + data on the buffer for different consumers. IOBufferReaders are + REQUIRED when using buffer. alloc_reader() MUST ONLY be a called + on newly allocated buffers. Calling on a buffer with data already + placed on it will result in the reader starting at an indeterminate + place on the buffer. + + */ + IOBufferReader *alloc_reader(); + + /** + Allocates a new reader on this buffer and places it's starting + point at the same place as reader r. r MUST be a pointer to a reader + previous allocated from this buffer. + + */ + IOBufferReader *clone_reader(IOBufferReader * r); + + /** + Deallocates reader e from this buffer. e MUST be a pointer to a reader + previous allocated from this buffer. Reader need to allocated when a + particularly consumer is being removed from the buffer but the buffer + is still in use. Deallocation is not necessary when the buffer is + being freed as all outstanding readers are automatically deallocated. + + */ + void dealloc_reader(IOBufferReader * e); + + /** + Deallocates all outstanding readers on the buffer. + + */ + void dealloc_all_readers(); + + void set(void *b, int64_t len); + void set_xmalloced(void *b, int64_t len); + void alloc(int64_t i = default_large_iobuffer_size); + void alloc_xmalloc(int64_t buf_size); + void append_block_internal(IOBufferBlock * b); + int64_t puts(char *buf, int64_t len); + + // internal interface + + bool empty() + { + return !_writer; + } + int64_t max_read_avail(); + int max_block_count(); + void check_add_block(); + + IOBufferBlock *get_current_block(); + + void reset() + { + if (_writer) { + _writer->reset(); + } + for (int j = 0; j < MAX_MIOBUFFER_READERS; j++) + if (readers[j].allocated()) { + readers[j].reset(); + } + } + + void init_readers() + { + for (int j = 0; j < MAX_MIOBUFFER_READERS; j++) + if (readers[j].allocated() && !readers[j].block) + readers[j].block = _writer; + } + + void dealloc() + { + _writer = NULL; + dealloc_all_readers(); + } + + void clear() + { + dealloc(); + size_index = BUFFER_SIZE_NOT_ALLOCATED; + water_mark = 0; + } + + void realloc(int64_t i) + { + _writer->realloc(i); + } + void realloc(void *b, int64_t buf_size) + { + _writer->realloc(b, buf_size); + } + void realloc_xmalloc(void *b, int64_t buf_size) + { + _writer->realloc_xmalloc(b, buf_size); + } + void realloc_xmalloc(int64_t buf_size) + { + _writer->realloc_xmalloc(buf_size); + } + + int64_t size_index; + + /** + Determines when to stop writing or reading. The watermark is the + level to which the producer (filler) is required to fill the buffer + before it can expect the reader to consume any data. A watermark + of zero means that the reader will consume any amount of data, + no matter how small. + + */ + int64_t water_mark; + + Ptr _writer; + IOBufferReader readers[MAX_MIOBUFFER_READERS]; + +#ifdef TRACK_BUFFER_USER + const char *_location; +#endif + + MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark); + MIOBuffer(int64_t default_size_index); + MIOBuffer(); + ~MIOBuffer(); +}; + +/** + A wrapper for either a reader or a writer of an MIOBuffer. + +*/ +struct MIOBufferAccessor +{ + IOBufferReader *reader() + { + return entry; + } + MIOBuffer *writer() + { + return mbuf; + } + + int64_t block_size() + { + return mbuf->block_size(); + } + int64_t total_size() + { + return block_size(); + } + + void reader_for(IOBufferReader * abuf); + void reader_for(MIOBuffer * abuf); + void writer_for(MIOBuffer * abuf); + + void clear(); + void reset() + { + mbuf = NULL; + entry = NULL; + } + +// private: + + MIOBuffer *mbuf; + IOBufferReader *entry; + +MIOBufferAccessor():mbuf(NULL), entry(NULL) +#ifdef DEBUG + , name(NULL) +#endif + { + } + ~MIOBufferAccessor(); + +#ifdef DEBUG + const char *name; +#endif + +private: + MIOBufferAccessor(const MIOBufferAccessor &); + MIOBufferAccessor & operator =(const MIOBufferAccessor &); +}; + +TS_INLINE MIOBuffer * new_MIOBuffer_internal( +#ifdef TRACK_BUFFER_USER + const char *loc, +#endif + int64_t size_index = default_large_iobuffer_size); + +#ifdef TRACK_BUFFER_USER +class MIOBuffer_tracker +{ + const char *loc; + +public: + MIOBuffer_tracker(const char *_loc):loc(_loc) + { + } + MIOBuffer *operator() (int64_t size_index = default_large_iobuffer_size) { + return new_MIOBuffer_internal(loc, size_index); + } + +}; +#endif + +TS_INLINE MIOBuffer * new_empty_MIOBuffer_internal( +#ifdef TRACK_BUFFER_USER + const char *loc, +#endif + int64_t size_index = default_large_iobuffer_size); + +#ifdef TRACK_BUFFER_USER +class Empty_MIOBuffer_tracker +{ + const char *loc; + +public: + Empty_MIOBuffer_tracker(const char *_loc):loc(_loc) + { + } + MIOBuffer *operator() (int64_t size_index = default_large_iobuffer_size) { + return new_empty_MIOBuffer_internal(loc, size_index); + } +}; +#endif + +/// MIOBuffer allocator/deallocator +#ifdef TRACK_BUFFER_USER +#define new_MIOBuffer MIOBuffer_tracker(RES_PATH("memory/IOBuffer/")) +#define new_empty_MIOBuffer Empty_MIOBuffer_tracker(RES_PATH("memory/IOBuffer/")) +#else +#define new_MIOBuffer new_MIOBuffer_internal +#define new_empty_MIOBuffer new_empty_MIOBuffer_internal +#endif +TS_INLINE void free_MIOBuffer(MIOBuffer * mio); +////////////////////////////////////////////////////////////////////// + +TS_INLINE IOBufferBlock * new_IOBufferBlock_internal( +#ifdef TRACK_BUFFER_USER + const char *loc +#endif + ); +TS_INLINE IOBufferBlock * new_IOBufferBlock_internal( +#ifdef TRACK_BUFFER_USER + const char *loc, +#endif + IOBufferData * d, int64_t len = 0, int64_t offset = 0); + +#ifdef TRACK_BUFFER_USER +class IOBufferBlock_tracker +{ + const char *loc; + +public: + IOBufferBlock_tracker(const char *_loc):loc(_loc) + { + } + IOBufferBlock *operator() () + { + return new_IOBufferBlock_internal(loc); + } + IOBufferBlock *operator() (IOBufferData * d, int64_t len = 0, int64_t offset = 0) { + return new_IOBufferBlock_internal(loc, d, len, offset); + } + +}; +#endif + +/// IOBufferBlock allocator +#ifdef TRACK_BUFFER_USER +#define new_IOBufferBlock IOBufferBlock_tracker(RES_PATH("memory/IOBuffer/")) +#else +#define new_IOBufferBlock new_IOBufferBlock_internal +#endif +//////////////////////////////////////////////////////////// + +TS_INLINE IOBufferData *new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + int64_t size_index = default_large_iobuffer_size, + AllocType type = DEFAULT_ALLOC); + +TS_INLINE IOBufferData *new_xmalloc_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + void *b, int64_t size); + +TS_INLINE IOBufferData *new_constant_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *loc, +#endif + void *b, int64_t size); + + +#ifdef TRACK_BUFFER_USER +class IOBufferData_tracker +{ + const char *loc; + +public: + IOBufferData_tracker(const char *_loc):loc(_loc) + { + } + IOBufferData *operator() (int64_t size_index = default_large_iobuffer_size, AllocType type = DEFAULT_ALLOC) { + return new_IOBufferData_internal(loc, size_index, type); + } + +}; +#endif + +#ifdef TRACK_BUFFER_USER +#define new_IOBufferData IOBufferData_tracker(RES_PATH("memory/IOBuffer/")) +#define new_xmalloc_IOBufferData(b, size) \ +new_xmalloc_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), \ + (b), (size)) +#define new_constant_IOBufferData(b, size) \ +new_constant_IOBufferData_internal(RES_PATH("memory/IOBuffer/"), \ + (b), (size)) +#else +#define new_IOBufferData new_IOBufferData_internal +#define new_xmalloc_IOBufferData new_xmalloc_IOBufferData_internal +#define new_constant_IOBufferData new_constant_IOBufferData_internal +#endif + +TS_INLINE int64_t iobuffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size); +TS_INLINE int64_t index_to_buffer_size(int64_t idx); +/** + Clone a IOBufferBlock chain. Used to snarf a IOBufferBlock chain + w/o copy. + + @param b head of source IOBufferBlock chain. + @param offset # bytes in the beginning to skip. + @param len bytes to copy from source. + @return ptr to head of new IOBufferBlock chain. + +*/ +TS_INLINE IOBufferBlock *iobufferblock_clone(IOBufferBlock * b, int64_t offset, int64_t len); +/** + Skip over specified bytes in chain. Used for dropping references. + + @param b head of source IOBufferBlock chain. + @param poffset originally offset in b, finally offset in returned + IOBufferBlock. + @param plen value of write is subtracted from plen in the function. + @param write bytes to skip. + @return ptr to head of new IOBufferBlock chain. + +*/ +TS_INLINE IOBufferBlock *iobufferblock_skip(IOBufferBlock * b, int64_t *poffset, int64_t *plen, int64_t write); +#endif diff --git a/iocore/eventsystem/I_Lock.h b/iocore/eventsystem/I_Lock.h new file mode 100644 index 00000000..17645dc4 --- /dev/null +++ b/iocore/eventsystem/I_Lock.h @@ -0,0 +1,828 @@ +/** @file + + Basic locks for threads + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_Lock_h_ +#define _I_Lock_h_ + +#include "libts.h" +#include "I_Thread.h" + +#define MAX_LOCK_TIME HRTIME_MSECONDS(200) +#define THREAD_MUTEX_THREAD_HOLDING (-1024*1024) +#define HANDLER_NAME(_c) _c?_c->handler_name:(char*)NULL + +class EThread; +typedef EThread *EThreadPtr; +typedef volatile EThreadPtr VolatileEThreadPtr; + +inkcoreapi extern void lock_waiting(const char *file, int line, const char *handler); +inkcoreapi extern void lock_holding(const char *file, int line, const char *handler); +extern void lock_taken(const char *file, int line, const char *handler); + +/** + Lock object used in continuations and threads. + + The ProxyMutex class is the main synchronization object used + throughout the Event System. It is a reference counted object + that provides mutually exclusive access to a resource. Since the + Event System is multithreaded by design, the ProxyMutex is required + to protect data structures and state information that could + otherwise be affected by the action of concurrent threads. + + A ProxyMutex object has an ink_mutex member (defined in ink_mutex.h) + which is a wrapper around the platform dependent mutex type. This + member allows the ProxyMutex to provide the functionallity required + by the users of the class without the burden of platform specific + function calls. + + The ProxyMutex also has a reference to the current EThread holding + the lock as a back pointer for verifying that it is released + correctly. + + Acquiring/Releasing locks: + + Included with the ProxyMutex class, there are several macros that + allow you to lock/unlock the underlying mutex object. + +*/ +class ProxyMutex:public RefCountObj +{ +public: + + /** + Underlying mutex object. + + The platform independent mutex for the ProxyMutex class. You + must not modify or set it directly. + + */ + // coverity[uninit_member] + ink_mutex the_mutex; + + /** + Backpointer to owning thread. + + This is a pointer to the thread currently holding the mutex + lock. You must not modify or set this value directly. + + */ + volatile EThreadPtr thread_holding; + + int nthread_holding; + +#ifdef DEBUG + ink_hrtime hold_time; + const char *file; + int line; + const char *handler; + +# ifdef MAX_LOCK_TAKEN + int taken; +# endif //MAX_LOCK_TAKEN + +# ifdef LOCK_CONTENTION_PROFILING + int total_acquires, blocking_acquires, + nonblocking_acquires, successful_nonblocking_acquires, unsuccessful_nonblocking_acquires; + void print_lock_stats(int flag); +# endif //LOCK_CONTENTION_PROFILING +#endif //DEBUG + void free(); + + /** + Constructor - use new_ProxyMutex() instead. + + The constructor of a ProxyMutex object. Initializes the state + of the object but leaves the initialization of the mutex member + until it is needed (through init()). Do not use this constructor, + the preferred mechanism for creating a ProxyMutex is via the + new_ProxyMutex function, which provides a faster allocation. + + */ + ProxyMutex() + { + thread_holding = NULL; + nthread_holding = 0; +#ifdef DEBUG + hold_time = 0; + file = NULL; + line = 0; + handler = NULL; +# ifdef MAX_LOCK_TAKEN + taken = 0; +# endif //MAX_LOCK_TAKEN +# ifdef LOCK_CONTENTION_PROFILING + total_acquires = 0; + blocking_acquires = 0; + nonblocking_acquires = 0; + successful_nonblocking_acquires = 0; + unsuccessful_nonblocking_acquires = 0; +# endif //LOCK_CONTENTION_PROFILING +#endif //DEBUG + // coverity[uninit_member] + } + + /** + Initializes the underlying mutex object. + + After constructing your ProxyMutex object, use this function + to initialize the underlying mutex object with an optional name. + + @param name Name to identify this ProxyMutex. Its use depends + on the given platform. + + */ + void init(const char *name = "UnnamedMutex") { + ink_mutex_init(&the_mutex, name); + } +}; + +// The ClassAlocator for ProxyMutexes +extern inkcoreapi ClassAllocator mutexAllocator; + +/** + Smart pointer to a ProxyMutex object. + + Given that the ProxyMutex object incorporates reference counting + functionality, the ProxyMutexPtr provides a "smart pointer" + interface for using references of the ProxyMutex class. Internally, + it takes care of updating the object's reference count and to + free it once that value drops to zero. + +*/ +class ProxyMutexPtr +{ +public: + + /** + Constructor of the ProxyMutexPtr class. You can provide a pointer + to a ProxyMutex object or set it at a later time with the + assignment operator. + + */ +ProxyMutexPtr(ProxyMutex * ptr = 0):m_ptr(ptr) { + if (m_ptr) + REF_COUNT_OBJ_REFCOUNT_INC(m_ptr); + } + + /** + Copy constructor. + + Constructs a ProxyMutexPtr object from a constant reference to + other. If the object to initialize from has a reference to a + valid ProxyMutex object its reference count is incremented. + + @param src Constant ref to the ProxyMutexPtr to initialize from. + + */ + ProxyMutexPtr(const ProxyMutexPtr & src):m_ptr(src.m_ptr) + { + if (m_ptr) + REF_COUNT_OBJ_REFCOUNT_INC(m_ptr); + } + + /** + The destructor of a ProxyMutexPtr. It will free the ProxyMutex + object pointed at by this instance only if this is the last + reference to the object (reference count equal to zero). + + */ + ~ProxyMutexPtr() { + if (m_ptr && !m_ptr->refcount_dec()) + m_ptr->free(); + } + + /** + Assignment operator using a ProxyMutex object. + + Sets the ProxyMutex object to which this ProxyMutexPtr must + point at. Since the reference to the ProxyMutex is replaced, + the reference count for the previous object (if any) is decremented + and the object is freed if it drops to zero. + + @param p The reference to the ProxyMutex object. + + */ + ProxyMutexPtr & operator =(ProxyMutex * p) { + ProxyMutex *temp_ptr = m_ptr; + if (m_ptr == p) + return (*this); + m_ptr = p; + if (m_ptr) + m_ptr->refcount_inc(); + if (temp_ptr && REF_COUNT_OBJ_REFCOUNT_DEC(((RefCountObj *) temp_ptr)) == 0) + ((RefCountObj *) temp_ptr)->free(); + return (*this); + } + + /** + Assignment operator using another ProxyMutexPtr object. + + Sets the ProxyMutex object to which this ProxyMutexPtr must + point at to that of the 'src'. Since the reference to the + ProxyMutex is replaced, the reference count for the previous + object (if any) is decremented and the object is freed if it + drops to zero. + + @param src The ProxyMutexPtr to get the ProxyMutex reference from. + + */ + ProxyMutexPtr & operator =(const ProxyMutexPtr & src) { + return (operator =(src.m_ptr)); + } + + /** + Disassociates this object's reference to the ProxyMutex object + + This method verifies that the ProxyMutexPtr object no longer + references a ProxyMutex object. If it does, the ProxyMutex's + reference count is decremented and the object is freed if it + drops to zero. + + */ + void clear() + { + if (m_ptr) { + if (!((RefCountObj *) m_ptr)->refcount_dec()) + ((RefCountObj *) m_ptr)->free(); + m_ptr = NULL; + } + } + + // TODO eval if cast op needs to be removed + // The casting operators do not fair well together with comparison + // operators in many cases, gcc-3.4.x isn't too happy about it. It'd + // probably be safer to get rid of them entirely. + /** + Cast operator. + + When the cast (ProxyMutex*) is applied to a ProxyMutexPtr object, + a pointer to the managed ProxyMutex object is returned. + + */ + operator ProxyMutex *() const + { + return (m_ptr); + } + + /** + Pointer member selection operator. + + When applied to a ProxyMutexPtr object, it is applied to the + underlying ProxyMutex object. Make sure this ProxyMutexPtr + object has a valid reference to a ProxyMutex before using it. + + */ + ProxyMutex *operator ->() const + { + return (m_ptr); + } + + /** + Dereference operator. + + Provides access to the ProxyMutex object pointed at by this + ProxyMutexPtr. + + */ + ProxyMutex & operator *() const + { + return (*m_ptr); + } + + /** + Equality operator. + + Returns true if the two pointers are equivalent (the rhs and + the one stored inside the lhs ProxyMutexPtr object), otherwise + false. + + */ + int operator ==(const ProxyMutex * p) const + { + return (m_ptr == p); + } + + /** + Equality operator. + + Returns true if the pointers managed by the rhs and lhs + ProxyMutexPtr objects are equivalent. + + */ + int operator ==(const ProxyMutexPtr & p) const + { + return (m_ptr == p.m_ptr); + } + + /** + Inequality operator. + + Returns true if the two pointers are not equivalent (the rhs + and the one stored inside the lhs ProxyMutexPtr object), otherwise + false. + + */ + int operator !=(const ProxyMutex * p) const + { + return (m_ptr != p); + } + + /** + Inequality operator. + + Returns true if the pointers managed by the rhs and lhs + ProxyMutexPtr objects are not equivalent. + + */ + int operator !=(const ProxyMutexPtr & p) const + { + return (m_ptr != p.m_ptr); + } + + RefCountObj *_ptr() + { + return (RefCountObj *) m_ptr; + } + + /** + Pointer to the specified ProxyMutex. + + This is the pointer that stores the specified ProxyMutex. Do + not set or modify its value directly. + + */ + ProxyMutex *m_ptr; +}; + +inline bool +Mutex_trylock( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif + ProxyMutex * m, EThread * t) +{ + + ink_assert(t != 0); + ink_debug_assert(t == (EThread*)this_thread()); + if (m->thread_holding != t) { + if (!ink_mutex_try_acquire(&m->the_mutex)) { +#ifdef DEBUG + lock_waiting(m->file, m->line, m->handler); +#ifdef LOCK_CONTENTION_PROFILING + m->unsuccessful_nonblocking_acquires++; + m->nonblocking_acquires++; + m->total_acquires++; + m->print_lock_stats(0); +#endif //LOCK_CONTENTION_PROFILING +#endif //DEBUG + return false; + } + m->thread_holding = t; + ink_assert(m->thread_holding); +#ifdef DEBUG + m->file = afile; + m->line = aline; + m->handler = ahandler; + m->hold_time = ink_get_hrtime(); +#ifdef MAX_LOCK_TAKEN + m->taken++; +#endif //MAX_LOCK_TAKEN +#endif //DEBUG + } +#ifdef DEBUG +#ifdef LOCK_CONTENTION_PROFILING + m->successful_nonblocking_acquires++; + m->nonblocking_acquires++; + m->total_acquires++; + m->print_lock_stats(0); +#endif //LOCK_CONTENTION_PROFILING +#endif //DEBUG + m->nthread_holding++; + return true; +} + +inline bool +Mutex_trylock_spin( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif + ProxyMutex * m, EThread * t, int spincnt = 1) +{ + + ink_assert(t != 0); + if (m->thread_holding != t) { + int locked; + do { + if ((locked = ink_mutex_try_acquire(&m->the_mutex))) + break; + } while (--spincnt); + if (!locked) { +#ifdef DEBUG + lock_waiting(m->file, m->line, m->handler); +#ifdef LOCK_CONTENTION_PROFILING + m->unsuccessful_nonblocking_acquires++; + m->nonblocking_acquires++; + m->total_acquires++; + m->print_lock_stats(0); +#endif //LOCK_CONTENTION_PROFILING +#endif //DEBUG + return false; + } + m->thread_holding = t; + ink_debug_assert(m->thread_holding); +#ifdef DEBUG + m->file = afile; + m->line = aline; + m->handler = ahandler; + m->hold_time = ink_get_hrtime(); +#ifdef MAX_LOCK_TAKEN + m->taken++; +#endif //MAX_LOCK_TAKEN +#endif //DEBUG + } +#ifdef DEBUG +#ifdef LOCK_CONTENTION_PROFILING + m->successful_nonblocking_acquires++; + m->nonblocking_acquires++; + m->total_acquires++; + m->print_lock_stats(0); +#endif //LOCK_CONTENTION_PROFILING +#endif //DEBUG + m->nthread_holding++; + return true; +} + +inline int +Mutex_lock( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif + ProxyMutex * m, EThread * t) +{ + + ink_assert(t != 0); + if (m->thread_holding != t) { + ink_mutex_acquire(&m->the_mutex); + m->thread_holding = t; + ink_debug_assert(m->thread_holding); +#ifdef DEBUG + m->file = afile; + m->line = aline; + m->handler = ahandler; + m->hold_time = ink_get_hrtime(); +#ifdef MAX_LOCK_TAKEN + m->taken++; +#endif //MAX_LOCK_TAKEN +#endif //DEBUG + } +#ifdef DEBUG +#ifdef LOCK_CONTENTION_PROFILING + m->blocking_acquires++; + m->total_acquires++; + m->print_lock_stats(0); +#endif // LOCK_CONTENTION_PROFILING +#endif //DEBUG + m->nthread_holding++; + return true; +} + +inline void +Mutex_unlock(ProxyMutex * m, EThread * t) +{ + if (m->nthread_holding) { + ink_assert(t == m->thread_holding); + m->nthread_holding--; + if (!m->nthread_holding) { +#ifdef DEBUG + if (ink_get_hrtime() - m->hold_time > MAX_LOCK_TIME) + lock_holding(m->file, m->line, m->handler); +#ifdef MAX_LOCK_TAKEN + if (m->taken > MAX_LOCK_TAKEN) + lock_taken(m->file, m->line, m->handler); +#endif //MAX_LOCK_TAKEN + m->file = NULL; + m->line = 0; + m->handler = NULL; +#endif //DEBUG + ink_debug_assert(m->thread_holding); + m->thread_holding = 0; + ink_mutex_release(&m->the_mutex); + } + } +} + +struct MutexLock +{ + ProxyMutexPtr m; + MutexLock():m(NULL) + { + }; + + MutexLock( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif //DEBUG + ProxyMutex * am, EThread * t):m(am) + { + + Mutex_lock( +#ifdef DEBUG + afile, aline, ahandler, +#endif //DEBUG + m, t); + } + + void set_and_take( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif //DEBUG + ProxyMutex * am, EThread * t) + { + + m = am; + Mutex_lock( +#ifdef DEBUG + afile, aline, ahandler, +#endif //DEBUG + m, t); + } + + void release() + { + if (m) + Mutex_unlock(m, m->thread_holding); + m.clear(); + } + + ~MutexLock() { + if (m) + Mutex_unlock(m, m->thread_holding); + } + + int operator!() + { + return false; + } + operator bool() + { + return true; + } +}; + +struct MutexTryLock +{ + ProxyMutexPtr m; + volatile bool lock_acquired; + + MutexTryLock( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif //DEBUG + ProxyMutex * am, EThread * t) + { + lock_acquired = Mutex_trylock( +#ifdef DEBUG + afile, aline, ahandler, +#endif //DEBUG + am, t); + if (lock_acquired) + m = am; + } + + MutexTryLock( +#ifdef DEBUG + const char *afile, int aline, const char *ahandler, +#endif //DEBUG + ProxyMutex * am, EThread * t, int sp) + { + lock_acquired = Mutex_trylock_spin( +#ifdef DEBUG + afile, aline, ahandler, +#endif //DEBUG + am, t, sp); + if (lock_acquired) + m = am; + } + + ~MutexTryLock() { + if (m.m_ptr) + Mutex_unlock(m.m_ptr, m.m_ptr->thread_holding); + } + + void release() + { + if (m.m_ptr) { + Mutex_unlock(m.m_ptr, m.m_ptr->thread_holding); + m.clear(); + } + lock_acquired = false; + } + + int operator!() + { + return !lock_acquired; + } + operator bool() + { + return lock_acquired; + } +}; + +inline void +ProxyMutex::free() +{ +#ifdef DEBUG +#ifdef LOCK_CONTENTION_PROFILING + print_lock_stats(1); +#endif +#endif + ink_mutex_destroy(&the_mutex); + mutexAllocator.free(this); +} + +// TODO should take optional mutex "name" identifier, to pass along to the init() fun +/** + Creates a new ProxyMutex object. + + This is the preferred mechanism for constructing objects of the + ProxyMutex class. It provides you with faster allocation than + that of the normal constructor. + + @return A pointer to a ProxyMutex object appropriate for the build + environment. + +*/ +inline ProxyMutex * +new_ProxyMutex() +{ + ProxyMutex *m = mutexAllocator.alloc(); + m->init(); + return m; +} + +/*------------------------------------------------------*\ +| Macros | +\*------------------------------------------------------*/ + +/** + Blocks until the lock to the ProxyMutex is acquired. + + This macro performs a blocking call until the lock to the ProxyMutex + is acquired. This call allocates a special object that holds the + lock to the ProxyMutex only for the scope of the function or + region. It is a good practice to delimit such scope explicitly + with '{' and '}'. + + @param _l Arbitrary name for the lock to use in this call + @param _m A pointer to (or address of) a ProxyMutex object + @param _t The current EThread executing your code. + +*/ +# ifdef DEBUG +# define MUTEX_LOCK(_l,_m,_t) MutexLock _l(__FILE__,__LINE__,NULL,_m,_t) +# else +# define MUTEX_LOCK(_l,_m,_t) MutexLock _l(_m,_t) +# endif //DEBUG + +# ifdef DEBUG +/** + Attempts to acquire the lock to the ProxyMutex. + + This macro attempts to acquire the lock to the specified ProxyMutex + object in a non-blocking manner. After using the macro you can + see if it was successful by comparing the lock variable with true + or false (the variable name passed in the _l parameter). + + @param _l Arbitrary name for the lock to use in this call (lock variable) + @param _m A pointer to (or address of) a ProxyMutex object + @param _t The current EThread executing your code. + +*/ +# define MUTEX_TRY_LOCK(_l,_m,_t) \ +MutexTryLock _l(__FILE__,__LINE__,(char*)NULL,_m,_t) + +/** + Attempts to acquire the lock to the ProxyMutex. + + This macro performs up to the specified number of attempts to + acquire the lock on the ProxyMutex object. It does so by running + a busy loop (busy wait) '_sc' times. You should use it with care + since it blocks the thread during that time and wastes CPU time. + + @param _l Arbitrary name for the lock to use in this call (lock variable) + @param _m A pointer to (or address of) a ProxyMutex object + @param _t The current EThread executing your code. + @param _sc The number of attempts or spin count. It must be a positive value. + +*/ +# define MUTEX_TRY_LOCK_SPIN(_l,_m,_t,_sc) \ +MutexTryLock _l(__FILE__,__LINE__,(char*)NULL,_m,_t,_sc) + +# ifdef PURIFY + +/** + Attempts to acquire the lock to the ProxyMutex. + + This macro attempts to acquire the lock to the specified ProxyMutex + object in a non-blocking manner. After using the macro you can + see if it was successful by comparing the lock variable with true + or false (the variable name passed in the _l parameter). + + @param _l Arbitrary name for the lock to use in this call (lock variable) + @param _m A pointer to (or address of) a ProxyMutex object + @param _t The current EThread executing your code. + @param _c Continuation whose mutex will be attempted to lock. + +*/ +# define MUTEX_TRY_LOCK_FOR(_l,_m,_t,_c) \ +MutexTryLock _l(__FILE__,__LINE__,(char *)NULL,_m,_t) +# else //PURIFY +# define MUTEX_TRY_LOCK_FOR(_l,_m,_t,_c) \ +MutexTryLock _l(__FILE__,__LINE__,HANDLER_NAME(_c),_m,_t) +# endif //PURIFY +# else //DEBUG +# define MUTEX_TRY_LOCK(_l,_m,_t) MutexTryLock _l(_m,_t) +# define MUTEX_TRY_LOCK_SPIN(_l,_m,_t,_sc) MutexTryLock _l(_m,_t,_sc) +# define MUTEX_TRY_LOCK_FOR(_l,_m,_t,_c) MutexTryLock _l(_m,_t) +# endif //DEBUG + +/** + Releases the lock on a ProxyMutex. + + This macro releases the lock on the ProxyMutex, provided it is + currently held. The lock must have been successfully acquired + with one of the MUTEX macros. + + @param _l Arbitrary name for the lock to use in this call (lock + variable) It must be the same name as the one used to acquire the + lock. + +*/ +# define MUTEX_RELEASE(_l) (_l).release() + +///////////////////////////////////// +// DEPRECATED DEPRECATED DEPRECATED +#ifdef DEBUG +# define MUTEX_TAKE_TRY_LOCK(_m,_t) \ +Mutex_trylock(__FILE__,__LINE__,(char*)NULL,_m,_t) +# ifdef PURIFY +# define MUTEX_TAKE_TRY_LOCK_FOR(_m,_t,_c) \ +Mutex_trylock(__FILE__,__LINE__,(char *)NULL,_m,_t) +# define MUTEX_TAKE_TRY_LOCK_FOR_SPIN(_m,_t,_c,_sc) \ +Mutex_trylock_spin(__FILE__,__LINE__,(char *)NULL,_m,_t,_sc) +# else +# define MUTEX_TAKE_TRY_LOCK_FOR(_m,_t,_c) \ +Mutex_trylock(__FILE__,__LINE__,(char*)NULL,_m,_t) +# define MUTEX_TAKE_TRY_LOCK_FOR_SPIN(_m,_t,_c,_sc) \ +Mutex_trylock_spin(__FILE__,__LINE__,HANDLER_NAME(_c),_m,_t,_sc) +# endif +#else +# define MUTEX_TAKE_TRY_LOCK(_m,_t) Mutex_trylock(_m,_t) +# define MUTEX_TAKE_TRY_LOCK_FOR(_m,_t,_c) Mutex_trylock(_m,_t) +# define MUTEX_TAKE_TRY_LOCK_FOR_SPIN(_m,_t,_c,_sc) \ +Mutex_trylock_spin(_m,_t,_sc) +#endif + +#ifdef DEBUG +# define MUTEX_TAKE_LOCK(_m,_t)\ +Mutex_lock(__FILE__,__LINE__,(char*)NULL,_m,_t) +# define MUTEX_SET_AND_TAKE_LOCK(_s,_m,_t)\ +_s.set_and_take(__FILE__,__LINE__,(char*)NULL,_m,_t) +# ifdef PURIFY +# define MUTEX_TAKE_LOCK_FOR(_m,_t,_c) \ +Mutex_lock(__FILE__,__LINE__,(char *)NULL,_m,_t) +# else +# define MUTEX_TAKE_LOCK_FOR(_m,_t,_c) \ +Mutex_lock(__FILE__,__LINE__,HANDLER_NAME(_c),_m,_t) +# endif //PURIFY +#else +# define MUTEX_TAKE_LOCK(_m,_t) Mutex_lock(_m,_t) +# define MUTEX_SET_AND_TAKE_LOCK(_s,_m,_t)_s.set_and_take(_m,_t) +# define MUTEX_TAKE_LOCK_FOR(_m,_t,_c) Mutex_lock(_m,_t) +#endif //DEBUG + +#define MUTEX_UNTAKE_LOCK(_m,_t) Mutex_unlock(_m,_t) +// DEPRECATED DEPRECATED DEPRECATED +///////////////////////////////////// + +#endif // _Lock_h_ diff --git a/iocore/eventsystem/I_PriorityEventQueue.h b/iocore/eventsystem/I_PriorityEventQueue.h new file mode 100644 index 00000000..cd4707b1 --- /dev/null +++ b/iocore/eventsystem/I_PriorityEventQueue.h @@ -0,0 +1,126 @@ +/** @file + + Queue of Events sorted by the "at_timeout" field + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_PriorityEventQueue_h_ +#define _I_PriorityEventQueue_h_ + +#include "libts.h" +#include "I_ProxyAllocator.h" +#include "I_Event.h" + + +// <5ms, 10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120 +#define N_PQ_LIST 10 +#define PQ_BUCKET_TIME(_i) (HRTIME_MSECONDS(5) << (_i)) + +class EThread; + +struct PriorityEventQueue +{ + + Que(Event, link) after[N_PQ_LIST]; + ink_hrtime last_check_time; + uint32_t last_check_buckets; + + void enqueue(Event * e, ink_hrtime now) + { + ink_hrtime t = e->timeout_at - now; + int i = 0; + // equivalent but faster + if (t <= PQ_BUCKET_TIME(3)) + { + if (t <= PQ_BUCKET_TIME(1)) { + if (t <= PQ_BUCKET_TIME(0)) { + i = 0; + } else + { + i = 1; + } + } else { + if (t <= PQ_BUCKET_TIME(2)) { + i = 2; + } else { + i = 3; + } + } + } else { + if (t <= PQ_BUCKET_TIME(7)) { + if (t <= PQ_BUCKET_TIME(5)) { + if (t <= PQ_BUCKET_TIME(4)) { + i = 4; + } else { + i = 5; + } + } else { + if (t <= PQ_BUCKET_TIME(6)) { + i = 6; + } else { + i = 7; + } + } + } else { + if (t <= PQ_BUCKET_TIME(8)) { + i = 8; + } else { + i = 9; + } + } + } + e->in_the_priority_queue = 1; + e->in_heap = i; + after[i].enqueue(e); + } + + void remove(Event * e) + { + ink_assert(e->in_the_priority_queue); + e->in_the_priority_queue = 0; + after[e->in_heap].remove(e); + } + + Event *dequeue_ready(ink_hrtime t) + { + (void) t; + Event *e = after[0].dequeue(); + if (e) { + ink_assert(e->in_the_priority_queue); + e->in_the_priority_queue = 0; + } + return e; + } + + void check_ready(ink_hrtime now, EThread * t); + + ink_hrtime earliest_timeout() + { + for (int i = 0; i < N_PQ_LIST; i++) { + if (after[i].head) + return last_check_time + (PQ_BUCKET_TIME(i) / 2); + } + return last_check_time + HRTIME_FOREVER; + } + + PriorityEventQueue(); +}; + +#endif diff --git a/iocore/eventsystem/I_Processor.h b/iocore/eventsystem/I_Processor.h new file mode 100644 index 00000000..240f50f4 --- /dev/null +++ b/iocore/eventsystem/I_Processor.h @@ -0,0 +1,115 @@ +/** @file + + Public declaration of Processor class + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef _I_Processor_h_ +#define _I_Processor_h_ + +#include "libts.h" + +#define PROCESSOR_RECONFIGURE 0x01 +#define PROCESSOR_CHECK 0x02 +#define PROCESSOR_FIX 0x04 +#define PROCESSOR_IGNORE_ERRORS 0x08 + +class Processor; +class Thread; + +/** + Base class for all of the IO Core processors. + + The Processor class defines a common interface for all the + processors in the IO Core. A processor is multithreaded subsystem + specialized in some type of task or application. For example, + the Event System module includes the EventProcessor which provides + schedulling services, the Net module includes the NetProcessor + which provides networking services, etc. + + You cannot create objects of the Processor class and its methods + have no implementation. Therefore, you are expected to use objects + of a derived type. + + Most of such derived classes, provide a singleton object and is + common case to have a single instance in that application scope. + +*/ +class Processor +{ +public: + virtual ~Processor(); + + /** + Returns a Thread appropriate for the processor. + + Returns a new instance of a Thread or Thread derived class of + a thread which is the thread class for the processor. + + @param thread_index reserved for future use. + + */ + virtual Thread *create_thread(int thread_index); + + /** + Returns the number of threads required for this processor. If + the number is not defined or not used, it is equal to 0. + + */ + virtual int get_thread_count(); + + /** + This function attemps to stop the processor. Please refer to + the documentation on each processor to determine if it is + supported. + + */ + virtual void shutdown() + { + } + + /** + Starts execution of the processor. + + Attempts to start the number of threads specified for the + processor, initializes their states and sets them running. On + failure it returns a negative value. + + @param number_of_threads Positive value indicating the number + of threads to spawn for the processor. + + */ + virtual int start(int number_of_threads) + { + (void) number_of_threads; + return 0; + } + +protected: + Processor(); + +private: + // prevent unauthorized copies (Not implemented) + Processor(const Processor &); + Processor & operator =(const Processor &); +}; + +#endif //_I_Processor_h_ diff --git a/iocore/eventsystem/I_ProtectedQueue.h b/iocore/eventsystem/I_ProtectedQueue.h new file mode 100644 index 00000000..f2916554 --- /dev/null +++ b/iocore/eventsystem/I_ProtectedQueue.h @@ -0,0 +1,60 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Protected Queue, a FIFO queue with the following functionality: + (1). Multiple threads could be simultaneously trying to enqueue + and dequeue. Hence the queue needs to be protected with mutex. + (2). In case the queue is empty, dequeue() sleeps for a specified + amount of time, or until a new element is inserted, whichever + is earlier + + + ****************************************************************************/ +#ifndef _I_ProtectedQueue_h_ +#define _I_ProtectedQueue_h_ + +#include "libts.h" +#include "I_Event.h" +struct ProtectedQueue +{ + void enqueue(Event * e,bool fast_signal=false); + void signal(); + int try_signal(); // Use non blocking lock and if acquired, signal + void enqueue_local(Event * e); // Safe when called from the same thread + void remove(Event * e); + Event *dequeue_local(); + void dequeue_timed(ink_hrtime cur_time, ink_hrtime timeout, bool sleep); + + InkAtomicList al; + ink_mutex lock; + ink_cond might_have_data; + Que(Event, link) localQueue; + + ProtectedQueue(); +}; + +void flush_signals(EThread * t); + +#endif diff --git a/iocore/eventsystem/I_ProxyAllocator.h b/iocore/eventsystem/I_ProxyAllocator.h new file mode 100644 index 00000000..4343b403 --- /dev/null +++ b/iocore/eventsystem/I_ProxyAllocator.h @@ -0,0 +1,102 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ProxyAllocator.h + + + +*****************************************************************************/ +#ifndef _I_ProxyAllocator_h_ +#define _I_ProxyAllocator_h_ + +#include "libts.h" + +class EThread; + +#define MAX_ON_THREAD_FREELIST 512 + +struct ProxyAllocator +{ + int allocated; + void *freelist; + + ProxyAllocator():allocated(0), freelist(0) { } +}; + +template inline C * thread_alloc(ClassAllocator &a, ProxyAllocator & l) +{ + if (l.freelist) { + C *v = (C *) l.freelist; + l.freelist = *(C **) l.freelist; + l.allocated--; + *(void **) v = *(void **) &a.proto.typeObject; + return v; + } + return a.alloc(); +} + +template inline C * thread_alloc_init(ClassAllocator &a, ProxyAllocator & l) +{ + if (l.freelist) { + C *v = (C *) l.freelist; + l.freelist = *(C **) l.freelist; + l.allocated--; + memcpy((void *) v, (void *) &a.proto.typeObject, sizeof(C)); + return v; + } + return a.alloc(); +} + +template inline void +thread_freeup(ClassAllocator &a, ProxyAllocator & l) +{ + while (l.freelist) { + C *v = (C *) l.freelist; + l.freelist = *(C **) l.freelist; + l.allocated--; + a.free(v); // we could use a bulk free here + } + ink_assert(!l.allocated); +} + +#if !defined (PURIFY) && !defined(_IOCORE_WIN32) +#define THREAD_ALLOC(_a, _t) thread_alloc(::_a, _t->_a) +#define THREAD_ALLOC_INIT(_a, _t) thread_alloc_init(::_a, _t->_a) +#define THREAD_FREE_TO(_p, _a, _t, _m) do { \ + *(char **)_p = (char*)_t->_a.freelist; \ + _t->_a.freelist = _p; \ + _t->_a.allocated++; \ + if (_t->_a.allocated > _m) \ + thread_freeup(::_a, _t->_a); \ +} while (0) +#else +#define THREAD_ALLOC(_a, _t) ::_a.alloc() +#define THREAD_ALLOC_INIT(_a, _t) ::_a.alloc() +#define THREAD_FREE_TO(_p, _a, _t, _m) ::_a.free(_p) +#endif +#define THREAD_FREE(_p, _a, _t) \ + THREAD_FREE_TO(_p, _a, _t, MAX_ON_THREAD_FREELIST) + +#endif /* _ProxyAllocator_h_ */ diff --git a/iocore/eventsystem/I_SocketManager.h b/iocore/eventsystem/I_SocketManager.h new file mode 100644 index 00000000..b60e5649 --- /dev/null +++ b/iocore/eventsystem/I_SocketManager.h @@ -0,0 +1,136 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + SocketManager.h + + Handle the allocation of the socket descriptor (fd) resource. + + + ****************************************************************************/ + +#ifndef _I_SocketManager_h_ +#define _I_SocketManager_h_ + +#include "libts.h" +#include "I_EventSystem.h" +#include "I_Thread.h" + +#define DEFAULT_OPEN_MODE 0644 + +class Thread; + +#define SOCKET int + +/** Utility class for socket operations. + */ +struct SocketManager +{ + SocketManager(); + + // result is the socket or -errno + SOCKET socket(int domain = AF_INET, int type = SOCK_STREAM, int protocol = 0, bool bNonBlocking = true); + SOCKET mc_socket(int domain = AF_INET, int type = SOCK_DGRAM, int protocol = 0, bool bNonBlocking = true); + + // result is the fd or -errno + int open(const char *path, int oflag = O_RDWR | O_NDELAY | O_CREAT, mode_t mode = DEFAULT_OPEN_MODE); + + // result is the number of bytes or -errno + int64_t read(int fd, void *buf, int len, void *pOLP = NULL); + int64_t vector_io(int fd, struct iovec *vector, size_t count, int read_request, void *pOLP = 0); + int64_t readv(int fd, struct iovec *vector, size_t count); + int64_t read_vector(int fd, struct iovec *vector, size_t count, void *pOLP = 0); + int64_t pread(int fd, void *buf, int len, off_t offset, char *tag = NULL); + + int recv(int s, void *buf, int len, int flags); + int recvfrom(int fd, void *buf, int size, int flags, struct sockaddr *addr, socklen_t *addrlen); + + int64_t write(int fd, void *buf, int len, void *pOLP = NULL); + int64_t writev(int fd, struct iovec *vector, size_t count); + int64_t write_vector(int fd, struct iovec *vector, size_t count, void *pOLP = 0); + int64_t pwrite(int fd, void *buf, int len, off_t offset, char *tag = NULL); + + int send(int fd, void *buf, int len, int flags); + int sendto(int fd, void *buf, int len, int flags, struct sockaddr *to, int tolen); + int sendmsg(int fd, struct msghdr *m, int flags, void *pOLP = 0); + int64_t lseek(int fd, off_t offset, int whence); + int fstat(int fd, struct stat *); + int unlink(char *buf); + int fsync(int fildes); + int ftruncate(int fildes, off_t length); + int lockf(int fildes, int function, off_t size); + int poll(struct pollfd *fds, unsigned long nfds, int timeout); +#if TS_USE_EPOLL + int epoll_create(int size); + int epoll_close(int eps); + int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); + int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); +#endif +#if TS_USE_KQUEUE + int kqueue(); + int kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, + const struct timespec *timeout); +#endif +#if TS_USE_PORT + int port_create(); + int port_associate(int port, int fd, uintptr_t obj, + int events, void *user); + int port_dissociate(int port, int fd, uintptr_t obj); + int port_getn(int port, port_event_t *list, uint_t max, + uint_t *nget, timespec_t *timeout); +#endif + int shutdown(int s, int how); + int dup(int s); + + // result is the fd or -errno + int accept(int s, struct sockaddr *addr, socklen_t *addrlen); + + // manipulate socket buffers + int get_sndbuf_size(int s); + int get_rcvbuf_size(int s); + int set_sndbuf_size(int s, int size); + int set_rcvbuf_size(int s, int size); + + int getsockname(int s, struct sockaddr *, socklen_t *); + + /** Close the socket. + @return 0 if successful, -errno on error. + */ + int close(int sock); + int ink_bind(int s, struct sockaddr *name, int namelen, short protocol = 0); + + int pagesize; + + virtual ~ SocketManager(); + +private: + // just don't do it + SocketManager(SocketManager &); + SocketManager & operator=(SocketManager &); +}; + +extern SocketManager socketManager; + +#endif /*_SocketManager_h_*/ diff --git a/iocore/eventsystem/I_Tasks.h b/iocore/eventsystem/I_Tasks.h new file mode 100644 index 00000000..5e8c8ea5 --- /dev/null +++ b/iocore/eventsystem/I_Tasks.h @@ -0,0 +1,40 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#if !defined (I_Tasks_h) +#define I_Tasks_h + +#include "I_EventSystem.h" + +extern EventType ET_TASK; + +class TasksProcessor: public Processor +{ + public: + int start(int task_threads = 0); +}; + +extern TasksProcessor tasksProcessor; + +#endif diff --git a/iocore/eventsystem/I_Thread.h b/iocore/eventsystem/I_Thread.h new file mode 100644 index 00000000..0e0bf777 --- /dev/null +++ b/iocore/eventsystem/I_Thread.h @@ -0,0 +1,142 @@ +/** @file + + Thread + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Thread class provides the basic functionality for threads. Typically, + there will be additional derived classes. Having a common base class + for all threads is useful in many cases. I discuss below the use of + Threads in the context of Event Subsystem. Hopefully this would be + typical of other situations. + + EventProcessor needs to create a bunch of threads. It declares a + class called EThread, derived from Thread. It is the responsibility of + the EventProcessor to create and manage all the threads needed in the + Event Subsystem (Note: we have removed the original ThreadManager class + which used to create and manage *all* the threads in the system). By + monitoring, we mean checking the heartbeat of each thread and the + number of threads in the system etc. + + A derived class should either provide the function (and arguments) + needed by the Thread class (see start()), or should define the virtual + function execute(). + + The Thread class maintains a thread_key which registers *all* + the threads in the system (that have been created using Thread or + a derived class), using thread specific data calls. Whenever, you + call this_thread() you get a pointer to the Thread that is currently + executing you. Additionally, the EThread class (derived from Thread) + maintains its own independent key. All (and only) the threads created + in the Event Subsystem are registered with this key. Thus, whenever you + call this_ethread() you get a pointer to EThread. If you happen to call + this_ethread() from inside a thread which is not an EThread, you will + get a NULL value (since that thread will not be registered with the + EThread key). This will hopefully make the use of this_ethread() safer. + Note that an event created with EThread can also call this_thread(), + in which case, it will get a pointer to Thread (rather than to EThread). + + */ + +#ifndef _I_Thread_h +#define _I_Thread_h + +#if !defined(_I_EventSystem_h) && !defined(_P_EventSystem_h) +#error "include I_EventSystem.h or P_EventSystem.h" +-- -include I_Event.h or P_Event.h +#endif +#include "libts.h" + class Thread; +class ProxyMutex; + +#define THREADAPI +#define THREADAPI_RETURN_TYPE void * +typedef THREADAPI_RETURN_TYPE(THREADAPI * ThreadFunction) (void *arg); + +extern ProxyMutex *global_mutex; + +static const int MAX_THREAD_NAME_LENGTH = 16; + +/** + Base class for the threads in the Event System. Thread is the base + class for all the thread classes in the Event System. Objects of the + Thread class represent spawned or running threads and provide minimal + information for its derived classes. Thread objects have a reference + to a ProxyMutex, that is used for atomic operations internally, and + an ink_thread member that is used to identify the thread in the system. + + You should not create an object of the Thread class, they are typically + instantiated after some thread startup mechanism exposed by a processor, + but even then you would probably deal with processor functions and + not the Thread object itself. + +*/ +class Thread +{ +public: + + /*-------------------------------------------*\ + | Common Interface | + \*-------------------------------------------*/ + + /** + System-wide thread identifier. The thread identifier is represented + by the platform independent type ink_thread and it is the system-wide + value assigned to each thread. It is exposed as a convenience for + processors and you should not modify it directly. + + */ + ink_thread tid; + + /** + Thread lock to ensure atomic operations. The thread lock available + to derived classes to ensure atomic operations and protect critical + regions. Do not modify this member directly. + + */ + ProxyMutex *mutex; + + // PRIVATE + void set_specific(); + Thread(); + virtual ~ Thread(); + + static ink_hrtime cur_time; + inkcoreapi static ink_thread_key thread_data_key; + Ptr mutex_ptr; + +private: + // prevent unauthorized copies (Not implemented) + Thread(const Thread &); + Thread & operator =(const Thread &); + +public: + void start(const char* name, ThreadFunction f = NULL, void *a = NULL, size_t stacksize = 0); + + virtual void execute() + { } +}; + +TS_INLINE ink_hrtime ink_get_hrtime(); +TS_INLINE ink_hrtime ink_get_based_hrtime(); +TS_INLINE Thread *this_thread(); + +#endif /*_I_Thread_h*/ diff --git a/iocore/eventsystem/I_VConnection.h b/iocore/eventsystem/I_VConnection.h new file mode 100644 index 00000000..8909e537 --- /dev/null +++ b/iocore/eventsystem/I_VConnection.h @@ -0,0 +1,413 @@ +/** @file + + Public VConnection declaration and associated declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#if !defined (_I_VConnection_h_) +#define _I_VConnection_h_ + +#include "libts.h" +#include "I_EventSystem.h" +#if !defined(I_VIO_h) +#error "include I_VIO.h" +-- -include I_VIO.h +#endif + +// +// Data Types +// +#define VCONNECTION_CACHE_DATA_BASE 0 +#define VCONNECTION_NET_DATA_BASE 100 +#define VCONNECTION_API_DATA_BASE 200 + +// +// Event signals +// + +#define VC_EVENT_NONE EVENT_NONE + +/** When a Continuation is first scheduled on a processor. */ +#define VC_EVENT_IMMEDIATE EVENT_IMMEDIATE + +#define VC_EVENT_READ_READY VC_EVENT_EVENTS_START + +/** + Any data in the accociated buffer *will be written* when the + Continuation returns. + +*/ +#define VC_EVENT_WRITE_READY (VC_EVENT_EVENTS_START+1) + +#define VC_EVENT_READ_COMPLETE (VC_EVENT_EVENTS_START+2) +#define VC_EVENT_WRITE_COMPLETE (VC_EVENT_EVENTS_START+3) + +/** + No more data (end of stream). It should be interpreted by a + protocol engine as either a COMPLETE or ERROR. + +*/ +#define VC_EVENT_EOS (VC_EVENT_EVENTS_START+4) + +#define VC_EVENT_ERROR EVENT_ERROR + +/** + VC_EVENT_INACTIVITY_TIMEOUT indiates that the operation (read or write) has: + -# been enabled for more than the inactivity timeout period + (for a read, there has been space in the buffer) + (for a write, there has been data in the buffer) + -# no progress has been made + (for a read, no data has been read from the connection) + (for a write, no data has been written to the connection) + +*/ +#define VC_EVENT_INACTIVITY_TIMEOUT (VC_EVENT_EVENTS_START+5) + +/** + Total time for some operation has been exeeded, regardless of any + intermediate progress. + +*/ +#define VC_EVENT_ACTIVE_TIMEOUT (VC_EVENT_EVENTS_START+6) + +#define VC_EVENT_OOB_COMPLETE (VC_EVENT_EVENTS_START+7) + +// +// Event names +// + +// +// VC_EVENT_READ_READ occurs when data *has been written* into +// the associated buffer. +// +// VC_EVENT_ERROR indicates that some error has occured. The +// "data" will be either 0 if the errno is unavailable or errno. +// +// VC_EVENT_INTERVAL indidates that an interval timer has expired. +// + +// +// Event return codes +// +#define VC_EVENT_DONE CONTINUATION_DONE +#define VC_EVENT_CONT CONTINUATION_CONT + +////////////////////////////////////////////////////////////////////////////// +// +// Support Data Structures +// +////////////////////////////////////////////////////////////////////////////// + class VConnection; + +typedef int (VConnection::*VConnectionHandler) (int event, void *data); + +/** Used in VConnection::shutdown(). */ +enum ShutdownHowTo_t +{ + IO_SHUTDOWN_READ = 0, + IO_SHUTDOWN_WRITE, + IO_SHUTDOWN_READWRITE +}; + +/** + Base class for the connection classes that provide IO capabilities. + + The VConnection class is an abstract representation of a uni or + bi-directional data conduit returned by a Processor. In a sense, + they serve a similar purpose to file descriptors. A VConnection + is a pure base class that defines methods to perform stream IO. + It is also a Continuation that is called back from processors. + +*/ +class VConnection:public Continuation +{ +public: + + virtual ~ VConnection(); + + /** + Read data from the VConnection. + + Called by a state machine to read data from the VConnection. + Processors implementing read functionality take out lock, put + new bytes on the buffer and call the continuation back before + releasing the lock in order to enable the state machine to + handle transfer schemes where the end of a given transaction + is marked by a special character (ie: NNTP). + + Possible Event Codes + + On the callback to the continuation, the VConnection may use + on of the following values for the event code: + + + + + + + + + + + + + + + + + + + + + + +
Event codeMeaning
VC_EVENT_READ_READYData has been added to the buffer or the buffer is full
VC_EVENT_READ_COMPLETEThe amount of data indicated by 'nbytes' has been read into the + buffer
VC_EVENT_EOSThe stream being read from has been shutdown
VC_EVENT_ERRORAn error occurred during the read
+ + @param c Continuation to be called back with events. + @param nbytes Number of bytes to read. If unknown, nbytes must + be set to INT64_MAX. + @param buf buffer to read into. + @return VIO representing the scheduled IO operation. + + */ + virtual VIO *do_io_read(Continuation *c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) = 0; + + /** + Write data to the VConnection. + + This method is called by a state machine to write data to the + VConnection. + + Possible Event Codes + + On the callback to the continuation, the VConnection may use + on of the following event codes: + + + + + + + + + + + + + + + + + + + + + + + + + + +
Event codeMeaning
VC_EVENT_WRITE_READYData was written from the reader or there are no bytes available + for the reader to write.
VC_EVENT_WRITE_COMPLETEThe amount of data indicated by 'nbytes' has been written to the + VConnection
VC_EVENT_INACTIVITY_TIMEOUTNo activity was performed for a certain period.
VC_EVENT_ACTIVE_TIMEOUTWrite operation continued beyond a time limit.
VC_EVENT_ERRORAn error occurred during the write
+ + @param c Continuation to be called back with events. + @param nbytes Number of bytes to write. If unknown, nbytes must + be set to INT64_MAX. + @param buf Reader whose data is to be read from. + @param owner + @return VIO representing the scheduled IO operation. + + */ + virtual VIO *do_io_write(Continuation *c = NULL, + int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) = 0; + + /** + Indicate that the VConnection is no longer needed. + + Once the state machine has finished using this VConnection, it + must call this function to indicate that the VConnection can + be deallocated. After a close has been called, the VConnection + and underlying processor must not send any more events related + to this VConnection to the state machine. Likeswise, the state + machine must not access the VConnection or any VIOs obtained + from it after calling this method. + + @param lerrno indicates where a close is a normal close or an + abort. The difference between a normal close and an abort + depends on the underlying type of the VConnection. + + */ + virtual void do_io_close(int lerrno = -1) = 0; + + /** + Terminate one or both directions of the VConnection. + + Indicates that one or both sides of the VConnection should be + terminated. After this call is issued, no further I/O can be + done on the specified direction of the connection. The processor + must not send any further events (including timeout events) to + the state machine, and the state machine must not use any VIOs + from a shutdown direction of the connection. Even if both sides + of a connection are shutdown, the state machine must still call + do_io_close() when it wishes the VConnection to be deallocated. + + Possible howto values + + + + + + + + + + + + + + + + + + +
ValueMeaning
IO_SHUTDOWN_READIndicates that this VConnection should not generate any more + read events
IO_SHUTDOWN_WRITEIndicates that this VConnection should not generate any more + write events
IO_SHUTDOWN_READWRITEIndicates that this VConnection should not generate any more + read nor write events
+ + @param howto Specifies which direction of the VConnection to + shutdown. + + */ + virtual void do_io_shutdown(ShutdownHowTo_t howto) = 0; + + VConnection(ProxyMutex *aMutex); + +#if defined (_IOCORE_WIN32_WINNT) + virtual void set_nbytes(VIO *vio, int64_t nbytes); +#endif + + /** @deprecated */ + VIO *do_io(int op, Continuation *c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0, int data = 0); + + // Private + // Set continuation on a given vio. The public interface + // is through VIO::set_continuation() + virtual void set_continuation(VIO *vio, Continuation *cont); + + // Reenable a given vio. The public interface is through VIO::reenable + virtual void reenable(VIO *vio); + virtual void reenable_re(VIO *vio); + + /** + Convenience function to retreive information from VConnection. + + This function is provided as a convenience for state machines + to transmit information from/to a VConnection without breaking + the VConnection abstraction. Its behavior varies depending on + the type of VConnection being used. + + @param id Identifier associated to interpret the data field + @param data Value or pointer with state machine or VConnection data. + @return True if the oparation is successful. + + */ + virtual bool get_data(int id, void *data) + { + (void) id; + (void) data; + return false; + } + + /** + Convenience function to set information into the VConnection. + + This function is provided as a convenience for state machines + to transmit information from/to a VConnection without breaking + the VConnection abstraction. Its behavior varies depending on + the type of VConnection being used. + + @param id Identifier associated to interpret the data field. + @param data Value or pointer with state machine or VConnection data. + @return True if the oparation is successful. + + */ + virtual bool set_data(int id, void *data) + { + (void) id; + (void) data; + return false; + } + +public: + + /** + The error code from the last error. + + Indicates the last error on the VConnection. They are either + system error codes or from the InkErrno.h file. + + */ + int lerrno; +}; + +struct DummyVConnection: public VConnection +{ + virtual VIO *do_io_write(Continuation *c = NULL, int64_t nbytes = INT64_MAX, IOBufferReader *buf = 0, bool owner = false) { + (void) c; + (void) nbytes; + (void) buf; + (void) owner; + ink_debug_assert(!"VConnection::do_io_write -- " "cannot use default implementation"); + return NULL; + } + virtual VIO *do_io_read(Continuation *c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer *buf = 0) { + (void) c; + (void) nbytes; + (void) buf; + ink_debug_assert(!"VConnection::do_io_read -- " "cannot use default implementation"); + return NULL; + } + virtual void do_io_close(int alerrno = -1) { + (void) alerrno; + ink_debug_assert(!"VConnection::do_io_close -- " "cannot use default implementation"); + } + virtual void do_io_shutdown(ShutdownHowTo_t howto) + { + (void) howto; + ink_debug_assert(!"VConnection::do_io_shutdown -- " "cannot use default implementation"); + } +#ifdef _IOCORE_WIN32_WINNT + virtual void set_nbytes(VIO *vio, int64_t nbytes) + { + (void) vio; + (void) nbytes; + ink_debug_assert(!"DummyVConnection::set_nbytes -- " "cannot use default implementation"); + } +#endif +DummyVConnection(ProxyMutex *m):VConnection(m) { + } +}; + +#endif /*_I_VConnection_h_*/ diff --git a/iocore/eventsystem/I_VIO.h b/iocore/eventsystem/I_VIO.h new file mode 100644 index 00000000..78873398 --- /dev/null +++ b/iocore/eventsystem/I_VIO.h @@ -0,0 +1,220 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#if !defined (I_VIO_h) +#define I_VIO_h + +#include "libts.h" +#include "I_EventSystem.h" +#if !defined(I_IOBuffer_h) +#error "include I_IOBuffer.h" +-- -include I_IOBuffer.h +#endif +#include "ink_apidefs.h" + class Continuation; +class VConnection; +class IOVConnection; +class MIOBuffer; +class ProxyMutex; + +/** + Descriptor for an IO operation. + + A VIO is a descriptor for an in progress IO operation. It is + returned from do_io_read() and do_io_write() methods on VConnections. + Through the VIO, the state machine can monitor the progress of + an operation and reenable the operation when data becomes available. + + The VIO operation represents several types of operations, and + they can be identified through the 'op' member. It can take any + of the following values: + + + + + + + + + + + + + + + + + +
ConstantMeaning
READThe VIO represents a read operation
WRITEThe VIO represents a write operation
CLOSEThe VIO represents the request to close the + VConnection
ABORT
SHUTDOWN_READ
SHUTDOWN_WRITE
SHUTDOWN_READWRITE
SEEK
PREAD
PWRITE
STAT
+ +*/ +class VIO +{ +public: + ~VIO() + { + } + + /** Interface for the VConnection that owns this handle. */ + Continuation *get_continuation(); + void set_continuation(Continuation * cont); + + /** + Set nbytes to be what is current available. + + Interface to set nbytes to be ndone + buffer.reader()->read_avail() + if a reader is set. + */ + void done(); + + /** + Determine the number of bytes remaining. + + Convenience function to determine how many bytes the operation + has remaining. + + @return The number of bytes to be processed by the operation. + + */ + int64_t ntodo(); + + ///////////////////// + // buffer settings // + ///////////////////// + void set_writer(MIOBuffer * writer); + void set_reader(IOBufferReader * reader); + MIOBuffer *get_writer(); + IOBufferReader *get_reader(); + + /** + Reenable the IO operation. + + Interface that the state machine uses to reenable an I/O + operation. Reenable tells the VConnection that more data is + available for the operation and that it should try to continue + the operation in progress. I/O operations become disabled when + they can make no forward progress. For a read this means that + it's buffer is full. For a write, that it's buffer is empty. + If reenable is called and progress is still not possible, it + is ignored and no events are generated. However, unnecessary + reenables (ones where no progress can be made) should be avoided + as they hurt system throughput and waste CPU. + + */ + inkcoreapi void reenable(); + + /** + Reenable the IO operation. + + Interface that the state machine uses to reenable an I/O + operation. Reenable tells the VConnection that more data is + available for the operation and that it should try to continue + the operation in progress. I/O operations become disabled when + they can make no forward progress. For a read this means that + it's buffer is full. For a write, that it's buffer is empty. + If reenable is called and progress is still not possible, it + is ignored and no events are generated. However, unnecessary + reenables (ones where no progress can be made) should be avoided + as they hurt system throughput and waste CPU. + + */ + inkcoreapi void reenable_re(); + + VIO(int aop); + VIO(); + + enum + { + NONE = 0, READ, WRITE, CLOSE, ABORT, + SHUTDOWN_READ, SHUTDOWN_WRITE, SHUTDOWN_READWRITE, + SEEK, PREAD, PWRITE, STAT + }; + +public: + + /** + Continuation to callback. + + Used by the VConnection to store who is the continuation to + call with events for this operation. + + */ + Continuation * _cont; + + /** + Number of bytes to be done for this operation. + + The total number of bytes this operation must complete. + + */ + int64_t nbytes; + + /** + Number of bytes already completed. + + The number of bytes that already have been completed for the + operation. Processor can update this value only if they hold + the lock. + + */ + int64_t ndone; + + /** + Type of operation. + + The type of operation that this VIO represents. + + */ + int op; + + /** + Provides access to the reader or writer for this operation. + + Contains a pointer to the IOBufferReader if the operation is a + write and a pointer to a MIOBuffer if the operation is a read. + + */ + MIOBufferAccessor buffer; + + /** + Internal backpointer to the VConnection for use in the reenable + functions. + + */ + VConnection *vc_server; + + /** + Reference to the state machine's mutex. + + Maintains a reference to the state machine's mutex to allow + processors to safely lock the operation even if the state machine + has closed the VConnection and deallocated itself. + + */ + Ptr mutex; +}; + +#include "I_VConnection.h" +#endif diff --git a/iocore/eventsystem/Inline.cc b/iocore/eventsystem/Inline.cc new file mode 100644 index 00000000..3d52e0bd --- /dev/null +++ b/iocore/eventsystem/Inline.cc @@ -0,0 +1,32 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Inline Functions as globals for users using the public interface + * + */ +#define TS_INLINE +#define INLINE_CC + +#include "P_EventSystem.h" + diff --git a/iocore/eventsystem/Lock.cc b/iocore/eventsystem/Lock.cc new file mode 100644 index 00000000..8f9ee346 --- /dev/null +++ b/iocore/eventsystem/Lock.cc @@ -0,0 +1,112 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Basic Locks for Threads + + + +**************************************************************************/ +#include "P_EventSystem.h" + +ClassAllocator mutexAllocator("mutexAllocator"); + +// #define ERROR_CONFIG_TAG_LOCKS + +#ifdef ERROR_CONFIG_TAG_LOCKS +#include "Diags.h" +#endif + +#ifdef DEBUG // debug build needs lock_* functions +#undef INK_NO_LOCKS +#endif + +void +lock_waiting(const char *file, int line, const char *handler) +{ + (void) file; + (void) line; + (void) handler; +#ifdef ERROR_CONFIG_TAG_LOCKS + if (is_diags_on("locks")) + fprintf(stderr, "WARNING: waiting on lock %s:%d for %s\n", + file ? file : "UNKNOWN", line, handler ? handler : "UNKNOWN"); +#endif +} + +void +lock_holding(const char *file, int line, const char *handler) +{ + (void) file; + (void) line; + (void) handler; +#ifdef ERROR_CONFIG_TAG_LOCKS + if (is_diags_on("locks")) + fprintf(stderr, "WARNING: holding lock %s:%d too long for %s\n", + file ? file : "UNKNOWN", line, handler ? handler : "UNKNOWN"); +#endif +} + +void +lock_taken(const char *file, int line, const char *handler) +{ + (void) file; + (void) line; + (void) handler; +#ifdef ERROR_CONFIG_TAG_LOCKS + if (is_diags_on("locks")) + fprintf(stderr, "WARNING: lock %s:%d taken too many times for %s\n", + file ? file : "UNKNOWN", line, handler ? handler : "UNKNOWN"); +#endif +} + +#ifdef LOCK_CONTENTION_PROFILING +void +ProxyMutex::print_lock_stats(int flag) +{ + if (flag) { + if (total_acquires < 10) + return; + printf("Lock Stats (Dying):successful %d (%.2f%%), unsuccessful %d (%.2f%%) blocking %d \n", + successful_nonblocking_acquires, + (nonblocking_acquires > 0 ? + successful_nonblocking_acquires * 100.0 / nonblocking_acquires : 0.0), + unsuccessful_nonblocking_acquires, + (nonblocking_acquires > 0 ? + unsuccessful_nonblocking_acquires * 100.0 / nonblocking_acquires : 0.0), blocking_acquires); + fflush(stdout); + } else { + if (!(total_acquires % 100)) { + printf("Lock Stats (Alive):successful %d (%.2f%%), unsuccessful %d (%.2f%%) blocking %d \n", + successful_nonblocking_acquires, + (nonblocking_acquires > 0 ? + successful_nonblocking_acquires * 100.0 / nonblocking_acquires : 0.0), + unsuccessful_nonblocking_acquires, + (nonblocking_acquires > 0 ? + unsuccessful_nonblocking_acquires * 100.0 / nonblocking_acquires : 0.0), blocking_acquires); + fflush(stdout); + } + } +} +#endif //LOCK_CONTENTION_PROFILING diff --git a/iocore/eventsystem/Makefile.am b/iocore/eventsystem/Makefile.am new file mode 100644 index 00000000..81a2dc84 --- /dev/null +++ b/iocore/eventsystem/Makefile.am @@ -0,0 +1,67 @@ +# Makefile.am for the traffic/iocore/eventsystem hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/records + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +noinst_LIBRARIES = libinkevent.a + +libinkevent_a_SOURCES = \ + EventSystem.cc \ + I_Action.h \ + I_Continuation.h \ + I_EThread.h \ + I_Event.h \ + I_EventProcessor.h \ + I_EventSystem.h \ + I_IOBuffer.h \ + I_Lock.h \ + IOBuffer.cc \ + I_PriorityEventQueue.h \ + I_Processor.h \ + I_ProtectedQueue.h \ + I_ProxyAllocator.h \ + I_SocketManager.h \ + I_Thread.h \ + I_VConnection.h \ + I_VIO.h \ + Lock.cc \ + P_EventSystem.h \ + P_Freer.h \ + P_IOBuffer.h \ + P_ProtectedQueue.h \ + PQ-List.cc \ + Processor.cc \ + ProtectedQueue.cc \ + P_Thread.h \ + P_UnixEThread.h \ + P_UnixEvent.h \ + P_UnixEventProcessor.h \ + P_UnixSocketManager.h \ + P_VConnection.h \ + P_VIO.h \ + SocketManager.cc \ + Thread.cc \ + UnixEThread.cc \ + UnixEvent.cc \ + UnixEventProcessor.cc \ + Inline.cc \ + Tasks.cc \ + I_Tasks.h diff --git a/iocore/eventsystem/Makefile.in b/iocore/eventsystem/Makefile.in new file mode 100644 index 00000000..1aad95c0 --- /dev/null +++ b/iocore/eventsystem/Makefile.in @@ -0,0 +1,752 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/eventsystem hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = iocore/eventsystem +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinkevent_a_AR = $(AR) $(ARFLAGS) +libinkevent_a_LIBADD = +am_libinkevent_a_OBJECTS = EventSystem.$(OBJEXT) IOBuffer.$(OBJEXT) \ + Lock.$(OBJEXT) PQ-List.$(OBJEXT) Processor.$(OBJEXT) \ + ProtectedQueue.$(OBJEXT) SocketManager.$(OBJEXT) \ + Thread.$(OBJEXT) UnixEThread.$(OBJEXT) UnixEvent.$(OBJEXT) \ + UnixEventProcessor.$(OBJEXT) Inline.$(OBJEXT) Tasks.$(OBJEXT) +libinkevent_a_OBJECTS = $(am_libinkevent_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinkevent_a_SOURCES) +DIST_SOURCES = $(libinkevent_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/records + +noinst_LIBRARIES = libinkevent.a +libinkevent_a_SOURCES = \ + EventSystem.cc \ + I_Action.h \ + I_Continuation.h \ + I_EThread.h \ + I_Event.h \ + I_EventProcessor.h \ + I_EventSystem.h \ + I_IOBuffer.h \ + I_Lock.h \ + IOBuffer.cc \ + I_PriorityEventQueue.h \ + I_Processor.h \ + I_ProtectedQueue.h \ + I_ProxyAllocator.h \ + I_SocketManager.h \ + I_Thread.h \ + I_VConnection.h \ + I_VIO.h \ + Lock.cc \ + P_EventSystem.h \ + P_Freer.h \ + P_IOBuffer.h \ + P_ProtectedQueue.h \ + PQ-List.cc \ + Processor.cc \ + ProtectedQueue.cc \ + P_Thread.h \ + P_UnixEThread.h \ + P_UnixEvent.h \ + P_UnixEventProcessor.h \ + P_UnixSocketManager.h \ + P_VConnection.h \ + P_VIO.h \ + SocketManager.cc \ + Thread.cc \ + UnixEThread.cc \ + UnixEvent.cc \ + UnixEventProcessor.cc \ + Inline.cc \ + Tasks.cc \ + I_Tasks.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/eventsystem/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/eventsystem/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinkevent.a: $(libinkevent_a_OBJECTS) $(libinkevent_a_DEPENDENCIES) + -rm -f libinkevent.a + $(libinkevent_a_AR) libinkevent.a $(libinkevent_a_OBJECTS) $(libinkevent_a_LIBADD) + $(RANLIB) libinkevent.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EventSystem.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IOBuffer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Lock.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PQ-List.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Processor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ProtectedQueue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketManager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tasks.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixEThread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixEvent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixEventProcessor.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/eventsystem/PQ-List.cc b/iocore/eventsystem/PQ-List.cc new file mode 100644 index 00000000..483b6b1a --- /dev/null +++ b/iocore/eventsystem/PQ-List.cc @@ -0,0 +1,63 @@ +/** @file + + Queue of Events sorted by the "timeout_at" field impl as binary heap + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_EventSystem.h" + +PriorityEventQueue::PriorityEventQueue() +{ + last_check_time = ink_get_based_hrtime_internal(); + last_check_buckets = last_check_time / PQ_BUCKET_TIME(0); +} + +void +PriorityEventQueue::check_ready(ink_hrtime now, EThread * t) +{ + int i, j, k = 0; + uint32_t check_buckets = (uint32_t) (now / PQ_BUCKET_TIME(0)); + uint32_t todo_buckets = check_buckets ^ last_check_buckets; + last_check_time = now; + last_check_buckets = check_buckets; + todo_buckets &= ((1 << (N_PQ_LIST - 1)) - 1); + while (todo_buckets) { + k++; + todo_buckets >>= 1; + } + for (i = 1; i <= k; i++) { + Event *e; + Que(Event, link) q = after[i]; + after[i].clear(); + while ((e = q.dequeue()) != NULL) { + if (e->cancelled) { + e->in_the_priority_queue = 0; + e->cancelled = 0; + EVENT_FREE(e, eventAllocator, t); + } else { + ink_hrtime tt = e->timeout_at - now; + for (j = i; j > 0 && tt <= PQ_BUCKET_TIME(j - 1);) + j--; + e->in_heap = j; + after[j].enqueue(e); + } + } + } +} diff --git a/iocore/eventsystem/P_EventSystem.h b/iocore/eventsystem/P_EventSystem.h new file mode 100644 index 00000000..a121bf52 --- /dev/null +++ b/iocore/eventsystem/P_EventSystem.h @@ -0,0 +1,87 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Event Subsystem + + + +**************************************************************************/ +#ifndef _P_EventSystem_h +#define _P_EventSystem_h + +#ifndef INLINE_CC +#undef TS_INLINE +#define TS_INLINE inline +#endif + +#include "libts.h" + +#include "I_EventSystem.h" + +#include "P_Thread.h" +#include "P_VIO.h" +#include "P_IOBuffer.h" +#include "P_VConnection.h" +#include "P_Freer.h" +#include "P_UnixEvent.h" +#include "P_UnixEThread.h" +#include "P_ProtectedQueue.h" +#include "P_UnixEventProcessor.h" +#include "P_UnixSocketManager.h" +#undef EVENT_SYSTEM_MODULE_VERSION +#define EVENT_SYSTEM_MODULE_VERSION makeModuleVersion( \ + EVENT_SYSTEM_MODULE_MAJOR_VERSION, \ + EVENT_SYSTEM_MODULE_MINOR_VERSION, \ + PRIVATE_MODULE_HEADER) + + +// Macro definitions + +// error signalling macros +#define IOCORE_SignalWarning REC_SignalWarning +#define IOCORE_SignalError(_buf, _already) { \ + if(_already == false) \ + IOCORE_SignalManager(REC_SIGNAL_CONFIG_ERROR, _buf); \ + _already = true; \ + Warning(_buf); \ +} +#define IOCORE_SignalManager REC_SignalManager + +// configuration macros +#define IOCORE_RegisterConfigInteger RecRegisterConfigInt +#define IOCORE_RegisterConfigString RecRegisterConfigString +#define IOCORE_ReadConfigInt32 REC_ReadConfigInt32 +#define IOCORE_ReadConfigInteger REC_ReadConfigInteger +#define IOCORE_ReadConfigFloat REC_ReadConfigFloat +#define IOCORE_ReadConfigStringAlloc REC_ReadConfigStringAlloc +#define IOCORE_ReadConfigString REC_ReadConfigString +#define IOCORE_RegisterConfigUpdateFunc REC_RegisterConfigUpdateFunc +#define IOCORE_EstablishStaticConfigInteger REC_EstablishStaticConfigInteger +#define IOCORE_EstablishStaticConfigInt32 REC_EstablishStaticConfigInt32 +#define IOCORE_EstablishStaticConfigInt32U REC_EstablishStaticConfigInt32U +#define IOCORE_ConfigReadInteger REC_ConfigReadInteger +#define IOCORE_ConfigReadString REC_ConfigReadString + +#endif diff --git a/iocore/eventsystem/P_Freer.h b/iocore/eventsystem/P_Freer.h new file mode 100644 index 00000000..de23efac --- /dev/null +++ b/iocore/eventsystem/P_Freer.h @@ -0,0 +1,128 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#if !defined(_P_Freer_h_) +#define _P_Freer_h_ + + +#include "libts.h" + +template struct DeleterContinuation: public Continuation +{ +public: // Needed by WinNT compiler (compiler bug) + C * p; + int dieEvent(int event, void *e) + { + (void) event; + (void) e; + if (p) + delete p; + delete this; + return EVENT_DONE; + } + DeleterContinuation(C * ap):Continuation(new_ProxyMutex()), p(ap) + { + SET_HANDLER(&DeleterContinuation::dieEvent); + } +}; + +template TS_INLINE void +new_Deleter(C * ap, ink_hrtime t) +{ + eventProcessor.schedule_in(NEW(new DeleterContinuation (ap)), t, ET_CALL); +} + +template struct FreeCallContinuation: public Continuation +{ +public: // Needed by WinNT compiler (compiler bug) + C * p; + int dieEvent(int event, void *e) + { + (void) event; + (void) e; + p->free(); + delete this; + return EVENT_DONE; + } + FreeCallContinuation(C * ap):Continuation(NULL), p(ap) + { + SET_HANDLER(&FreeCallContinuation::dieEvent); + } +}; + +template TS_INLINE void +new_FreeCaller(C * ap, ink_hrtime t) +{ + eventProcessor.schedule_in(NEW(new FreeCallContinuation (ap)), t, ET_CALL); +} + +struct FreerContinuation; +typedef int (FreerContinuation::*FreerContHandler) (int, void *); + +struct FreerContinuation: public Continuation +{ + void *p; + int dieEvent(int event, Event * e) + { + (void) event; + (void) e; + xfree(p); + delete this; + return EVENT_DONE; + } + FreerContinuation(void *ap):Continuation(NULL), p(ap) + { + SET_HANDLER((FreerContHandler) & FreerContinuation::dieEvent); + } +}; + +TS_INLINE void +new_Freer(void *ap, ink_hrtime t) +{ + eventProcessor.schedule_in(NEW(new FreerContinuation(ap)), t, ET_CALL); +} + +template struct DereferContinuation: public Continuation +{ + C *p; + int dieEvent(int event, Event * e) + { + (void) event; + (void) e; + p->refcount_dec(); + delete this; + return EVENT_DONE; + } + DereferContinuation(C * ap):Continuation(NULL), p(ap) + { + SET_HANDLER(&DereferContinuation::dieEvent); + } +}; + +template TS_INLINE void +new_Derefer(C * ap, ink_hrtime t) +{ + eventProcessor.schedule_in(NEW(new DereferContinuation (ap)), t, ET_CALL); +} + +#endif /* _Freer_h_ */ diff --git a/iocore/eventsystem/P_IOBuffer.h b/iocore/eventsystem/P_IOBuffer.h new file mode 100644 index 00000000..b9ccce0f --- /dev/null +++ b/iocore/eventsystem/P_IOBuffer.h @@ -0,0 +1,1191 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +#if !defined (_P_IOBuffer_h) +#define _P_IOBuffer_h +#include "libts.h" + +// TODO: I think we're overly aggressive here on making MIOBuffer 64-bit +// but not sure it's worthwhile changing anything to 32-bit honestly. + +////////////////////////////////////////////////////////////// +// +// returns 0 for DEFAULT_BUFFER_BASE_SIZE, +// +1 for each power of 2 +// +////////////////////////////////////////////////////////////// +TS_INLINE int64_t +buffer_size_to_index(int64_t size, int64_t max = max_iobuffer_size) +{ + int64_t r = max; + + while (r && BUFFER_SIZE_FOR_INDEX(r - 1) >= size) + r--; + return r; +} + +TS_INLINE int64_t +iobuffer_size_to_index(int64_t size, int64_t max) +{ + if (size > BUFFER_SIZE_FOR_INDEX(max)) + return BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size); + return buffer_size_to_index(size, max); +} + +TS_INLINE int64_t +index_to_buffer_size(int64_t idx) +{ + if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(idx)) + return BUFFER_SIZE_FOR_INDEX(idx); + else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(idx)) + return BUFFER_SIZE_FOR_XMALLOC(idx); + // coverity[dead_error_condition] + else if (BUFFER_SIZE_INDEX_IS_CONSTANT(idx)) + return BUFFER_SIZE_FOR_CONSTANT(idx); + // coverity[dead_error_line] + return 0; +} + +TS_INLINE IOBufferBlock * +iobufferblock_clone(IOBufferBlock * b, int64_t offset, int64_t len) +{ + + IOBufferBlock *start_buf = NULL; + IOBufferBlock *current_buf = NULL; + + while (b && len >= 0) { + char *start = b->_start; + char *end = b->_end; + int64_t max_bytes = end - start; + max_bytes -= offset; + if (max_bytes <= 0) { + offset = -max_bytes; + b = b->next; + continue; + } + int64_t bytes = len; + if (bytes >= max_bytes) + bytes = max_bytes; + IOBufferBlock *new_buf = b->clone(); + new_buf->_start += offset; + new_buf->_buf_end = new_buf->_end = new_buf->_start + bytes; + if (!start_buf) { + start_buf = new_buf; + current_buf = start_buf; + } else { + current_buf->next = new_buf; + current_buf = new_buf; + } + len -= bytes; + b = b->next; + offset = 0; + } + return start_buf; +} + +TS_INLINE IOBufferBlock * +iobufferblock_skip(IOBufferBlock * b, int64_t *poffset, int64_t *plen, int64_t write) +{ + int64_t offset = *poffset; + int64_t len = write; + while (b && len >= 0) { + int64_t max_bytes = b->read_avail(); + max_bytes -= offset; + if (max_bytes <= 0) { + offset = -max_bytes; + b = b->next; + continue; + } + if (len >= max_bytes) { + b = b->next; + len -= max_bytes; + offset = 0; + } else { + offset = offset + len; + break; + } + } + *poffset = offset; + *plen -= write; + return b; +} + +#ifdef TRACK_BUFFER_USER +struct Resource; +extern Resource *res_lookup(const char *path); + +TS_INLINE void +iobuffer_mem_inc(const char *_loc, int64_t _size_index) +{ + if (!res_track_memory) + return; + + if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index)) + return; + + if (!_loc) + _loc = "memory/IOBuffer/UNKNOWN-LOCATION"; + Resource *res = res_lookup(_loc); + ink_debug_assert(strcmp(_loc, res->path) == 0); +#ifdef DEBUG + int64_t r = ink_atomic_increment64(&res->value, index_to_buffer_size(_size_index)); + ink_debug_assert(r >= 0); +#else + ink_atomic_increment64(&res->value, index_to_buffer_size(_size_index)); +#endif +} + +TS_INLINE void +iobuffer_mem_dec(const char *_loc, int64_t _size_index) +{ + if (!res_track_memory) + return; + + if (!BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index)) + return; + if (!_loc) + _loc = "memory/IOBuffer/UNKNOWN-LOCATION"; + Resource *res = res_lookup(_loc); + ink_debug_assert(strcmp(_loc, res->path) == 0); +#ifdef DEBUG + int64_t r = ink_atomic_increment64(&res->value, -index_to_buffer_size(_size_index)); + ink_debug_assert(r >= index_to_buffer_size(_size_index)); +#else + ink_atomic_increment64(&res->value, -index_to_buffer_size(_size_index)); +#endif +} +#endif + +////////////////////////////////////////////////////////////////// +// +// inline functions definitions +// +////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////// +// +// class IOBufferData -- +// inline functions definitions +// +////////////////////////////////////////////////////////////////// +TS_INLINE int64_t +IOBufferData::block_size() +{ + return index_to_buffer_size(_size_index); +} + +TS_INLINE IOBufferData * +new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + void *b, int64_t size, int64_t asize_index) +{ + (void) size; + IOBufferData *d = ioDataAllocator.alloc(); + d->_size_index = asize_index; + ink_assert(BUFFER_SIZE_INDEX_IS_CONSTANT(asize_index) + || size <= d->block_size()); +#ifdef TRACK_BUFFER_USER + d->_location = location; +#endif + d->_data = (char *) b; + return d; +} + +TS_INLINE IOBufferData * +new_constant_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *loc, +#endif + void *b, int64_t size) +{ + return new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + loc, +#endif + b, size, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(size)); +} + +TS_INLINE IOBufferData * +new_xmalloc_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + void *b, int64_t size) +{ + return new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + location, +#endif + b, size, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(size)); +} + +TS_INLINE IOBufferData * +new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + void *b, int64_t size) +{ + return new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + location, +#endif + b, size, iobuffer_size_to_index(size)); +} + +TS_INLINE IOBufferData * +new_IOBufferData_internal( +#ifdef TRACK_BUFFER_USER + const char *loc, +#endif + int64_t size_index, AllocType type) +{ + IOBufferData *d = ioDataAllocator.alloc(); +#ifdef TRACK_BUFFER_USER + d->_location = loc; +#endif + d->alloc(size_index, type); + return d; +} + +// IRIX has a compiler bug which prevents this function +// from being compiled correctly at -O3 +// so it is DUPLICATED in IOBuffer.cc +// ****** IF YOU CHANGE THIS FUNCTION change that one as well. +TS_INLINE void +IOBufferData::alloc(int64_t size_index, AllocType type) +{ + if (_data) + dealloc(); + _size_index = size_index; + _mem_type = type; +#ifdef TRACK_BUFFER_USER + iobuffer_mem_inc(_location, size_index); +#endif + switch (type) { + case MEMALIGNED: + if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index)) + _data = (char *) ioBufAllocator[size_index].alloc_void(); + // coverity[dead_error_condition] + else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index)) + // coverity[dead_error_line] + _data = (char *) valloc(index_to_buffer_size(size_index)); + break; + default: + case DEFAULT_ALLOC: + if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(size_index)) + _data = (char *) ioBufAllocator[size_index].alloc_void(); + else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(size_index)) + _data = (char *) xmalloc(BUFFER_SIZE_FOR_XMALLOC(size_index)); + break; + } +} + +// ****** IF YOU CHANGE THIS FUNCTION change that one as well. + + +TS_INLINE void +IOBufferData::dealloc() +{ +#ifdef TRACK_BUFFER_USER + iobuffer_mem_dec(_location, _size_index); +#endif + switch (_mem_type) { + case MEMALIGNED: + if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index)) + ioBufAllocator[_size_index].free_void(_data); + else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index)) + ::free((void *) _data); + break; + default: + case DEFAULT_ALLOC: + if (BUFFER_SIZE_INDEX_IS_FAST_ALLOCATED(_size_index)) + ioBufAllocator[_size_index].free_void(_data); + else if (BUFFER_SIZE_INDEX_IS_XMALLOCED(_size_index)) + xfree(_data); + break; + } + _data = 0; + _size_index = BUFFER_SIZE_NOT_ALLOCATED; + _mem_type = NO_ALLOC; +} + +TS_INLINE void +IOBufferData::free() +{ + dealloc(); + ioDataAllocator.free(this); +} + +////////////////////////////////////////////////////////////////// +// +// class IOBufferBlock -- +// inline functions definitions +// +////////////////////////////////////////////////////////////////// +TS_INLINE IOBufferBlock * +new_IOBufferBlock_internal( +#ifdef TRACK_BUFFER_USER + const char *location +#endif + ) +{ + IOBufferBlock *b = ioBlockAllocator.alloc(); +#ifdef TRACK_BUFFER_USER + b->_location = location; +#endif + return b; +} + +TS_INLINE IOBufferBlock * +new_IOBufferBlock_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + IOBufferData * d, int64_t len, int64_t offset) +{ + IOBufferBlock *b = ioBlockAllocator.alloc(); +#ifdef TRACK_BUFFER_USER + b->_location = location; +#endif + b->set(d, len, offset); + return b; +} + +TS_INLINE +IOBufferBlock::IOBufferBlock(): +_start(0), +_end(0), +_buf_end(0) +#ifdef TRACK_BUFFER_USER +, +_location(0) +#endif +{ + return; +} + +TS_INLINE void +IOBufferBlock::consume(int64_t len) +{ + _start += len; + ink_assert(_start <= _end); +} + +TS_INLINE void +IOBufferBlock::fill(int64_t len) +{ + _end += len; + ink_assert(_end <= _buf_end); +} + +TS_INLINE void +IOBufferBlock::reset() +{ + _end = _start = buf(); + _buf_end = buf() + data->block_size(); +} + +TS_INLINE void +IOBufferBlock::alloc(int64_t i) +{ + ink_debug_assert(BUFFER_SIZE_ALLOCATED(i)); +#ifdef TRACK_BUFFER_USER + data = new_IOBufferData_internal(_location, i); +#else + data = new_IOBufferData_internal(i); +#endif + reset(); +} + +TS_INLINE void +IOBufferBlock::clear() +{ + data = NULL; + IOBufferBlock *p = next; + while (p) { + int r = p->refcount_dec(); + if (r) + break; + else { + IOBufferBlock *n = p->next.m_ptr; + p->next.m_ptr = NULL; + p->free(); + p = n; + } + } + next.m_ptr = NULL; + _buf_end = _end = _start = NULL; +} + +TS_INLINE IOBufferBlock * +IOBufferBlock::clone() +{ +#ifdef TRACK_BUFFER_USER + IOBufferBlock *b = new_IOBufferBlock_internal(_location); +#else + IOBufferBlock *b = new_IOBufferBlock_internal(); +#endif + b->data = data; + b->_start = _start; + b->_end = _end; + b->_buf_end = _end; +#ifdef TRACK_BUFFER_USER + b->_location = _location; +#endif + return b; +} + +TS_INLINE void +IOBufferBlock::dealloc() +{ + clear(); +} + +TS_INLINE void +IOBufferBlock::free() +{ + dealloc(); + ioBlockAllocator.free(this); +} + +TS_INLINE void +IOBufferBlock::set_internal(void *b, int64_t len, int64_t asize_index) +{ +#ifdef TRACK_BUFFER_USER + data = new_IOBufferData_internal(_location, BUFFER_SIZE_NOT_ALLOCATED); +#else + data = new_IOBufferData_internal(BUFFER_SIZE_NOT_ALLOCATED); +#endif + data->_data = (char *) b; +#ifdef TRACK_BUFFER_USER + iobuffer_mem_inc(_location, asize_index); +#endif + data->_size_index = asize_index; + reset(); + _end = _start + len; +} + +TS_INLINE void +IOBufferBlock::set(IOBufferData * d, int64_t len, int64_t offset) +{ + data = d; + _start = buf() + offset; + _end = _start + len; + _buf_end = _start + d->block_size(); +} + +TS_INLINE void +IOBufferBlock::realloc_set_internal(void *b, int64_t buf_size, int64_t asize_index) +{ + int64_t data_size = size(); + memcpy(b, _start, size()); + dealloc(); + set_internal(b, buf_size, asize_index); + _end = _start + data_size; +} + +TS_INLINE void +IOBufferBlock::realloc(void *b, int64_t buf_size) +{ + realloc_set_internal(b, buf_size, BUFFER_SIZE_NOT_ALLOCATED); +} + +TS_INLINE void +IOBufferBlock::realloc_xmalloc(void *b, int64_t buf_size) +{ + realloc_set_internal(b, buf_size, -buf_size); +} + +TS_INLINE void +IOBufferBlock::realloc_xmalloc(int64_t buf_size) +{ + realloc_set_internal(xmalloc(buf_size), buf_size, -buf_size); +} + +TS_INLINE void +IOBufferBlock::realloc(int64_t i) +{ + if (i == data->_size_index) + return; + if (i >= (int64_t) sizeof(ioBufAllocator)) + return; + + ink_release_assert(i > data->_size_index && i != BUFFER_SIZE_NOT_ALLOCATED); + void *b = ioBufAllocator[i].alloc_void(); + realloc_set_internal(b, BUFFER_SIZE_FOR_INDEX(i), i); +} + +////////////////////////////////////////////////////////////////// +// +// class IOBufferReader -- +// inline functions definitions +// +////////////////////////////////////////////////////////////////// +TS_INLINE void +IOBufferReader::skip_empty_blocks() +{ + while (block->next && block->next->read_avail() && start_offset >= block->size()) { + start_offset -= block->size(); + block = block->next; + } +} + +TS_INLINE bool +IOBufferReader::low_water() +{ + return mbuf->low_water(); +} + +TS_INLINE bool +IOBufferReader::high_water() +{ + return read_avail() >= mbuf->water_mark; +} + +TS_INLINE bool +IOBufferReader::current_low_water() +{ + return mbuf->current_low_water(); +} + +TS_INLINE IOBufferBlock * +IOBufferReader::get_current_block() +{ + return block; +} + +TS_INLINE char * +IOBufferReader::start() +{ + if (block == 0) + return 0; + skip_empty_blocks(); + return block->start() + start_offset; +} + +TS_INLINE char * +IOBufferReader::end() +{ + if (block == 0) + return 0; + skip_empty_blocks(); + return block->end(); +} + +TS_INLINE int64_t +IOBufferReader::block_read_avail() +{ + if (block == 0) + return 0; + skip_empty_blocks(); + return (int64_t) (block->end() - (block->start() + start_offset)); +} + +TS_INLINE int +IOBufferReader::block_count() +{ + int count = 0; + IOBufferBlock *b = block; + + while (b) { + count++; + b = b->next; + } + return count; +} + +TS_INLINE int64_t +IOBufferReader::read_avail() +{ + int64_t t = 0; + IOBufferBlock *b = block; + + while (b) { + t += b->read_avail(); + b = b->next; + } + t -= start_offset; + if (size_limit != INT64_MAX && t > size_limit) + t = size_limit; + return t; +} + +TS_INLINE void +IOBufferReader::consume(int64_t n) +{ + start_offset += n; + if (size_limit != INT64_MAX) + size_limit -= n; + ink_assert(size_limit >= 0); + if (block == 0) + return; + int64_t r = block->read_avail(); + int64_t s = start_offset; + while (r <= s && block->next && block->next->read_avail()) { + s -= r; + start_offset = s; + block = block->next; + r = block->read_avail(); + } + ink_debug_assert(read_avail() >= 0); +} + +TS_INLINE char & +IOBufferReader::operator[] (int64_t i) +{ + static char + _error = '\0'; + + IOBufferBlock * + b = block; + i += start_offset; + while (b) { + int64_t bytes = b->read_avail(); + if (bytes > i) + return b->start()[i]; + i -= bytes; + b = b->next; + } + + ink_assert(!"out of range"); + if (unlikely(b)) + return *b->start(); + + return _error; +} + +TS_INLINE void +IOBufferReader::clear() +{ + accessor = NULL; + block = NULL; + mbuf = NULL; + start_offset = 0; + size_limit = INT64_MAX; +} + +TS_INLINE void +IOBufferReader::reset() +{ + block = mbuf->_writer; + start_offset = 0; + size_limit = INT64_MAX; +} + +//////////////////////////////////////////////////////////////// +// +// class MIOBuffer -- +// inline functions definitions +// +//////////////////////////////////////////////////////////////// +inkcoreapi extern ClassAllocator ioAllocator; +//////////////////////////////////////////////////////////////// +// +// MIOBuffer::MIOBuffer() +// +// This constructor accepts a pre-allocated memory buffer, +// wraps if in a IOBufferData and IOBufferBlock structures +// and sets it as the current block. +// NOTE that in this case the memory buffer will not be freed +// by the MIOBuffer class. It is the user responsibility to +// free the memory buffer. The wrappers (MIOBufferBlock and +// MIOBufferData) will be freed by this class. +// +//////////////////////////////////////////////////////////////// +TS_INLINE +MIOBuffer::MIOBuffer(void *b, int64_t bufsize, int64_t aWater_mark) +{ + set(b, bufsize); + water_mark = aWater_mark; + size_index = BUFFER_SIZE_NOT_ALLOCATED; +#ifdef TRACK_BUFFER_USER + _location = NULL; +#endif + return; +} + +TS_INLINE +MIOBuffer::MIOBuffer(int64_t default_size_index) +{ + clear(); + size_index = default_size_index; +#ifdef TRACK_BUFFER_USER + _location = NULL; +#endif + return; +} + +TS_INLINE +MIOBuffer::MIOBuffer() +{ + clear(); +#ifdef TRACK_BUFFER_USER + _location = NULL; +#endif + return; +} + +TS_INLINE +MIOBuffer::~ +MIOBuffer() +{ + _writer = NULL; + dealloc_all_readers(); +} + +TS_INLINE MIOBuffer * new_MIOBuffer_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + int64_t size_index) +{ + MIOBuffer *b = ioAllocator.alloc(); +#ifdef TRACK_BUFFER_USER + b->_location = location; +#endif + b->alloc(size_index); + return b; +} + +TS_INLINE void +free_MIOBuffer(MIOBuffer * mio) +{ + mio->_writer = NULL; + mio->dealloc_all_readers(); + ioAllocator.free(mio); +} + +TS_INLINE MIOBuffer * new_empty_MIOBuffer_internal( +#ifdef TRACK_BUFFER_USER + const char *location, +#endif + int64_t size_index) +{ + MIOBuffer *b = ioAllocator.alloc(); + b->size_index = size_index; +#ifdef TRACK_BUFFER_USER + b->_location = location; +#endif + return b; +} + +TS_INLINE void +free_empty_MIOBuffer(MIOBuffer * mio) +{ + ioAllocator.free(mio); +} + +TS_INLINE IOBufferReader * +MIOBuffer::alloc_accessor(MIOBufferAccessor * anAccessor) +{ + int i; + for (i = 0; i < MAX_MIOBUFFER_READERS; i++) + if (!readers[i].allocated()) + break; + + // TODO refactor code to return NULL at some point + ink_release_assert(i < MAX_MIOBUFFER_READERS); + + IOBufferReader *e = &readers[i]; + e->mbuf = this; + e->reset(); + e->accessor = anAccessor; + + return e; +} + +TS_INLINE IOBufferReader * +MIOBuffer::alloc_reader() +{ + int i; + for (i = 0; i < MAX_MIOBUFFER_READERS; i++) + if (!readers[i].allocated()) + break; + + // TODO refactor code to return NULL at some point + ink_release_assert(i < MAX_MIOBUFFER_READERS); + + IOBufferReader *e = &readers[i]; + e->mbuf = this; + e->reset(); + e->accessor = NULL; + + return e; +} + +TS_INLINE int64_t +MIOBuffer::block_size() +{ + return index_to_buffer_size(size_index); +} +TS_INLINE IOBufferReader * +MIOBuffer::clone_reader(IOBufferReader * r) +{ + int i; + for (i = 0; i < MAX_MIOBUFFER_READERS; i++) + if (!readers[i].allocated()) + break; + + // TODO refactor code to return NULL at some point + ink_release_assert(i < MAX_MIOBUFFER_READERS); + + IOBufferReader *e = &readers[i]; + e->mbuf = this; + e->accessor = NULL; + e->block = r->block; + e->start_offset = r->start_offset; + e->size_limit = r->size_limit; + ink_assert(e->size_limit >= 0); + + return e; +} + +TS_INLINE int64_t +MIOBuffer::block_write_avail() +{ + IOBufferBlock *b = first_write_block(); + return b ? b->write_avail() : 0; +} + +//////////////////////////////////////////////////////////////// +// +// MIOBuffer::append_block() +// +// Appends a block to writer->next and make it the current +// block. +// Note that the block is not appended to the end of the list. +// That means that if writer->next was not null before this +// call then the block that writer->next was pointing to will +// have its reference count decremented and writer->next +// will have a new value which is the new block. +// In any case the new appended block becomes the current +// block. +// +//////////////////////////////////////////////////////////////// +TS_INLINE void +MIOBuffer::append_block_internal(IOBufferBlock * b) +{ + // It would be nice to remove an empty buffer at the beginning, + // but this breaks HTTP. + // if (!_writer || !_writer->read_avail()) + if (!_writer) { + _writer = b; + init_readers(); + } else { + ink_assert(!_writer->next || !_writer->next->read_avail()); + _writer->next = b; + while (b->read_avail()) { + _writer = b; + b = b->next; + if (!b) + break; + } + } + while (_writer->next && !_writer->write_avail() && _writer->next->read_avail()) + _writer = _writer->next; +} + +TS_INLINE void +MIOBuffer::append_block(IOBufferBlock * b) +{ + ink_assert(b->read_avail()); + append_block_internal(b); +} + +//////////////////////////////////////////////////////////////// +// +// MIOBuffer::append_block() +// +// Allocate a block, appends it to current->next +// and make the new block the current block (writer). +// +//////////////////////////////////////////////////////////////// +TS_INLINE void +MIOBuffer::append_block(int64_t asize_index) +{ + ink_debug_assert(BUFFER_SIZE_ALLOCATED(asize_index)); +#ifdef TRACK_BUFFER_USER + IOBufferBlock *b = new_IOBufferBlock_internal(_location); +#else + IOBufferBlock *b = new_IOBufferBlock_internal(); +#endif + b->alloc(asize_index); + append_block_internal(b); + return; +} + +TS_INLINE void +MIOBuffer::add_block() +{ + append_block(size_index); +} + +TS_INLINE void +MIOBuffer::check_add_block() +{ + if (!high_water() && current_low_water()) + add_block(); +} + +TS_INLINE IOBufferBlock * +MIOBuffer::get_current_block() +{ + return first_write_block(); +} + +////////////////////////////////////////////////////////////////// +// +// MIOBuffer::current_write_avail() +// +// returns the total space available in all blocks. +// This function is different than write_avail() because +// it will not append a new block if there is no space +// or below the watermark space available. +// +////////////////////////////////////////////////////////////////// +TS_INLINE int64_t +MIOBuffer::current_write_avail() +{ + int64_t t = 0; + IOBufferBlock *b = _writer; + while (b) { + t += b->write_avail(); + b = b->next; + } + return t; +} + +////////////////////////////////////////////////////////////////// +// +// MIOBuffer::write_avail() +// +// returns the number of bytes available in the current block. +// If there is no current block or not enough free space in +// the current block then a new block is appended. +// +////////////////////////////////////////////////////////////////// +TS_INLINE int64_t +MIOBuffer::write_avail() +{ + check_add_block(); + return current_write_avail(); +} + +TS_INLINE void +MIOBuffer::fill(int64_t len) +{ + int64_t f = _writer->write_avail(); + while (f < len) { + _writer->fill(f); + len -= f; + if (len > 0) + _writer = _writer->next; + f = _writer->write_avail(); + } + _writer->fill(len); +} + +TS_INLINE int +MIOBuffer::max_block_count() +{ + int maxb = 0; + for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) { + if (readers[i].allocated()) { + int c = readers[i].block_count(); + if (c > maxb) { + maxb = c; + } + } + } + return maxb; +} + +TS_INLINE int64_t +MIOBuffer::max_read_avail() +{ + int64_t s = 0; + int found = 0; + for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) { + if (readers[i].allocated()) { + int64_t ss = readers[i].read_avail(); + if (ss > s) { + s = ss; + } + found = 1; + } + } + if (!found && _writer) + return _writer->read_avail(); + return s; +} + +TS_INLINE void +MIOBuffer::set(void *b, int64_t len) +{ +#ifdef TRACK_BUFFER_USER + _writer = new_IOBufferBlock_internal(_location); +#else + _writer = new_IOBufferBlock_internal(); +#endif + _writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_CONSTANT_SIZE(len)); + init_readers(); +} + +TS_INLINE void +MIOBuffer::set_xmalloced(void *b, int64_t len) +{ +#ifdef TRACK_BUFFER_USER + _writer = new_IOBufferBlock_internal(_location); +#else + _writer = new_IOBufferBlock_internal(); +#endif + _writer->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len)); + init_readers(); +} + +TS_INLINE void +MIOBuffer::append_xmalloced(void *b, int64_t len) +{ +#ifdef TRACK_BUFFER_USER + IOBufferBlock *x = new_IOBufferBlock_internal(_location); +#else + IOBufferBlock *x = new_IOBufferBlock_internal(); +#endif + x->set_internal(b, len, BUFFER_SIZE_INDEX_FOR_XMALLOC_SIZE(len)); + append_block_internal(x); +} + +TS_INLINE void +MIOBuffer::append_fast_allocated(void *b, int64_t len, int64_t fast_size_index) +{ +#ifdef TRACK_BUFFER_USER + IOBufferBlock *x = new_IOBufferBlock_internal(_location); +#else + IOBufferBlock *x = new_IOBufferBlock_internal(); +#endif + x->set_internal(b, len, fast_size_index); + append_block_internal(x); +} + +TS_INLINE void +MIOBuffer::alloc(int64_t i) +{ +#ifdef TRACK_BUFFER_USER + _writer = new_IOBufferBlock_internal(_location); +#else + _writer = new_IOBufferBlock_internal(); +#endif + _writer->alloc(i); + size_index = i; + init_readers(); +} + +TS_INLINE void +MIOBuffer::alloc_xmalloc(int64_t buf_size) +{ + char *b = (char *) xmalloc(buf_size); + set_xmalloced(b, buf_size); +} + +TS_INLINE void +MIOBuffer::dealloc_reader(IOBufferReader * e) +{ + if (e->accessor) { + ink_assert(e->accessor->mbuf == this); + ink_assert(e->accessor->entry == e); + e->accessor->reset(); + } + e->clear(); +} + +TS_INLINE IOBufferReader * +IOBufferReader::clone() +{ + return mbuf->clone_reader(this); +} + +TS_INLINE void +IOBufferReader::dealloc() +{ + mbuf->dealloc_reader(this); +} + +TS_INLINE void +MIOBuffer::dealloc_all_readers() +{ + for (int i = 0; i < MAX_MIOBUFFER_READERS; i++) + if (readers[i].allocated()) + dealloc_reader(&readers[i]); +} + +TS_INLINE void +MIOBuffer::set_size_index(int64_t size) +{ + size_index = iobuffer_size_to_index(size); +} + +TS_INLINE void +MIOBufferAccessor::reader_for(MIOBuffer * abuf) +{ + mbuf = abuf; + if (abuf) + entry = mbuf->alloc_accessor(this); + else + entry = NULL; +} + +TS_INLINE void +MIOBufferAccessor::reader_for(IOBufferReader * areader) +{ + if (entry == areader) + return; + mbuf = areader->mbuf; + entry = areader; + ink_assert(mbuf); +} + +TS_INLINE void +MIOBufferAccessor::writer_for(MIOBuffer * abuf) +{ + mbuf = abuf; + entry = NULL; +} + +TS_INLINE void +MIOBufferAccessor::clear() +{ + entry = NULL; + mbuf = NULL; +} + +TS_INLINE +MIOBufferAccessor::~ +MIOBufferAccessor() +{ +} + +#endif diff --git a/iocore/eventsystem/P_ProtectedQueue.h b/iocore/eventsystem/P_ProtectedQueue.h new file mode 100644 index 00000000..aa6720bd --- /dev/null +++ b/iocore/eventsystem/P_ProtectedQueue.h @@ -0,0 +1,96 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Protected Queue + + + ****************************************************************************/ +#ifndef _P_ProtectedQueue_h_ +#define _P_ProtectedQueue_h_ + +#include "I_EventSystem.h" + + +TS_INLINE +ProtectedQueue::ProtectedQueue() +{ + Event e; + ink_mutex_init(&lock, "ProtectedQueue"); + ink_atomiclist_init(&al, "ProtectedQueue", (char *) &e.link.next - (char *) &e); + ink_cond_init(&might_have_data); +} + +TS_INLINE void +ProtectedQueue::signal() +{ + // Need to get the lock before you can signal the thread + ink_mutex_acquire(&lock); + ink_cond_signal(&might_have_data); + ink_mutex_release(&lock); +} + +TS_INLINE int +ProtectedQueue::try_signal() +{ + // Need to get the lock before you can signal the thread + if (ink_mutex_try_acquire(&lock)) { + ink_cond_signal(&might_have_data); + ink_mutex_release(&lock); + return 1; + } else { + return 0; + } +} + +// Called from the same thread (don't need to signal) +TS_INLINE void +ProtectedQueue::enqueue_local(Event * e) +{ + ink_assert(!e->in_the_prot_queue && !e->in_the_priority_queue); + e->in_the_prot_queue = 1; + localQueue.enqueue(e); +} + +TS_INLINE void +ProtectedQueue::remove(Event * e) +{ + ink_assert(e->in_the_prot_queue); + if (!ink_atomiclist_remove(&al, e)) + localQueue.remove(e); + e->in_the_prot_queue = 0; +} + +TS_INLINE Event * +ProtectedQueue::dequeue_local() +{ + Event *e = localQueue.dequeue(); + if (e) { + ink_assert(e->in_the_prot_queue); + e->in_the_prot_queue = 0; + } + return e; +} + +#endif diff --git a/iocore/eventsystem/P_Thread.h b/iocore/eventsystem/P_Thread.h new file mode 100644 index 00000000..780fcfe6 --- /dev/null +++ b/iocore/eventsystem/P_Thread.h @@ -0,0 +1,69 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Basic Threads + + + +****************************************************************************/ +#ifndef _P_Thread_h_ +#define _P_Thread_h_ + +#include "I_Thread.h" + + /////////////////////////////////////////////// + // Common Interface impl // + /////////////////////////////////////////////// +TS_INLINE +Thread::~ +Thread() +{ +} + +TS_INLINE void +Thread::set_specific() +{ + ink_thread_setspecific(Thread::thread_data_key, this); +} + +TS_INLINE Thread * +this_thread() +{ + return (Thread *) ink_thread_getspecific(Thread::thread_data_key); +} + +TS_INLINE ink_hrtime +ink_get_hrtime() +{ + return Thread::cur_time; +} + +TS_INLINE ink_hrtime +ink_get_based_hrtime() +{ + return Thread::cur_time; +} + +#endif //_P_Thread_h_ diff --git a/iocore/eventsystem/P_UnixEThread.h b/iocore/eventsystem/P_UnixEThread.h new file mode 100644 index 00000000..c5691342 --- /dev/null +++ b/iocore/eventsystem/P_UnixEThread.h @@ -0,0 +1,182 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_UnixEThread.h + + + +*****************************************************************************/ +#ifndef _P_UnixEThread_h_ +#define _P_UnixEThread_h_ + +#include "I_EThread.h" +#include "I_ProxyAllocator.h" +#include "I_EventProcessor.h" + +const int DELAY_FOR_RETRY = HRTIME_MSECONDS(10); + +TS_INLINE Event * +EThread::schedule_spawn(Continuation * cont) +{ + Event *e = EVENT_ALLOC(eventAllocator, this); + return schedule(e->init(cont, 0, 0)); +} + +TS_INLINE Event * +EThread::schedule_imm(Continuation * cont, int callback_event, void *cookie) +{ + Event *e =::eventAllocator.alloc(); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, 0, 0)); +} + +TS_INLINE Event * +EThread::schedule_imm_signal(Continuation * cont, int callback_event, void *cookie) +{ + Event *e =::eventAllocator.alloc(); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, 0, 0), true); +} + +TS_INLINE Event * +EThread::schedule_at(Continuation * cont, ink_hrtime t, int callback_event, void *cookie) +{ + Event *e =::eventAllocator.alloc(); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, t, 0)); +} + +TS_INLINE Event * +EThread::schedule_in(Continuation * cont, ink_hrtime t, int callback_event, void *cookie) +{ + Event *e =::eventAllocator.alloc(); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, ink_get_based_hrtime() + t, 0)); +} + +TS_INLINE Event * +EThread::schedule_every(Continuation * cont, ink_hrtime t, int callback_event, void *cookie) +{ + Event *e =::eventAllocator.alloc(); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, ink_get_based_hrtime() + t, t)); +} + +TS_INLINE Event * +EThread::schedule(Event * e, bool fast_signal) +{ + e->ethread = this; + ink_assert(tt == REGULAR); + if (e->continuation->mutex) + e->mutex = e->continuation->mutex; + else + e->mutex = e->continuation->mutex = e->ethread->mutex; + ink_assert(e->mutex.m_ptr); + EventQueueExternal.enqueue(e, fast_signal); + return e; +} + +TS_INLINE Event * +EThread::schedule_imm_local(Continuation * cont, int callback_event, void *cookie) +{ + Event *e = EVENT_ALLOC(eventAllocator, this); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule_local(e->init(cont, 0, 0)); +} + +TS_INLINE Event * +EThread::schedule_at_local(Continuation * cont, ink_hrtime t, int callback_event, void *cookie) +{ + Event *e = EVENT_ALLOC(eventAllocator, this); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule_local(e->init(cont, t, 0)); +} + +TS_INLINE Event * +EThread::schedule_in_local(Continuation * cont, ink_hrtime t, int callback_event, void *cookie) +{ + Event *e = EVENT_ALLOC(eventAllocator, this); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule_local(e->init(cont, ink_get_based_hrtime() + t, 0)); +} + +TS_INLINE Event * +EThread::schedule_every_local(Continuation * cont, ink_hrtime t, int callback_event, void *cookie) +{ + Event *e = EVENT_ALLOC(eventAllocator, this); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule_local(e->init(cont, ink_get_based_hrtime() + t, t)); +} + +TS_INLINE Event * +EThread::schedule_local(Event * e) +{ + if (tt != REGULAR) { + ink_debug_assert(tt == DEDICATED); + return eventProcessor.schedule(e, ET_CALL); + } + if (!e->mutex.m_ptr) { + e->ethread = this; + e->mutex = e->continuation->mutex; + } else { + ink_assert(e->ethread == this); + } + e->globally_allocated = false; + EventQueueExternal.enqueue_local(e); + return e; +} + +TS_INLINE EThread * +this_ethread() +{ + return (EThread *) this_thread(); +} + +TS_INLINE void +EThread::free_event(Event * e) +{ + ink_assert(!e->in_the_priority_queue && !e->in_the_prot_queue); + e->mutex = NULL; + EVENT_FREE(e, eventAllocator, this); +} + +#if defined(USE_OLD_EVENTFD) +TS_INLINE int +EThread::getEventFd() +{ + return EventQueueExternal.getReadFd(); +} +#endif + +#endif /*_EThread_h_*/ diff --git a/iocore/eventsystem/P_UnixEvent.h b/iocore/eventsystem/P_UnixEvent.h new file mode 100644 index 00000000..54469a9b --- /dev/null +++ b/iocore/eventsystem/P_UnixEvent.h @@ -0,0 +1,58 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_UnixEvent_h_ +#define _P_UnixEvent_h_ + +TS_INLINE Event * +Event::init(Continuation * c, ink_hrtime atimeout_at, ink_hrtime aperiod) +{ + continuation = c; + timeout_at = atimeout_at; + period = aperiod; + immediate = !period && !atimeout_at; + cancelled = false; + return this; +} + +TS_INLINE void +Event::free() +{ + mutex = NULL; + eventAllocator.free(this); +} + +TS_INLINE +Event::Event(): + ethread(0), + in_the_prot_queue(false), + in_the_priority_queue(false), + immediate(false), + globally_allocated(true), + in_heap(false), + timeout_at(0), + period(0) +{ +} + +#endif /*_UnixEvent_h_*/ diff --git a/iocore/eventsystem/P_UnixEventProcessor.h b/iocore/eventsystem/P_UnixEventProcessor.h new file mode 100644 index 00000000..0c89f7cf --- /dev/null +++ b/iocore/eventsystem/P_UnixEventProcessor.h @@ -0,0 +1,155 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_UnixEventProcessor_h_ +#define _P_UnixEventProcessor_h_ +#include "I_EventProcessor.h" + +const int LOAD_BALANCE_INTERVAL = 1; + + +TS_INLINE +EventProcessor::EventProcessor(): +n_ethreads(0), +n_thread_groups(0), +n_dthreads(0), +thread_data_used(0) +{ + memset(all_ethreads, 0, sizeof(all_ethreads)); + memset(dthreads, 0, sizeof(dthreads)); + memset(n_threads_for_type, 0, sizeof(n_threads_for_type)); + memset(next_thread_for_type, 0, sizeof(next_thread_for_type)); +} + +TS_INLINE off_t +EventProcessor::allocate(int size) +{ + static off_t start = (offsetof(EThread, thread_private) + 7) & ~7; + static off_t loss = start - offsetof(EThread, thread_private); + size = (size + 7) & ~7; // 8 byte alignment + + int old; + do { + old = thread_data_used; + if (old + loss + size > PER_THREAD_DATA) + return -1; + } while (!ink_atomic_cas(&thread_data_used, old, old + size)); + + return (off_t) (old + start); +} + +TS_INLINE EThread * +EventProcessor::assign_thread(EventType etype) +{ + int next; + + ink_assert(etype < MAX_EVENT_TYPES); + if (n_threads_for_type[etype] > 1) + next = next_thread_for_type[etype]++ % n_threads_for_type[etype]; + else + next = 0; + return (eventthread[etype][next]); +} + +TS_INLINE Event * +EventProcessor::schedule(Event * e, EventType etype, bool fast_signal) +{ + ink_assert(etype < MAX_EVENT_TYPES); + e->ethread = assign_thread(etype); + if (e->continuation->mutex) + e->mutex = e->continuation->mutex; + else + e->mutex = e->continuation->mutex = e->ethread->mutex; + e->ethread->EventQueueExternal.enqueue(e, fast_signal); + return e; +} + + +TS_INLINE Event * +EventProcessor::schedule_imm_signal(Continuation * cont, EventType et, int callback_event, void *cookie) +{ + Event *e = eventAllocator.alloc(); + + ink_assert(et < MAX_EVENT_TYPES); +#ifdef ENABLE_TIME_TRACE + e->start_time = ink_get_hrtime(); +#endif + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, 0, 0), et, true); +} + +TS_INLINE Event * +EventProcessor::schedule_imm(Continuation * cont, EventType et, int callback_event, void *cookie) +{ + Event *e = eventAllocator.alloc(); + + ink_assert(et < MAX_EVENT_TYPES); +#ifdef ENABLE_TIME_TRACE + e->start_time = ink_get_hrtime(); +#endif + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, 0, 0), et); +} + +TS_INLINE Event * +EventProcessor::schedule_at(Continuation * cont, ink_hrtime t, EventType et, int callback_event, void *cookie) +{ + Event *e = eventAllocator.alloc(); + + ink_assert(t > 0); + ink_assert(et < MAX_EVENT_TYPES); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, t, 0), et); +} + +TS_INLINE Event * +EventProcessor::schedule_in(Continuation * cont, ink_hrtime t, EventType et, int callback_event, void *cookie) +{ + Event *e = eventAllocator.alloc(); + + ink_assert(et < MAX_EVENT_TYPES); + e->callback_event = callback_event; + e->cookie = cookie; + return schedule(e->init(cont, ink_get_based_hrtime() + t, 0), et); +} + +TS_INLINE Event * +EventProcessor::schedule_every(Continuation * cont, ink_hrtime t, EventType et, int callback_event, void *cookie) +{ + Event *e = eventAllocator.alloc(); + + ink_assert(t != 0); + ink_assert(et < MAX_EVENT_TYPES); + e->callback_event = callback_event; + e->cookie = cookie; + if (t < 0) + return schedule(e->init(cont, t, t), et); + else + return schedule(e->init(cont, ink_get_based_hrtime() + t, t), et); +} + + +#endif diff --git a/iocore/eventsystem/P_UnixSocketManager.h b/iocore/eventsystem/P_UnixSocketManager.h new file mode 100644 index 00000000..b23a1d85 --- /dev/null +++ b/iocore/eventsystem/P_UnixSocketManager.h @@ -0,0 +1,582 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + UnixSocketManager.h + + Handle the allocation of the socket descriptor (fd) resource. + + +****************************************************************************/ +#ifndef _P_UnixSocketManager_h_ +#define _P_UnixSocketManager_h_ + +#include "libts.h" +#include "I_SocketManager.h" + + +// +// These limits are currently disabled +// +// 1024 - stdin, stderr, stdout +#define EPOLL_MAX_DESCRIPTOR_SIZE 32768 + +TS_INLINE bool +transient_error() +{ + bool transient = (errno == EINTR); +#ifdef ENOMEM + transient = transient || (errno == ENOMEM); +#endif +#ifdef ENOBUFS + transient = transient || (errno == ENOBUFS); +#endif + return transient; +} + + +// +// Timing done in the connectionManager +// +TS_INLINE int +SocketManager::accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int r; + do { + r =::accept(s, addr, addrlen); + if (likely(r >= 0)) + break; + r = -errno; + } while (transient_error()); + + return r; +} + +TS_INLINE int +SocketManager::open(const char *path, int oflag, mode_t mode) +{ + int s; + do { + s =::open(path, oflag, mode); + if (likely(s >= 0)) + break; + s = -errno; + } while (transient_error()); + return s; +} + +TS_INLINE int64_t +SocketManager::read(int fd, void *buf, int size, void *pOLP) +{ + NOWARN_UNUSED(pOLP); + int64_t r; + do { + r =::read(fd, buf, size); + if (likely(r >= 0)) + break; + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int64_t +SocketManager::pread(int fd, void *buf, int size, off_t offset, char *tag) +{ + NOWARN_UNUSED(tag); + int64_t r; + do { + r =::pread(fd, buf, size, offset); + if (r < 0) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int64_t +SocketManager::readv(int fd, struct iovec *vector, size_t count) +{ + int64_t r; + do { + // coverity[tainted_data_argument] + if (likely((r =::readv(fd, vector, count)) >= 0)) + break; + r = -errno; + } while (transient_error()); + return r; +} + +TS_INLINE int64_t +SocketManager::vector_io(int fd, struct iovec *vector, size_t count, int read_request, void *pOLP) +{ + NOWARN_UNUSED(pOLP); + const int max_iovecs_per_request = 16; + int n; + int64_t r = 0; + int n_vec; + int64_t bytes_xfered = 0; + int current_count; + int64_t current_request_bytes; + + for (n_vec = 0; n_vec < (int) count; n_vec += max_iovecs_per_request) { + current_count = min(max_iovecs_per_request, ((int) (count - n_vec))); + do { + // coverity[tainted_data_argument] + r = read_request ? ::readv(fd, &vector[n_vec], current_count) : ::writev(fd, &vector[n_vec], current_count); + if (likely(r >= 0)) + break; + r = -errno; + } while (transient_error()); + + if (r <= 0) { + return (bytes_xfered && (r == -EAGAIN)) ? bytes_xfered : r; + } + bytes_xfered += r; + + if ((n_vec + max_iovecs_per_request) >= (int) count) + break; + + // Compute bytes in current vector + current_request_bytes = 0; + for (n = n_vec; n < (n_vec + current_count); ++n) + current_request_bytes += vector[n].iov_len; + + // Exit if we were unable to read all data in the current vector + if (r != current_request_bytes) + break; + } + return bytes_xfered; +} + +TS_INLINE int64_t +SocketManager::read_vector(int fd, struct iovec *vector, size_t count, void *pOLP) +{ + return vector_io(fd, vector, count, 1, pOLP); +} + +TS_INLINE int +SocketManager::recv(int fd, void *buf, int size, int flags) +{ + int r; + do { + if (unlikely((r =::recv(fd, (char *) buf, size, flags)) < 0)) { + r = -errno; + } + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::recvfrom(int fd, void *buf, int size, int flags, struct sockaddr *addr, socklen_t *addrlen) +{ + int r; + do { + r =::recvfrom(fd, (char *) buf, size, flags, addr, addrlen); + if (unlikely(r < 0)) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int64_t +SocketManager::write(int fd, void *buf, int size, void *pOLP) +{ + NOWARN_UNUSED(pOLP); + int64_t r; + do { + if (likely((r =::write(fd, buf, size)) >= 0)) + break; + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int64_t +SocketManager::pwrite(int fd, void *buf, int size, off_t offset, char *tag) +{ + NOWARN_UNUSED(tag); + int64_t r; + do { + if (unlikely((r =::pwrite(fd, buf, size, offset)) < 0)) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int64_t +SocketManager::writev(int fd, struct iovec *vector, size_t count) +{ + int64_t r; + do { + if (likely((r =::writev(fd, vector, count)) >= 0)) + break; + r = -errno; + } while (transient_error()); + return r; +} + +TS_INLINE int64_t +SocketManager::write_vector(int fd, struct iovec *vector, size_t count, void *pOLP) +{ + return vector_io(fd, vector, count, 0, pOLP); +} + + +TS_INLINE int +SocketManager::send(int fd, void *buf, int size, int flags) +{ + int r; + do { + if (unlikely((r =::send(fd, (char *) buf, size, flags)) < 0)) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::sendto(int fd, void *buf, int len, int flags, struct sockaddr *to, int tolen) +{ + int r; + do { + if (unlikely((r =::sendto(fd, (char *) buf, len, flags, to, tolen)) < 0)) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::sendmsg(int fd, struct msghdr *m, int flags, void *pOLP) +{ + NOWARN_UNUSED(pOLP); + int r; + do { + if (unlikely((r =::sendmsg(fd, m, flags)) < 0)) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int64_t +SocketManager::lseek(int fd, off_t offset, int whence) +{ + int64_t r; + do { + if ((r =::lseek(fd, offset, whence)) < 0) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::fstat(int fd, struct stat *buf) +{ + int r; + do { + if ((r =::fstat(fd, buf)) >= 0) + break; + r = -errno; + } while (transient_error()); + return r; +} + +TS_INLINE int +SocketManager::unlink(char *buf) +{ + int r; + do { + if ((r =::unlink(buf)) < 0) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::fsync(int fildes) +{ + int r; + do { + if ((r =::fsync(fildes)) < 0) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::ftruncate(int fildes, off_t length) +{ + int r; + do { + if ((r =::ftruncate(fildes, length)) < 0) + r = -errno; + } while (r == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::poll(struct pollfd *fds, unsigned long nfds, int timeout) +{ + int r; + do { + if ((r =::poll(fds, nfds, timeout)) >= 0) + break; + r = -errno; + } while (transient_error()); + return r; +} + +#if TS_USE_EPOLL +TS_INLINE int +SocketManager::epoll_create(int size) +{ + int r; + if (size <= 0) + size = EPOLL_MAX_DESCRIPTOR_SIZE; + do { + if (likely((r =::epoll_create(size)) >= 0)) + break; + r = -errno; + } while (errno == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::epoll_close(int epfd) +{ + int r = 0; + if (likely(epfd >= 0)) { + do { + if (likely((r =::close(epfd)) == 0)) + break; + r = -errno; + } while (errno == -EINTR); + } + return r; +} + +TS_INLINE int +SocketManager::epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + int r; + do { + if (likely((r =::epoll_ctl(epfd, op, fd, event)) == 0)) + break; + r = -errno; + } while (errno == -EINTR); + return r; +} + +TS_INLINE int +SocketManager::epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) +{ + int r; + do { + if ((r =::epoll_wait(epfd, events, maxevents, timeout)) >= 0) + break; + r = -errno; + } while (errno == -EINTR); + return r; +} + +#endif /* TS_USE_EPOLL */ + +#if TS_USE_KQUEUE +TS_INLINE int +SocketManager::kqueue() +{ + return ::kqueue(); +} + +TS_INLINE int +SocketManager::kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, + const struct timespec *timeout) +{ + int r; + do { + r =::kevent(kq, changelist, nchanges, + eventlist, nevents, timeout); + if (likely(r >= 0)) { + break; + } + r = -errno; + } while (errno == -EINTR); + return r; +} +#endif /* TS_USE_KQUEUE */ + +#if TS_USE_PORT +TS_INLINE int +SocketManager::port_create() +{ + return ::port_create(); +} + +TS_INLINE int +SocketManager::port_associate(int port, int source, uintptr_t obj, + int events, void *user) +{ + int r; + r =::port_associate(port, source, obj, events, user); + if(r < 0) + r = -errno; + return r; +} + +TS_INLINE int +SocketManager::port_dissociate(int port, int source, uintptr_t obj) +{ + int r; + r =::port_dissociate(port, source, obj); + if(r < 0) + r = -errno; + return r; +} + +TS_INLINE int +SocketManager::port_getn(int port, port_event_t *list, uint_t max, + uint_t *nget, timespec_t *timeout) +{ + int r; + do { + if ((r =::port_getn(port, list, max, nget, timeout)) >= 0) + break; + r = -errno; + } while (errno == -EINTR); //TODO: possible EAGAIN(undocumented) + return r; +} +#endif /* TS_USE_PORT */ + + +TS_INLINE int +SocketManager::get_sndbuf_size(int s) +{ + int bsz = 0; + int bszsz, r; + + bszsz = sizeof(bsz); + r = safe_getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &bsz, &bszsz); + return (r == 0 ? bsz : r); +} + +TS_INLINE int +SocketManager::get_rcvbuf_size(int s) +{ + int bsz = 0; + int bszsz, r; + + bszsz = sizeof(bsz); + r = safe_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &bsz, &bszsz); + return (r == 0 ? bsz : r); +} + +TS_INLINE int +SocketManager::set_sndbuf_size(int s, int bsz) +{ + return safe_setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &bsz, sizeof(bsz)); +} + +TS_INLINE int +SocketManager::set_rcvbuf_size(int s, int bsz) +{ + return safe_setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &bsz, sizeof(bsz)); +} + +TS_INLINE int +SocketManager::getsockname(int s, struct sockaddr *sa, socklen_t *sz) +{ + return::getsockname(s, sa, sz); +} + +TS_INLINE int +SocketManager::socket(int domain, int type, int protocol, bool bNonBlocking) +{ + NOWARN_UNUSED(bNonBlocking); + return::socket(domain, type, protocol); +} + +TS_INLINE int +SocketManager::mc_socket(int domain, int type, int protocol, bool bNonBlocking) +{ + return SocketManager::socket(domain, type, protocol, bNonBlocking); +} + +TS_INLINE int +SocketManager::shutdown(int s, int how) +{ + int res; + do { + if (unlikely((res =::shutdown(s, how)) < 0)) + res = -errno; + } while (res == -EINTR); + return res; +} + +TS_INLINE int +SocketManager::lockf(int s, int f, off_t size) +{ + int res; + do { + if ((res =::lockf(s, f, size)) < 0) + res = -errno; + } while (res == -EINTR); + return res; +} + +TS_INLINE int +SocketManager::dup(int s) +{ + int res; + do { + if ((res =::dup(s)) >= 0) + break; + res = -errno; + } while (res == -EINTR); + return res; +} + +int safe_msync(caddr_t addr, size_t len, caddr_t end, int flags); + +#ifndef MADV_NORMAL +#define MADV_NORMAL 0 +#endif + +#ifndef MADV_RANDOM +#define MADV_RANDOM 1 +#endif + +#ifndef MADV_SEQUENTIAL +#define MADV_SEQUENTIAL 2 +#endif + +#ifndef MADV_WILLNEED +#define MADV_WILLNEED 3 +#endif + +#ifndef MADV_DONTNEED +#define MADV_DONTNEED 4 +#endif + +int safe_madvise(caddr_t addr, size_t len, caddr_t end, int flags); +int safe_mlock(caddr_t addr, size_t len, caddr_t end); + +#endif /*P_UnixSocketManager_h_ */ diff --git a/iocore/eventsystem/P_VConnection.h b/iocore/eventsystem/P_VConnection.h new file mode 100644 index 00000000..b18c3d2f --- /dev/null +++ b/iocore/eventsystem/P_VConnection.h @@ -0,0 +1,138 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#if !defined (P_VConnection_h) +#define P_VConnection_h +#include "I_EventSystem.h" + +TS_INLINE const char * +get_vc_event_name(int event) +{ + switch (event) { + default: + return "unknown event"; + case VC_EVENT_NONE: + return "VC_EVENT_NONE"; + case VC_EVENT_IMMEDIATE: + return "VC_EVENT_IMMEDIATE"; + case VC_EVENT_READ_READY: + return "VC_EVENT_READ_READY"; + case VC_EVENT_WRITE_READY: + return "VC_EVENT_WRITE_READY"; + case VC_EVENT_READ_COMPLETE: + return "VC_EVENT_READ_COMPLETE"; + case VC_EVENT_WRITE_COMPLETE: + return "VC_EVENT_WRITE_COMPLETE"; + case VC_EVENT_EOS: + return "VC_EVENT_EOS"; + case VC_EVENT_ERROR: + return "VC_EVENT_ERROR"; + case VC_EVENT_INACTIVITY_TIMEOUT: + return "VC_EVENT_INACTIVITY_TIMEOUT"; + case VC_EVENT_ACTIVE_TIMEOUT: + return "VC_EVENT_ACTIVE_TIMEOUT"; + } +} + + +TS_INLINE +VConnection::VConnection(ProxyMutex * aMutex) + : +Continuation(aMutex), +lerrno(0) +{ + SET_HANDLER(0); +} + +TS_INLINE +VConnection::~ +VConnection() +{ +} + +////////////////////////////////////////////////////////////////////////////// +// +// DEPRECATED DEPRECATED DEPRECATED +// +// inline VIO * VConnection::do_io() +// +// This method enqueues a VIO operation onto the VIO queue, and +// activates the I/O operation if and operation of that type isn't +// already underway. +// +////////////////////////////////////////////////////////////////////////////// + +static TS_INLINE VIO * +vc_do_io_write(VConnection * vc, Continuation * cont, int64_t nbytes, MIOBuffer * buf, int64_t offset) +{ + IOBufferReader *reader = buf->alloc_reader(); + + if (offset > 0) + reader->consume(offset); + + return vc->do_io_write(cont, nbytes, reader, true); +} + +TS_INLINE VIO * +VConnection::do_io(int op, Continuation * c, int64_t nbytes, MIOBuffer * cb, int data) +{ + switch (op) { + case VIO::READ: + return do_io_read(c, nbytes, cb); + case VIO::WRITE: + return vc_do_io_write(this, c, nbytes, cb, data); + case VIO::CLOSE: + do_io_close(); + return NULL; + case VIO::ABORT: + do_io_close(data); + return NULL; + case VIO::SHUTDOWN_READ: + do_io_shutdown(IO_SHUTDOWN_READ); + return NULL; + case VIO::SHUTDOWN_WRITE: + do_io_shutdown(IO_SHUTDOWN_WRITE); + return NULL; + case VIO::SHUTDOWN_READWRITE: + do_io_shutdown(IO_SHUTDOWN_READWRITE); + return NULL; + } + ink_assert(!"cannot use default implementation for do_io operation"); + return NULL; +} + +TS_INLINE void +VConnection::set_continuation(VIO *, Continuation *) +{ +} +TS_INLINE void +VConnection::reenable(VIO *) +{ +} +TS_INLINE void +VConnection::reenable_re(VIO * vio) +{ + reenable(vio); +} +#endif diff --git a/iocore/eventsystem/P_VIO.h b/iocore/eventsystem/P_VIO.h new file mode 100644 index 00000000..39d88b22 --- /dev/null +++ b/iocore/eventsystem/P_VIO.h @@ -0,0 +1,139 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#if !defined ( P_VIO_h) +#define P_VIO_h +#include "I_VIO.h" + +TS_INLINE +VIO::VIO(int aop) + :_cont(NULL), + nbytes(0), + ndone(0), + op(aop), + buffer(), + vc_server(0), + mutex(0) +{ } + +///////////////////////////////////////////////////////////// +// +// VIO::VIO() +// +///////////////////////////////////////////////////////////// +TS_INLINE +VIO::VIO() + :_cont(0), + nbytes(0), + ndone(0), + op(VIO::NONE), + buffer(), + vc_server(0), + mutex(0) +{ } + +TS_INLINE Continuation * +VIO::get_continuation() +{ + return _cont; +} +TS_INLINE void +VIO::set_writer(MIOBuffer * writer) +{ + buffer.writer_for(writer); +} +TS_INLINE void +VIO::set_reader(IOBufferReader * reader) +{ + buffer.reader_for(reader); +} +TS_INLINE MIOBuffer * +VIO::get_writer() +{ + return buffer.writer(); +} +TS_INLINE IOBufferReader * +VIO::get_reader() +{ + return (buffer.reader()); +} +TS_INLINE int64_t +VIO::ntodo() +{ + return nbytes - ndone; +} +TS_INLINE void +VIO::done() +{ + if (buffer.reader()) + nbytes = ndone + buffer.reader()->read_avail(); + else + nbytes = ndone; +} + +///////////////////////////////////////////////////////////// +// +// VIO::set_continuation() +// +///////////////////////////////////////////////////////////// +TS_INLINE void +VIO::set_continuation(Continuation * acont) +{ + if (vc_server) + vc_server->set_continuation(this, acont); + if (acont) { + mutex = acont->mutex; + _cont = acont; + } else { + mutex = NULL; + _cont = NULL; + } + return; +} + +///////////////////////////////////////////////////////////// +// +// VIO::reenable() +// +///////////////////////////////////////////////////////////// +TS_INLINE void +VIO::reenable() +{ + if (vc_server) + vc_server->reenable(this); +} + +///////////////////////////////////////////////////////////// +// +// VIO::reenable_re() +// +///////////////////////////////////////////////////////////// +TS_INLINE void +VIO::reenable_re() +{ + if (vc_server) + vc_server->reenable_re(this); +} + +#endif /* #if !defined ( P_VIO_h) */ diff --git a/iocore/eventsystem/Processor.cc b/iocore/eventsystem/Processor.cc new file mode 100644 index 00000000..56ab1a4b --- /dev/null +++ b/iocore/eventsystem/Processor.cc @@ -0,0 +1,91 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Processor.cc + + Processor objects process requests which are placed in the Processor's + input queue. A Processor can contain multiple threads to process + requests in the queue. Requests in the queue are Continuations, which + describe functions to run, and what to do when the function is complete + (if anything). + + Basically, Processors should be viewed as multi-threaded schedulers which + process request Continuations from their queue. Requests can be made of + a Processor either by directly adding a request Continuation to the queue, + or more conveniently, by calling a method service call which synthesizes + the appropriate request Continuation and places it in the queue. + + + ****************************************************************************/ + +#include "P_EventSystem.h" +////////////////////////////////////////////////////////////////////////////// +// +// Processor::Processor() +// +// Constructor for a Processor. +// +////////////////////////////////////////////////////////////////////////////// + +Processor::Processor() +{ +} /* End Processor::Processor() */ + + +////////////////////////////////////////////////////////////////////////////// +// +// Processor::~Processor() +// +// Destructor for a Processor. +// +////////////////////////////////////////////////////////////////////////////// + +Processor::~Processor() +{ +} /* End Processor::~Processor() */ + +////////////////////////////////////////////////////////////////// +// +// Processor::create_thread() +// +////////////////////////////////////////////////////////////////// +Thread * +Processor::create_thread(int thread_index) +{ + NOWARN_UNUSED(thread_index); + ink_release_assert(!"Processor::create_thread -- no default implementation"); + return ((Thread *) 0); +} + +////////////////////////////////////////////////////////////////// +// +// Processor::get_thread_count() +// +////////////////////////////////////////////////////////////////// +int +Processor::get_thread_count() +{ + return (0); +} diff --git a/iocore/eventsystem/ProtectedQueue.cc b/iocore/eventsystem/ProtectedQueue.cc new file mode 100644 index 00000000..4da134b4 --- /dev/null +++ b/iocore/eventsystem/ProtectedQueue.cc @@ -0,0 +1,169 @@ +/** @file + + FIFO queue + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + ProtectedQueue implements a FIFO queue with the following functionality: + -# Multiple threads could be simultaneously trying to enqueue and + dequeue. Hence the queue needs to be protected with mutex. + -# In case the queue is empty, dequeue() sleeps for a specified amount + of time, or until a new element is inserted, whichever is earlier. + +*/ + +#include "P_EventSystem.h" + + +// The protected queue is designed to delay signaling of threads +// until some amount of work has been completed on the current thread +// in order to prevent excess context switches. +// +// Defining EAGER_SIGNALLING disables this behavior and causes +// threads to be made runnable immediately. +// +// #define EAGER_SIGNALLING + +extern ClassAllocator eventAllocator; + +void +ProtectedQueue::enqueue(Event *e , bool fast_signal) +{ + ink_assert(!e->in_the_prot_queue && !e->in_the_priority_queue); + EThread *e_ethread = e->ethread; + e->in_the_prot_queue = 1; + bool was_empty = (ink_atomiclist_push(&al, e) == NULL); + + if (was_empty) { + EThread *inserting_thread = this_ethread(); + // queue e->ethread in the list of threads to be signalled + // inserting_thread == 0 means it is not a regular EThread + if (inserting_thread != e_ethread) { + if (!inserting_thread || !inserting_thread->ethreads_to_be_signalled) { + signal(); + if (fast_signal) { + if (e_ethread->signal_hook) + e_ethread->signal_hook(e_ethread); + } + } else { +#ifdef EAGER_SIGNALLING + // Try to signal now and avoid deferred posting. + if (e_ethread->EventQueueExternal.try_signal()) + return; +#endif + if (fast_signal) { + if (e_ethread->signal_hook) + e_ethread->signal_hook(e_ethread); + } + int &t = inserting_thread->n_ethreads_to_be_signalled; + EThread **sig_e = inserting_thread->ethreads_to_be_signalled; + if ((t + 1) >= eventProcessor.n_ethreads) { + // we have run out of room + if ((t + 1) == eventProcessor.n_ethreads) { + // convert to direct map, put each ethread (sig_e[i]) into + // the direct map loation: sig_e[sig_e[i]->id] + for (int i = 0; i < t; i++) { + EThread *cur = sig_e[i]; // put this ethread + while (cur) { + EThread *next = sig_e[cur->id]; // into this location + if (next == cur) + break; + sig_e[cur->id] = cur; + cur = next; + } + // if not overwritten + if (sig_e[i] && sig_e[i]->id != i) + sig_e[i] = 0; + } + t++; + } + // we have a direct map, insert this EThread + sig_e[e_ethread->id] = e_ethread; + } else + // insert into vector + sig_e[t++] = e_ethread; + } + } + } +} + +void +flush_signals(EThread * thr) +{ + ink_debug_assert(this_ethread() == thr); + int n = thr->n_ethreads_to_be_signalled; + if (n > eventProcessor.n_ethreads) + n = eventProcessor.n_ethreads; // MAX + int i; + + // Since the lock is only there to prevent a race in ink_cond_timedwait + // the lock is taken only for a short time, thus it is unlikely that + // this code has any effect. +#ifdef EAGER_SIGNALLING + for (i = 0; i < n; i++) { + // Try to signal as many threads as possible without blocking. + if (thr->ethreads_to_be_signalled[i]) { + if (thr->ethreads_to_be_signalled[i]->EventQueueExternal.try_signal()) + thr->ethreads_to_be_signalled[i] = 0; + } + } +#endif + for (i = 0; i < n; i++) { + if (thr->ethreads_to_be_signalled[i]) { + thr->ethreads_to_be_signalled[i]->EventQueueExternal.signal(); + if (thr->ethreads_to_be_signalled[i]->signal_hook) + thr->ethreads_to_be_signalled[i]->signal_hook(thr->ethreads_to_be_signalled[i]); + thr->ethreads_to_be_signalled[i] = 0; + } + } + thr->n_ethreads_to_be_signalled = 0; +} + +void +ProtectedQueue::dequeue_timed(ink_hrtime cur_time, ink_hrtime timeout, bool sleep) +{ + (void) cur_time; + Event *e; + if (sleep) { + ink_mutex_acquire(&lock); + if (INK_ATOMICLIST_EMPTY(al)) { + timespec ts = ink_based_hrtime_to_timespec(timeout); + ink_cond_timedwait(&might_have_data, &lock, &ts); + } + ink_mutex_release(&lock); + } + + e = (Event *) ink_atomiclist_popall(&al); + // invert the list, to preserve order + SLL l, t; + t.head = e; + while ((e = t.pop())) + l.push(e); + // insert into localQueue + while ((e = l.pop())) { + if (!e->cancelled) + localQueue.enqueue(e); + else { + e->mutex = NULL; + eventAllocator.free(e); + } + } +} diff --git a/iocore/eventsystem/SocketManager.cc b/iocore/eventsystem/SocketManager.cc new file mode 100644 index 00000000..37a3134d --- /dev/null +++ b/iocore/eventsystem/SocketManager.cc @@ -0,0 +1,138 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + SocketManager.cc + ****************************************************************************/ +#include "libts.h" + +#if !defined(linux) +#include +#endif + +#if defined(solaris) +// XXX: Those are already included from ink_platform.h!!! +#include +#include +extern "C" int madvise(caddr_t, size_t, int); // FIXME: why is this not being found +#endif + +#include "P_EventSystem.h" + +SocketManager socketManager; + +SocketManager::SocketManager() +{ + pagesize = getpagesize(); +} + +SocketManager::~SocketManager() +{ + // free the hash table and values +} + +int +safe_msync(caddr_t addr, size_t len, caddr_t end, int flags) +{ + (void) end; + // align start back to page boundary + caddr_t a = (caddr_t) (((uintptr_t) addr) & ~(socketManager.pagesize - 1)); + // align length to page boundry covering region + size_t l = (len + (addr - a) + (socketManager.pagesize - 1)) & ~(socketManager.pagesize - 1); + if ((a + l) > end) + l = end - a; // strict limit +#if defined(linux) +/* Fix INKqa06500 + Under Linux, msync(..., MS_SYNC) calls are painfully slow, even on + non-dirty buffers. This is true as of kernel 2.2.12. We sacrifice + restartability under OS in order to avoid a nasty performance hit + from a kernel global lock. */ +#if 0 + // this was long long ago + if (flags & MS_SYNC) + flags = (flags & ~MS_SYNC) | MS_ASYNC; +#endif +#endif + int res = msync(a, l, flags); + return res; +} + +int +safe_madvise(caddr_t addr, size_t len, caddr_t end, int flags) +{ + (void) end; +#if defined(linux) + (void) addr; + (void) len; + (void) end; + (void) flags; + return 0; +#else + caddr_t a = (caddr_t) (((uintptr_t) addr) & ~(socketManager.pagesize - 1)); + size_t l = (len + (addr - a) + socketManager.pagesize - 1) + & ~(socketManager.pagesize - 1); + int res = 0; + res = madvise(a, l, flags); + return res; +#endif +} + +int +safe_mlock(caddr_t addr, size_t len, caddr_t end) +{ + + caddr_t a = (caddr_t) (((uintptr_t) addr) & ~(socketManager.pagesize - 1)); + size_t l = (len + (addr - a) + socketManager.pagesize - 1) + & ~(socketManager.pagesize - 1); + if ((a + l) > end) + l = end - a; // strict limit + int res = mlock(a, l); + return res; +} + +int +SocketManager::ink_bind(int s, struct sockaddr *name, int namelen, short Proto) +{ + (void) Proto; + return safe_bind(s, name, namelen); +} + + +int +SocketManager::close(int s) +{ + int res; + + if (s == 0) + return -EACCES; + else if (s < 0) + return -EINVAL; + + do { + res = ::close(s); + if (res == -1) + res = -errno; + } while (res == -EINTR); + return res; +} diff --git a/iocore/eventsystem/Tasks.cc b/iocore/eventsystem/Tasks.cc new file mode 100644 index 00000000..7d1c55f7 --- /dev/null +++ b/iocore/eventsystem/Tasks.cc @@ -0,0 +1,36 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_Tasks.h" + +// Globals +EventType ET_TASK = ET_CALL; +TasksProcessor tasksProcessor; + +int +TasksProcessor::start(int task_threads) +{ + if (task_threads > 0) + ET_TASK = eventProcessor.spawn_event_threads(task_threads, "ET_TASK"); + return 0; +} diff --git a/iocore/eventsystem/Thread.cc b/iocore/eventsystem/Thread.cc new file mode 100644 index 00000000..71603fe2 --- /dev/null +++ b/iocore/eventsystem/Thread.cc @@ -0,0 +1,107 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Basic Threads + + + +**************************************************************************/ +#include "P_EventSystem.h" + + /////////////////////////////////////////////// + // Common Interface impl // + /////////////////////////////////////////////// + +static ink_thread_key init_thread_key(); + +ProxyMutex *global_mutex = NULL; +ink_hrtime + Thread::cur_time = 0; +inkcoreapi ink_thread_key + Thread::thread_data_key = init_thread_key(); + +Thread::Thread() +{ + mutex = new_ProxyMutex(); + mutex_ptr = mutex; + MUTEX_TAKE_LOCK(mutex, (EThread *) this); + mutex->nthread_holding = THREAD_MUTEX_THREAD_HOLDING; +} + +static void +key_destructor(void *value) +{ + (void) value; +} + +ink_thread_key +init_thread_key() +{ + ink_thread_key_create(&Thread::thread_data_key, key_destructor); + return Thread::thread_data_key; +} + + /////////////////////////////////////////////// + // Unix & non-NT Interface impl // + /////////////////////////////////////////////// + +struct thread_data_internal +{ + ThreadFunction f; + void *a; + Thread *me; + char name[MAX_THREAD_NAME_LENGTH]; +}; + +static void * +spawn_thread_internal(void *a) +{ + thread_data_internal *p = (thread_data_internal *) a; + + p->me->set_specific(); + ink_set_thread_name(p->name); + if (p->f) + p->f(p->a); + else + p->me->execute(); + xfree(a); + return NULL; +} + +void +Thread::start(const char* name, ThreadFunction f, void *a, size_t stacksize) +{ + thread_data_internal *p = (thread_data_internal *) xmalloc(sizeof(thread_data_internal)); + + if (0 == stacksize) + REC_ReadConfigInteger(stacksize, "proxy.config.thread.default.stacksize"); + + p->f = f; + p->a = a; + p->me = this; + memset(p->name, 0, MAX_THREAD_NAME_LENGTH); + ink_strncpy(p->name, name, MAX_THREAD_NAME_LENGTH - 1); + this->tid = ink_thread_create(spawn_thread_internal, (void *) p, 0, stacksize); +} diff --git a/iocore/eventsystem/UnixEThread.cc b/iocore/eventsystem/UnixEThread.cc new file mode 100644 index 00000000..6b6a1083 --- /dev/null +++ b/iocore/eventsystem/UnixEThread.cc @@ -0,0 +1,298 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +////////////////////////////////////////////////////////////////////// +// +// The EThread Class +// +///////////////////////////////////////////////////////////////////// +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "P_EventSystem.h" + +#if TS_HAS_EVENTFD +#include +#endif + +struct AIOCallback; + +#define MAX_HEARTBEATS_MISSED 10 +#define NO_HEARTBEAT -1 +#define THREAD_MAX_HEARTBEAT_MSECONDS 60 +#define NO_ETHREAD_ID -1 + +EThread::EThread() + : generator((uint64_t)ink_get_hrtime_internal() ^ (uint64_t)(uintptr_t)this), + ethreads_to_be_signalled(NULL), + n_ethreads_to_be_signalled(0), + main_accept_index(-1), + id(NO_ETHREAD_ID), event_types(0), + signal_hook(0), + tt(REGULAR), eventsem(NULL) +{ + memset(thread_private, 0, PER_THREAD_DATA); +} + +EThread::EThread(ThreadType att, int anid) + : generator((uint64_t)ink_get_hrtime_internal() ^ (uint64_t)(uintptr_t)this), + ethreads_to_be_signalled(NULL), + n_ethreads_to_be_signalled(0), + main_accept_index(-1), + id(anid), + event_types(0), + signal_hook(0), + tt(att), + eventsem(NULL) +{ + ethreads_to_be_signalled = (EThread **) xmalloc(MAX_EVENT_THREADS * sizeof(EThread *)); + memset((char *) ethreads_to_be_signalled, 0, MAX_EVENT_THREADS * sizeof(EThread *)); + memset(thread_private, 0, PER_THREAD_DATA); +#if TS_HAS_EVENTFD + evfd = eventfd(0, O_NONBLOCK | FD_CLOEXEC); + if (evfd < 0) { + if (errno == EINVAL) { // flags invalid for kernel <= 2.6.26 + evfd = eventfd(0,0); + if (evfd < 0) + Fatal("EThread::EThread: %d=eventfd(0,0),errno(%d)",evfd,errno); + } else + Fatal("EThread::EThread: %d=eventfd(0,O_NONBLOCK | FD_CLOEXEC),errno(%d)",evfd,errno); + } + fcntl(evfd, F_SETFD, FD_CLOEXEC); + fcntl(evfd, F_SETFL, O_NONBLOCK); +#else + ink_release_assert(pipe(evpipe) >= 0); + fcntl(evpipe[0], F_SETFD, FD_CLOEXEC); + fcntl(evpipe[0], F_SETFL, O_NONBLOCK); + fcntl(evpipe[1], F_SETFD, FD_CLOEXEC); + fcntl(evpipe[1], F_SETFL, O_NONBLOCK); +#endif +} + +EThread::EThread(ThreadType att, Event * e, ink_sem * sem) + : generator((uint32_t)((uintptr_t)time(NULL) ^ (uintptr_t) this)), + ethreads_to_be_signalled(NULL), + n_ethreads_to_be_signalled(0), + main_accept_index(-1), + id(NO_ETHREAD_ID), event_types(0), + signal_hook(0), + tt(att), oneevent(e), eventsem(sem) +{ + ink_assert(att == DEDICATED); + memset(thread_private, 0, PER_THREAD_DATA); +} + + +// Provide a destructor so that SDK functions which create and destroy +// threads won't have to deal with EThread memory deallocation. +EThread::~EThread() +{ + if (n_ethreads_to_be_signalled > 0) + flush_signals(this); + if (ethreads_to_be_signalled) + xfree(ethreads_to_be_signalled); +} + +bool +EThread::is_event_type(EventType et) +{ + return !!(event_types & (1 << (int) et)); +} + +void +EThread::set_event_type(EventType et) +{ + event_types |= (1 << (int) et); +} + +void +EThread::process_event(Event * e, int calling_code) +{ + ink_assert((!e->in_the_prot_queue && !e->in_the_priority_queue)); + MUTEX_TRY_LOCK_FOR(lock, e->mutex.m_ptr, this, e->continuation); + if (!lock) { + e->timeout_at = cur_time + DELAY_FOR_RETRY; + EventQueueExternal.enqueue_local(e); + } else { + if (e->cancelled) { + free_event(e); + return; + } + Continuation *c_temp = e->continuation; + e->continuation->handleEvent(calling_code, e); + ink_assert(!e->in_the_priority_queue); + ink_assert(c_temp == e->continuation); + MUTEX_RELEASE(lock); + if (e->period) { + if (!e->in_the_prot_queue && !e->in_the_priority_queue) { + if (e->period < 0) + e->timeout_at = e->period; + else { + cur_time = ink_get_based_hrtime(); + e->timeout_at = cur_time + e->period; + if (e->timeout_at < cur_time) + e->timeout_at = cur_time; + } + EventQueueExternal.enqueue_local(e); + } + } else if (!e->in_the_prot_queue && !e->in_the_priority_queue) + free_event(e); + } +} + +// +// void EThread::execute() +// +// Execute loops forever on: +// Find the earliest event. +// Sleep until the event time or until an earlier event is inserted +// When its time for the event, try to get the appropriate continuation +// lock. If successful, call the continuation, otherwise put the event back +// into the queue. +// + +void +EThread::execute() { + switch (tt) { + + case REGULAR: { + Event *e; + Que(Event, link) NegativeQueue; + ink_hrtime next_time = 0; + + // give priority to immediate events + for (;;) { + // execute all the available external events that have + // already been dequeued + cur_time = ink_get_based_hrtime_internal(); + while ((e = EventQueueExternal.dequeue_local())) { + if (!e->timeout_at) { // IMMEDIATE + ink_assert(e->period == 0); + process_event(e, e->callback_event); + } else if (e->timeout_at > 0) // INTERVAL + EventQueue.enqueue(e, cur_time); + else { // NEGATIVE + Event *p = NULL; + Event *a = NegativeQueue.head; + while (a && a->timeout_at > e->timeout_at) { + p = a; + a = a->link.next; + } + if (!a) + NegativeQueue.enqueue(e); + else + NegativeQueue.insert(e, p); + } + } + bool done_one; + do { + done_one = false; + // execute all the eligible internal events + EventQueue.check_ready(cur_time, this); + while ((e = EventQueue.dequeue_ready(cur_time))) { + ink_assert(e); + ink_assert(e->timeout_at > 0); + if (e->cancelled) + free_event(e); + else { + done_one = true; + process_event(e, e->callback_event); + } + } + } while (done_one); + // execute any negative (poll) events + if (NegativeQueue.head) { + if (n_ethreads_to_be_signalled) + flush_signals(this); + // dequeue all the external events and put them in a local + // queue. If there are no external events available, don't + // do a cond_timedwait. + if (!INK_ATOMICLIST_EMPTY(EventQueueExternal.al)) + EventQueueExternal.dequeue_timed(cur_time, next_time, false); + while ((e = EventQueueExternal.dequeue_local())) { + if (!e->timeout_at) + process_event(e, e->callback_event); + else { + if (e->cancelled) + free_event(e); + else { + // If its a negative event, it must be a result of + // a negative event, which has been turned into a + // timed-event (because of a missed lock), executed + // before the poll. So, it must + // be executed in this round (because you can't have + // more than one poll between two executions of a + // negative event) + if (e->timeout_at < 0) { + Event *p = NULL; + Event *a = NegativeQueue.head; + while (a && a->timeout_at > e->timeout_at) { + p = a; + a = a->link.next; + } + if (!a) + NegativeQueue.enqueue(e); + else + NegativeQueue.insert(e, p); + } else + EventQueue.enqueue(e, cur_time); + } + } + } + // execute poll events + while ((e = NegativeQueue.dequeue())) + process_event(e, EVENT_POLL); + if (!INK_ATOMICLIST_EMPTY(EventQueueExternal.al)) + EventQueueExternal.dequeue_timed(cur_time, next_time, false); + } else { // Means there are no negative events + next_time = EventQueue.earliest_timeout(); + ink_hrtime sleep_time = next_time - cur_time; + if (sleep_time > THREAD_MAX_HEARTBEAT_MSECONDS * HRTIME_MSECOND) { + next_time = cur_time + THREAD_MAX_HEARTBEAT_MSECONDS * HRTIME_MSECOND; + sleep_time = THREAD_MAX_HEARTBEAT_MSECONDS * HRTIME_MSECOND; + } + // dequeue all the external events and put them in a local + // queue. If there are no external events available, do a + // cond_timedwait. + if (n_ethreads_to_be_signalled) + flush_signals(this); + EventQueueExternal.dequeue_timed(cur_time, next_time, true); + } + } + } + + case DEDICATED: { + // coverity[lock] + if (eventsem) + ink_sem_wait(eventsem); + MUTEX_TAKE_LOCK_FOR(oneevent->mutex, this, oneevent->continuation); + oneevent->continuation->handleEvent(EVENT_IMMEDIATE, oneevent); + MUTEX_UNTAKE_LOCK(oneevent->mutex, this); + free_event(oneevent); + break; + } + + default: + ink_assert(!"bad case value (execute)"); + break; + } /* End switch */ + // coverity[missing_unlock] +} diff --git a/iocore/eventsystem/UnixEvent.cc b/iocore/eventsystem/UnixEvent.cc new file mode 100644 index 00000000..e34b4770 --- /dev/null +++ b/iocore/eventsystem/UnixEvent.cc @@ -0,0 +1,103 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/**************************************************************************** + + Event.cc + + +*****************************************************************************/ +#include "P_EventSystem.h" + +ClassAllocator eventAllocator("eventAllocator", 256); + +void +Event::schedule_imm(int acallback_event) +{ + callback_event = acallback_event; + ink_debug_assert(ethread == this_ethread()); + if (in_the_prot_queue) + ethread->EventQueueExternal.remove(this); + if (in_the_priority_queue) + ethread->EventQueue.remove(this); + timeout_at = 0; + period = 0; + immediate = true; + mutex = continuation->mutex; + ethread->EventQueueExternal.enqueue_local(this); +} + +void +Event::schedule_at(ink_hrtime atimeout_at, int acallback_event) +{ + callback_event = acallback_event; + ink_debug_assert(ethread == this_ethread()); + ink_assert(atimeout_at > 0); + if (in_the_prot_queue) + ethread->EventQueueExternal.remove(this); + if (in_the_priority_queue) + ethread->EventQueue.remove(this); + timeout_at = atimeout_at; + period = 0; + immediate = false; + mutex = continuation->mutex; + ethread->EventQueueExternal.enqueue_local(this); +} + +void +Event::schedule_in(ink_hrtime atimeout_in, int acallback_event) +{ + callback_event = acallback_event; + ink_debug_assert(ethread == this_ethread()); + if (in_the_prot_queue) + ethread->EventQueueExternal.remove(this); + if (in_the_priority_queue) + ethread->EventQueue.remove(this); + timeout_at = ink_get_based_hrtime() + atimeout_in; + period = 0; + immediate = false; + mutex = continuation->mutex; + ethread->EventQueueExternal.enqueue_local(this); +} + +void +Event::schedule_every(ink_hrtime aperiod, int acallback_event) +{ + callback_event = acallback_event; + ink_debug_assert(ethread == this_ethread()); + ink_assert(aperiod != 0); + if (in_the_prot_queue) + ethread->EventQueueExternal.remove(this); + if (in_the_priority_queue) + ethread->EventQueue.remove(this); + if (aperiod < 0) { + timeout_at = aperiod; + } else { + timeout_at = ink_get_based_hrtime() + aperiod; + } + period = aperiod; + immediate = false; + mutex = continuation->mutex; + ethread->EventQueueExternal.enqueue_local(this); +} diff --git a/iocore/eventsystem/UnixEventProcessor.cc b/iocore/eventsystem/UnixEventProcessor.cc new file mode 100644 index 00000000..07be2431 --- /dev/null +++ b/iocore/eventsystem/UnixEventProcessor.cc @@ -0,0 +1,122 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_EventSystem.h" /* MAGIC_EDITING_TAG */ + + + +EventType +EventProcessor::spawn_event_threads(int n_threads, const char* et_name) +{ + char thr_name[MAX_THREAD_NAME_LENGTH]; + EventType new_thread_group_id; + int i; + + ink_release_assert(n_threads > 0); + ink_release_assert((n_ethreads + n_threads) <= MAX_EVENT_THREADS); + ink_release_assert(n_thread_groups < MAX_EVENT_TYPES); + + new_thread_group_id = (EventType) n_thread_groups; + + for (i = 0; i < n_threads; i++) { + EThread *t = NEW(new EThread(REGULAR, n_ethreads + i)); + all_ethreads[n_ethreads + i] = t; + eventthread[new_thread_group_id][i] = t; + t->set_event_type(new_thread_group_id); + } + + n_threads_for_type[new_thread_group_id] = n_threads; + for (i = 0; i < n_threads; i++) { + snprintf(thr_name, MAX_THREAD_NAME_LENGTH, "[%s %d]", et_name, i); + eventthread[new_thread_group_id][i]->start(thr_name); + } + + n_thread_groups++; + n_ethreads += n_threads; + Debug("iocore_thread", "Created thread group id %d", new_thread_group_id); + + return new_thread_group_id; +} + + +#define INK_NO_CLUSTER + +class EventProcessor eventProcessor; + +int +EventProcessor::start(int n_event_threads) +{ + char thr_name[MAX_THREAD_NAME_LENGTH]; + int i; + + // do some sanity checking. + static int started = 0; + ink_release_assert(!started); + ink_release_assert(n_event_threads > 0 && n_event_threads <= MAX_EVENT_THREADS); + started = 1; + + n_ethreads = n_event_threads; + n_thread_groups = 1; + + int first_thread = 1; + + for (i = 0; i < n_event_threads; i++) { + EThread *t = NEW(new EThread(REGULAR, i)); + if (first_thread && !i) { + ink_thread_setspecific(Thread::thread_data_key, t); + global_mutex = t->mutex; + t->cur_time = ink_get_based_hrtime_internal(); + } + all_ethreads[i] = t; + + eventthread[ET_CALL][i] = t; + t->set_event_type((EventType) ET_CALL); + } + n_threads_for_type[ET_CALL] = n_event_threads; + for (i = first_thread; i < n_ethreads; i++) { + snprintf(thr_name, MAX_THREAD_NAME_LENGTH, "[ET_NET %d]", i); + all_ethreads[i]->start(thr_name); + } + + return 0; +} + +void +EventProcessor::shutdown() +{ +} + +Event * +EventProcessor::spawn_thread(Continuation *cont, const char* thr_name, ink_sem *sem) +{ + Event *e = eventAllocator.alloc(); + + e->init(cont, 0, 0); + dthreads[n_dthreads] = NEW(new EThread(DEDICATED, e, sem)); + e->ethread = dthreads[n_dthreads]; + e->mutex = e->continuation->mutex = dthreads[n_dthreads]->mutex; + n_dthreads++; + e->ethread->start(thr_name); + + return e; +} diff --git a/iocore/eventsystem/test_Buffer.cc b/iocore/eventsystem/test_Buffer.cc new file mode 100644 index 00000000..764b3177 --- /dev/null +++ b/iocore/eventsystem/test_Buffer.cc @@ -0,0 +1,160 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_EventSystem.h" + +#define TEST_TIME_SECOND 60 +#define TEST_THREADS 2 + +int count; +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_IOCORE_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + + +int +main() +{ + RecModeT mode_type = RECM_STAND_ALONE; + count = 0; + RecProcessInit(mode_type); + + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(TEST_THREADS); + + for (int i = 0; i < 100; i++) { + MIOBuffer *b1 = new_MIOBuffer(default_large_iobuffer_size); + IOBufferReader *b1reader = b1->alloc_reader(); + b1->fill(1024 * 3); + MIOBuffer *b2 = new_MIOBuffer(default_large_iobuffer_size); + IOBufferReader *b2reader = b2->alloc_reader(); + b2->fill(1024 * 3); + //b1->write(b2reader, 2*1024); + free_MIOBuffer(b2); + /* leak this */ + b1 = NULL; + if ((i % 20) == 0) + xdump_to_file(stderr); + } + + exit(0); +#ifndef _IOCORE_WIN32_WINNT + this_thread()->execute(); +#else + Sleep(INFINITE); +#endif + return 0; +} diff --git a/iocore/eventsystem/test_Event.i b/iocore/eventsystem/test_Event.i new file mode 100644 index 00000000..394b32aa --- /dev/null +++ b/iocore/eventsystem/test_Event.i @@ -0,0 +1,174 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define TEST_TIME_SECOND 60 +#define TEST_THREADS 2 + +int count; +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + +struct alarm_printer:public Continuation +{ + alarm_printer(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&alarm_printer::dummy_function); + } + int dummy_function(int event, Event * e) + { + ink_atomic_increment((int *) &count, 1); + printf("Count = %d\n", count); + return 0; + } +}; +struct process_killer:public Continuation +{ + process_killer(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&process_killer::kill_function); + } + int kill_function(int event, Event * e) + { + printf("Count is %d \n", count); + if (count <= 0) + exit(1); + if (count > TEST_TIME_SECOND * TEST_THREADS) + exit(1); + exit(0); + return 0; + } +}; + + + +int +main(int argc, char *argv[]) +{ + RecModeT mode_type = RECM_STAND_ALONE; + count = 0; + RecProcessInit(mode_type); + + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(TEST_THREADS); + + alarm_printer *alrm = new alarm_printer(new_ProxyMutex()); + process_killer *killer = new process_killer(new_ProxyMutex()); + eventProcessor.schedule_in(killer, HRTIME_SECONDS(60)); + eventProcessor.schedule_every(alrm, HRTIME_SECONDS(1)); + this_thread()->execute(); + return 0; +} diff --git a/iocore/eventsystem/test_I_Buffer.cc b/iocore/eventsystem/test_I_Buffer.cc new file mode 100644 index 00000000..e236b517 --- /dev/null +++ b/iocore/eventsystem/test_I_Buffer.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_EventSystem.h" +#include "test_Buffer.cc" diff --git a/iocore/eventsystem/test_I_Event.cc b/iocore/eventsystem/test_I_Event.cc new file mode 100644 index 00000000..a8d7bc01 --- /dev/null +++ b/iocore/eventsystem/test_I_Event.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_EventSystem.h" +#include "test_Event.i" diff --git a/iocore/eventsystem/test_P_Buffer.cc b/iocore/eventsystem/test_P_Buffer.cc new file mode 100644 index 00000000..f26d8859 --- /dev/null +++ b/iocore/eventsystem/test_P_Buffer.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_EventSystem.h" +#include "test_Buffer.cc" diff --git a/iocore/eventsystem/test_P_Event.cc b/iocore/eventsystem/test_P_Event.cc new file mode 100644 index 00000000..a8d7bc01 --- /dev/null +++ b/iocore/eventsystem/test_P_Event.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_EventSystem.h" +#include "test_Event.i" diff --git a/iocore/hostdb/HostDB.cc b/iocore/hostdb/HostDB.cc new file mode 100644 index 00000000..f01567e2 --- /dev/null +++ b/iocore/hostdb/HostDB.cc @@ -0,0 +1,2333 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define _HOSTDB_CC_ + +#include "P_HostDB.h" +#include "I_Layout.h" + +#ifndef NON_MODULAR +//char system_config_directory[512] = "etc/trafficserver"; +#else +#include "Show.h" +#endif + +// dxu: turn off all Diags.h 's function. +//#define Debug +//#define Warning +//#define Note + +// +// Compilation Options +// +#define USE_MMH + +#include "ink_apidefs.h" + +HostDBProcessor hostDBProcessor; +int HostDBProcessor::hostdb_strict_round_robin = 0; +int hostdb_enable = true; +int hostdb_migrate_on_demand = true; +int hostdb_cluster = false; +int hostdb_cluster_round_robin = false; +int hostdb_lookup_timeout = 120; +int hostdb_insert_timeout = 160; +int hostdb_re_dns_on_reload = false; +int hostdb_ttl_mode = TTL_OBEY; +unsigned int hostdb_current_interval = 0; +unsigned int hostdb_ip_stale_interval = HOST_DB_IP_STALE; +unsigned int hostdb_ip_timeout_interval = HOST_DB_IP_TIMEOUT; +unsigned int hostdb_ip_fail_timeout_interval = HOST_DB_IP_FAIL_TIMEOUT; +unsigned int hostdb_serve_stale_but_revalidate = 0; +char hostdb_filename[PATH_NAME_MAX + 1] = DEFAULT_HOST_DB_FILENAME; +int hostdb_size = DEFAULT_HOST_DB_SIZE; +//int hostdb_timestamp = 0; +int hostdb_sync_frequency = 60; +int hostdb_disable_reverse_lookup = 0; + +ClassAllocator hostDBContAllocator("hostDBContAllocator"); + +// Static configuration information + +HostDBCache + hostDB; + +#ifdef NON_MODULAR +static Queue remoteHostDBQueue[MULTI_CACHE_PARTITIONS]; +#endif + +static inline int +corrupt_debugging_callout(HostDBInfo * e, RebuildMC & r) +{ + Debug("hostdb", "corrupt %d part %d", (char *) &e->app.rr.offset - r.data, r.partition); + return -1; +} + + +inline void +hostdb_cont_free(HostDBContinuation * cont) +{ + if (cont->pending_action) + cont->pending_action->cancel(); + cont->mutex = 0; + cont->action.mutex = 0; + hostDBContAllocator.free(cont); +} + + +// +// Function Prototypes +// +#ifdef NON_MODULAR +static Action * +register_ShowHostDB(Continuation * c, HTTPHdr * h); +#endif + + +HostDBCache::HostDBCache() +{ + tag_bits = HOST_DB_TAG_BITS; + max_hits = (1 << HOST_DB_HITS_BITS) - 1; + version.ink_major = HOST_DB_CACHE_MAJOR_VERSION; + version.ink_minor = HOST_DB_CACHE_MINOR_VERSION; +} + + +int +HostDBCache::rebuild_callout(HostDBInfo * e, RebuildMC & r) +{ + if (e->round_robin && e->reverse_dns) + return corrupt_debugging_callout(e, r); + if (e->reverse_dns) { + if (e->data.hostname_offset < 0) + return 0; + if (e->data.hostname_offset > 0) { + if (!valid_offset(e->data.hostname_offset - 1)) + return corrupt_debugging_callout(e, r); + char *p = (char *) ptr(&e->data.hostname_offset, r.partition); + if (!p) + return corrupt_debugging_callout(e, r); + char *s = p; + while (*p && p - s < MAXDNAME) { + if (!valid_heap_pointer(p)) + return corrupt_debugging_callout(e, r); + p++; + } + if (p - s >= MAXDNAME) + return corrupt_debugging_callout(e, r); + } + } + if (e->round_robin) { + if (e->app.rr.offset < 0) + return 0; + if (!valid_offset(e->app.rr.offset - 1)) + return corrupt_debugging_callout(e, r); + HostDBRoundRobin *rr = (HostDBRoundRobin *) ptr(&e->app.rr.offset, r.partition); + if (!rr) + return corrupt_debugging_callout(e, r); + if (rr->n > HOST_DB_MAX_ROUND_ROBIN_INFO || rr->n <= 0 || + rr->good > HOST_DB_MAX_ROUND_ROBIN_INFO || rr->good <= 0 || rr->good > rr->n) + return corrupt_debugging_callout(e, r); + for (int i = 0; i < rr->good; i++) { + if (!valid_heap_pointer(((char *) &rr->info[i + 1]) - 1)) + return -1; + if (!rr->info[i].ip()) + return corrupt_debugging_callout(e, r); + if (rr->info[i].md5_high != e->md5_high || + rr->info[i].md5_low != e->md5_low || rr->info[i].md5_low_low != e->md5_low_low) + return corrupt_debugging_callout(e, r); + } + } + if (e->is_ip_timeout()) + return 0; + return 1; +} + + +HostDBCache * +HostDBProcessor::cache() +{ + return &hostDB; +} + + +struct HostDBTestRR: public Continuation +{ + int fd; + char b[512]; + int nb; + int outstanding, success, failure; + int in; + + int mainEvent(int event, Event * e) + { + if (event == EVENT_INTERVAL) { + printf("HostDBTestRR: %d outstanding %d succcess %d failure\n", outstanding, success, failure); + } + if (event == EVENT_HOST_DB_LOOKUP) { + outstanding--; + if (e) + success++; + else + failure++; + } + if (in) + return EVENT_CONT; + in = 1; + while (outstanding < 40) { + if (!nb) + goto Lreturn; + char *end = (char *)memchr(b, '\n', nb); + if (!end) + read_some(); + end = (char *)memchr(b, '\n', nb); + if (!end) + nb = 0; + else { + *end = 0; + outstanding++; + hostDBProcessor.getbyname_re(this, b); + nb -= ((end + 1) - b); + memcpy(b, end + 1, nb); + if (!nb) + read_some(); + } + } + Lreturn: + in = 0; + return EVENT_CONT; + } + + + void read_some() + { + nb = read(fd, b + nb, 512 - nb); + ink_release_assert(nb >= 0); + } + + +HostDBTestRR():Continuation(new_ProxyMutex()), nb(0), outstanding(0), success(0), failure(0), in(0) { + printf("starting HostDBTestRR....\n"); + fd = open("hostdb_test.config", O_RDONLY, 0); + ink_release_assert(fd >= 0); + read_some(); + SET_HANDLER(&HostDBTestRR::mainEvent); + } +}; + + +struct HostDBSyncer: public Continuation +{ + int frequency; + ink_hrtime start_time; + + int sync_event(int event, void *edata); + int wait_event(int event, void *edata); + + HostDBSyncer(); +}; + + +HostDBSyncer::HostDBSyncer(): +Continuation(new_ProxyMutex()), frequency(0), start_time(0) +{ + SET_HANDLER(&HostDBSyncer::sync_event); + IOCORE_EstablishStaticConfigInt32(hostdb_sync_frequency, "proxy.config.cache.hostdb.sync_frequency"); +} + + +int +HostDBSyncer::sync_event(int, void *) +{ + SET_HANDLER(&HostDBSyncer::wait_event); + start_time = ink_get_hrtime(); + hostDBProcessor.cache()->sync_partitions(this); + return EVENT_DONE; +} + + +int +HostDBSyncer::wait_event(int, void *) +{ + SET_HANDLER(&HostDBSyncer::sync_event); + mutex->thread_holding->schedule_in_local(this, HRTIME_SECONDS(hostdb_sync_frequency)); + return EVENT_DONE; +} + + +int +HostDBCache::start(int flags) +{ + Store *hostDBStore; + Span *hostDBSpan; + char storage_path[PATH_NAME_MAX + 1]; + int storage_size = 0; + + bool reconfigure = ((flags & PROCESSOR_RECONFIGURE) ? true : false); + bool fix = ((flags & PROCESSOR_FIX) ? true : false); + + // Read configuration + // Command line overrides manager configuration. + // + IOCORE_ReadConfigInt32(hostdb_enable, "proxy.config.hostdb"); + IOCORE_ReadConfigString(hostdb_filename, "proxy.config.hostdb.filename", PATH_NAME_MAX); + IOCORE_ReadConfigInt32(hostdb_size, "proxy.config.hostdb.size"); + +#if defined (_IOCORE_WIN32) + // since the config directory is always based of TSBase, we make sure + // all the internal paths correctly get set. + char szPath[PATH_NAME_MAX + 1]; + IOCORE_ReadConfigString(szPath, "proxy.config.hostdb.storage_path", PATH_NAME_MAX); + int i = 0; + while (szPath[i] != 0) { + if (szPath[i] == '/') + szPath[i] = '\\'; + i++; + } + ink_strncpy(storage_path, system_root_dir, sizeof(storage_path)); + strcat(storage_path, DIR_SEP); + strcat(storage_path, szPath); +#else + IOCORE_ReadConfigString(storage_path, "proxy.config.hostdb.storage_path", PATH_NAME_MAX); +#endif + IOCORE_ReadConfigInt32(storage_size, "proxy.config.hostdb.storage_size"); + + if (storage_path[0] != '/') { + Layout::relative_to(storage_path, PATH_NAME_MAX, + system_root_dir, storage_path); + } + + Debug("hostdb", "Storage path is %s", storage_path); + + // XXX: Should this be W_OK? + if (access(storage_path, R_OK) == -1) { + ink_strncpy(storage_path, system_runtime_dir, sizeof(storage_path)); + if (access(storage_path, R_OK) == -1) { + Warning("Unable to access() directory '%s': %d, %s", storage_path, errno, strerror(errno)); + Warning(" Please set 'proxy.config.hostdb.storage_path' or 'proxy.config.local_state_dir' "); + } + } + hostDBStore = NEW(new Store); + hostDBSpan = NEW(new Span); + hostDBSpan->init(storage_path, storage_size); + hostDBStore->add(hostDBSpan); + + Debug("hostdb", "Opening %s, size=%d", hostdb_filename, hostdb_size); + if (open(hostDBStore, "hostdb.config", hostdb_filename, hostdb_size, reconfigure, fix, false /* slient */ ) < 0) { + Note("reconfiguring host database"); + + char p[PATH_NAME_MAX + 1]; + Layout::relative_to(p, PATH_NAME_MAX, + system_config_directory, "internal/hostdb.config"); + if (unlink(p) < 0) + Debug("hostdb", "unable to unlink %s", p); + + delete hostDBStore; + hostDBStore = NEW(new Store); + hostDBSpan = NEW(new Span); + hostDBSpan->init(storage_path, storage_size); + hostDBStore->add(hostDBSpan); + + if (open(hostDBStore, "hostdb.config", hostdb_filename, hostdb_size, true, fix) < 0) { + Warning("could not initialize host database. Host database will be disabled"); + hostdb_enable = 0; + delete hostDBStore; + return -1; + } + } + HOSTDB_SET_DYN_COUNT(hostdb_bytes_stat, totalsize); + // XXX I don't see this being reference in the previous function calls, so I am going to delete it -bcall + delete hostDBStore; + return 0; +} + + +// Start up the Host Database processor. +// Load configuration, register configuration and statistics and +// open the cache. +// +int +HostDBProcessor::start(int) +{ + //bool found = false; + hostDB.alloc_mutexes(); + + if (hostDB.start(0) < 0) + return -1; + +#ifdef NON_MODULAR + if (auto_clear_hostdb_flag) + hostDB.clear(); +#endif + + HOSTDB_SET_DYN_COUNT(hostdb_total_entries_stat, hostDB.totalelements); + +#ifdef NON_MODULAR + statPagesManager.register_http("hostdb", register_ShowHostDB); +#endif + + // + // Register configuration callback, and establish configuation links + // + IOCORE_EstablishStaticConfigInt32(hostdb_ttl_mode, "proxy.config.hostdb.ttl_mode"); + IOCORE_EstablishStaticConfigInt32(hostdb_disable_reverse_lookup, "proxy.config.hostdb.disable_reverse_lookup"); + IOCORE_EstablishStaticConfigInt32(hostdb_re_dns_on_reload, "proxy.config.hostdb.re_dns_on_reload"); + IOCORE_EstablishStaticConfigInt32(hostdb_migrate_on_demand, "proxy.config.hostdb.migrate_on_demand"); + IOCORE_EstablishStaticConfigInt32(hostdb_strict_round_robin, "proxy.config.hostdb.strict_round_robin"); + IOCORE_EstablishStaticConfigInt32(hostdb_cluster, "proxy.config.hostdb.cluster"); + IOCORE_EstablishStaticConfigInt32(hostdb_cluster_round_robin, "proxy.config.hostdb.cluster.round_robin"); + IOCORE_EstablishStaticConfigInt32(hostdb_lookup_timeout, "proxy.config.hostdb.lookup_timeout"); + IOCORE_EstablishStaticConfigInt32U(hostdb_ip_timeout_interval, "proxy.config.hostdb.timeout"); + IOCORE_EstablishStaticConfigInt32U(hostdb_ip_stale_interval, "proxy.config.hostdb.verify_after"); + IOCORE_EstablishStaticConfigInt32U(hostdb_ip_fail_timeout_interval, "proxy.config.hostdb.fail.timeout"); + IOCORE_EstablishStaticConfigInt32U(hostdb_serve_stale_but_revalidate, "proxy.config.hostdb.serve_stale_for"); + + // + // Set up hostdb_current_interval + // + hostdb_current_interval = (unsigned int) + (ink_get_based_hrtime() / HOST_DB_TIMEOUT_INTERVAL); + //hostdb_timestamp = time(NULL); + + HostDBContinuation *b = hostDBContAllocator.alloc(); + SET_CONTINUATION_HANDLER(b, (HostDBContHandler) & HostDBContinuation::backgroundEvent); + b->mutex = new_ProxyMutex(); + eventProcessor.schedule_every(b, HOST_DB_TIMEOUT_INTERVAL, ET_DNS); + + // + // Sync HostDB + // + eventProcessor.schedule_imm(NEW(new HostDBSyncer)); + return 0; +} + + +void +HostDBContinuation::init(char *hostname, int len, + int aip, int aport, INK_MD5 & amd5, Continuation * cont, void *pDS, bool is_srv, int timeout) +{ + if (hostname) { + memcpy(name, hostname, len); + name[len] = 0; + } else + name[0] = 0; + dns_lookup_timeout = timeout; + namelen = len; + is_srv_lookup = is_srv; + ip = aip; + port = aport; + md5 = amd5; + mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets)); + m_pDS = pDS; + if (cont) { + action = cont; + } else { + //ink_assert(!"this sucks"); + action.mutex = mutex; + } +} + + +void +make_md5(INK_MD5 & md5, char *hostname, int len, int port, char *pDNSServers, int srv) +{ +#ifdef USE_MMH + MMH_CTX ctx; + ink_code_incr_MMH_init(&ctx); + ink_code_incr_MMH_update(&ctx, hostname, len); + unsigned short p = port; + p = htons(p); + ink_code_incr_MMH_update(&ctx, (char *) &p, 2); + ink_code_incr_MMH_update(&ctx, (char *) &srv, 4); /* FIXME: check this */ + if (pDNSServers) + ink_code_incr_MMH_update(&ctx, pDNSServers, strlen(pDNSServers)); + ink_code_incr_MMH_final((char *) &md5, &ctx); +#else + INK_DIGEST_CTX ctx; + ink_code_incr_md5_init(&ctx); + ink_code_incr_md5_update(&ctx, hostname, len); + unsigned short p = port; + p = htons(p); + ink_code_incr_md5_update(&ctx, (char *) &p, 2); + ink_code_incr_MMH_update(&ctx, (char *) &srv, 4); /* FIXME: check this */ + if (pDNSServers) + ink_code_incr_md5_update(&ctx, pDNSServers, strlen(pDNSServers)); + ink_code_incr_md5_final((char *) &md5, &ctx); +#endif +} + + +static bool +reply_to_cont(Continuation * cont, HostDBInfo * ar) +{ + const char *reason = "none"; + HostDBInfo *r = ar; + + if (r == NULL) { + cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); + return false; + } + + if (r->failed()) { + if (r->is_srv && r->srv_count) { + cont->handleEvent(EVENT_SRV_LOOKUP, NULL); + return false; + } + cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); + return false; + } else { + if (r->reverse_dns) { + if (!r->hostname()) { + reason = "missing hostname"; + ink_assert(!"missing hostname"); + goto Lerror; + } + Debug("hostdb", "hostname = %s", r->hostname()); + } + if (r->round_robin) { + if (!r->rr()) { + reason = "missing round-robin"; + ink_assert(!"missing round-robin"); + goto Lerror; + } + Debug("hostdb", "RR of %d with %d good, 1st IP = %X", r->rr()->n, r->rr()->good, r->ip()); + } + if (r->is_srv && r->srv_count) { + cont->handleEvent(EVENT_SRV_LOOKUP, r); + if (!r->full) + goto Ldelete; + return true; + } else if (r->is_srv) { + /* failure case where this is an SRV lookup, but we got no records back -- this is handled properly in process_srv_info */ + cont->handleEvent(EVENT_SRV_LOOKUP, r); + return true; + } + cont->handleEvent(EVENT_HOST_DB_LOOKUP, r); + if (!r->full) + goto Ldelete; + return true; + } +Lerror: + if (r->is_srv && r->srv_count) { + cont->handleEvent(EVENT_SRV_LOOKUP, r); + } + cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); +Ldelete: + Warning("bogus entry deleted from HostDB: %s", reason); + hostDB.delete_block(ar); + return false; +} + + +HostDBInfo * +probe(ProxyMutex *mutex, INK_MD5 & md5, char *hostname, int len, int ip, int port, void *pDS, bool ignore_timeout, + bool is_srv_lookup) +{ + ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding); + if (hostdb_enable) { + uint64_t folded_md5 = fold_md5(md5); + HostDBInfo *r = hostDB.lookup_block(folded_md5, hostDB.levels); + Debug("hostdb", "probe %s %llX %d [ignore_timeout = %d]", hostname, folded_md5, !!r, ignore_timeout); + if (r && md5[1] == r->md5_high) { + + // Check for timeout (fail probe) + // + if (r->is_deleted()) { + Debug("hostdb", "HostDB entry was set as deleted"); + return NULL; + } else if (r->failed()) { + Debug("hostdb", "%s failed", hostname); + if (r->is_ip_fail_timeout()) { + Debug("hostdb", "fail timeout %u", r->ip_interval()); + return NULL; + } + } else if (!ignore_timeout && r->is_ip_timeout() && !r->serve_stale_but_revalidate()) { + Debug("hostdb", "timeout %u %u %u", r->ip_interval(), r->ip_timestamp, r->ip_timeout_interval); + HOSTDB_INCREMENT_DYN_STAT(hostdb_ttl_expires_stat); + return NULL; + } +//error conditions + if (r->reverse_dns && !r->hostname()) { + Debug("hostdb", "missing reverse dns"); + hostDB.delete_block(r); + return NULL; + } + if (r->round_robin && !r->rr()) { + Debug("hostdb", "missing round-robin"); + hostDB.delete_block(r); + return NULL; + } + // Check for stale (revalidate offline if we are the owner) + // -or- + // we are beyond our TTL but we choose to serve for another N seconds [hostdb_serve_stale_but_revalidate seconds] + if ((!ignore_timeout && r->is_ip_stale() +#ifdef NON_MODULAR + && !cluster_machine_at_depth(master_hash(md5)) +#endif + && !r->reverse_dns) || (r->is_ip_timeout() && r->serve_stale_but_revalidate())) { + Debug("hostdb", "stale %u %u %u, using it and refreshing it", r->ip_interval(), + r->ip_timestamp, r->ip_timeout_interval); + r->refresh_ip(); + if (!is_dotted_form_hostname(hostname)) { + HostDBContinuation *c = hostDBContAllocator.alloc(); + c->init(hostname, len, ip, port, md5, NULL, pDS, is_srv_lookup, 0); + c->do_dns(); + } + } + + r->hits++; + if (!r->hits) + r->hits--; + return r; + } + } + return NULL; +} + + +// +// Insert a HostDBInfo into the database +// A null value indicates that the block is empty. +// +HostDBInfo * +HostDBContinuation::insert(unsigned int attl) +{ + ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding); + uint64_t folded_md5 = fold_md5(md5); + // remove the old one to prevent buildup + HostDBInfo *old_r = hostDB.lookup_block(folded_md5, 3); + if (old_r) + hostDB.delete_block(old_r); + HostDBInfo *r = hostDB.insert_block(folded_md5, NULL, 0); + Debug("hostdb_insert", "inserting in bucket %d", (int) (folded_md5 % hostDB.buckets)); + r->md5_high = md5[1]; + if (attl > HOST_DB_MAX_TTL) + attl = HOST_DB_MAX_TTL; + r->ip_timeout_interval = attl; + r->ip_timestamp = hostdb_current_interval; + Debug("hostdb", "inserting for: %s: (md5: %llX) now: %u timeout: %u ttl: %u", name, folded_md5, r->ip_timestamp, + r->ip_timeout_interval, attl); + return r; +} + + +// +// Get an entry by either name or IP +// +Action * +HostDBProcessor::getby(Continuation * cont, + char *hostname, int len, int port, unsigned int ip, bool aforce_dns, int dns_lookup_timeout) +{ + INK_MD5 md5; + char *pServerLine = 0; + void *pDS = 0; + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat); + + if ((!hostdb_enable || (hostname && !*hostname)) || (hostdb_disable_reverse_lookup && ip)) { + MUTEX_TRY_LOCK(lock, cont->mutex, thread); + if (!lock) + goto Lretry; + cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); + return ACTION_RESULT_DONE; + } +#ifdef SPLIT_DNS + if (hostname && SplitDNSConfig::isSplitDNSEnabled()) { + char *scan = hostname; + for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++); + if ('\0' != *scan) { + void *pSD = (void *) SplitDNSConfig::acquire(); + if (0 != pSD) { + pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname); + + if (0 != pDS) { + pServerLine = ((DNSServer *) pDS)->x_dns_ip_line; + } + } + SplitDNSConfig::release((SplitDNS *) pSD); + } + } +#endif // SPLIT_DNS + + // if it is by name, INK_MD5 the name + // + if (hostname) { + if (!len) + len = strlen(hostname); + make_md5(md5, hostname, len, port, pServerLine); + } else { + + // INK_MD5 the ip, pad on both sizes with 0's + // so that it does not intersect the string space + // + // suvasv: Changed from this + // uint64_t dummy = ip << 16; + // to uint64_t dummy = ip*64*1024 for bug INKqa10029. + // Problem was that ip << 16 would not work for architectures with + // a different byte order. This takes cares of all byte orders. + uint64_t dummy = ((uint64_t) ip) * 64 * 1024; + md5.encodeBuffer((char *) &dummy, 8); + } + + // Attempt to find the result in-line, for level 1 hits + // + if (!aforce_dns) { + // find the partition lock + // + // TODO: Could we reuse the "mutex" above safely? I think so, but not sure. + ProxyMutex *bmutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets)); + MUTEX_TRY_LOCK(lock, bmutex, thread); + MUTEX_TRY_LOCK(lock2, cont->mutex, thread); + + // If we can get the lock and a level 1 probe succeeds, return + // + if (lock && lock2) { + HostDBInfo *r = probe(bmutex, md5, hostname, len, ip, port, pDS); + if (r) { + Debug("hostdb", "immediate answer for %s", hostname ? hostname : ""); + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat); + reply_to_cont(cont, r); + return ACTION_RESULT_DONE; + } + } + } + Debug("hostdb", "delaying force %d answer for %s", aforce_dns, hostname); + +Lretry: + // Otherwise, create a continuation to do a deeper probe in the background + // + HostDBContinuation *c = hostDBContAllocator.alloc(); + c->init(hostname, len, ip, port, md5, cont, pDS, false, dns_lookup_timeout); + c->action = cont; + c->force_dns = aforce_dns; + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent); + + // Since ProxyMutexPtr has a cast operator, gcc-3.x get upset + // about ambiguity when doing this comparison, so by reversing + // the operands, I force it to pick the cast operation /leif. + if (thread->mutex == cont->mutex) { + thread->schedule_in(c, MUTEX_RETRY_DELAY); + } else { + dnsProcessor.thread->schedule_imm(c); + } + + return &c->action; +} + + +// Wrapper from getbyname to getby +// +Action * +HostDBProcessor::getbyname_re(Continuation * cont, char *ahostname, int len, int port, int flags) +{ + bool force_dns = false; + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + + if (flags & HOSTDB_FORCE_DNS_ALWAYS) + force_dns = true; + else if (flags & HOSTDB_FORCE_DNS_RELOAD) { + force_dns = (hostdb_re_dns_on_reload ? true : false); + if (force_dns) + HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat); + } + return getby(cont, ahostname, len, port, 0, force_dns); +} + + +/* Support SRV records */ +Action * +HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info, + char *hostname, int len, int port, int flags, int dns_lookup_timeout) +{ + ink_debug_assert(cont->mutex->thread_holding == this_ethread()); + bool force_dns = false; + EThread *thread = cont->mutex->thread_holding; + ProxyMutex *mutex = thread->mutex; + + if (flags & HOSTDB_FORCE_DNS_ALWAYS) + force_dns = true; + else if (flags & HOSTDB_FORCE_DNS_RELOAD) { + force_dns = (hostdb_re_dns_on_reload ? true : false); + if (force_dns) + HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat); + } + + INK_MD5 md5; + void *pDS = 0; + + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat); + + if (!hostdb_enable || !*hostname) { + (cont->*process_srv_info) (NULL); + return ACTION_RESULT_DONE; + } + + if (!len) + len = strlen(hostname); + + make_md5(md5, hostname, len, port, 0, 1); + + // Attempt to find the result in-line, for level 1 hits + if (!force_dns) { + // find the partition lock + ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets)); + MUTEX_TRY_LOCK(lock, bucket_mutex, thread); + + // If we can get the lock and a level 1 probe succeeds, return + if (lock) { + HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, 1, port, pDS, false, true); + if (r) { + Debug("hostdb", "immediate SRV answer for %s from hostdb", hostname); + Debug("dns_srv", "immediate SRV answer for %s from hostdb", hostname); + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat); + (cont->*process_srv_info) (r); + return ACTION_RESULT_DONE; + } + } + } + + Debug("dns_srv", "delaying (force=%d) SRV answer for %s [timeout = %d]", force_dns, hostname, dns_lookup_timeout); + + // Otherwise, create a continuation to do a deeper probe in the background + HostDBContinuation *c = hostDBContAllocator.alloc(); + c->init(hostname, len, 0, port, md5, cont, pDS, true, dns_lookup_timeout); + c->force_dns = force_dns; + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent); + + if (thread->mutex == cont->mutex) { + thread->schedule_in(c, MUTEX_RETRY_DELAY); + } else { + dnsProcessor.thread->schedule_imm(c); + } + + return &c->action; +} + + +// Wrapper from getbyname to getby +// +Action * +HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn process_hostdb_info, + char *hostname, int len, int port, int flags, int dns_lookup_timeout) +{ + ink_debug_assert(cont->mutex->thread_holding == this_ethread()); + bool force_dns = false; + EThread *thread = cont->mutex->thread_holding; + ProxyMutex *mutex = thread->mutex; + + if (flags & HOSTDB_FORCE_DNS_ALWAYS) + force_dns = true; + else if (flags & HOSTDB_FORCE_DNS_RELOAD) { + force_dns = (hostdb_re_dns_on_reload ? true : false); + if (force_dns) + HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat); + } + + INK_MD5 md5; + void *pDS = 0; + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat); + + if (!hostdb_enable || !*hostname) { + (cont->*process_hostdb_info) (NULL); + return ACTION_RESULT_DONE; + } + + if (!len) + len = strlen(hostname); + +#ifdef SPLIT_DNS + if (SplitDNSConfig::isSplitDNSEnabled()) { + char *scan = hostname; + char *pServerLine = 0; + for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++); + if ('\0' != *scan) { + void *pSD = (void *) SplitDNSConfig::acquire(); + if (0 != pSD) { + pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname); + + if (0 != pDS) { + pServerLine = ((DNSServer *) pDS)->x_dns_ip_line; + } + } + SplitDNSConfig::release((SplitDNS *) pSD); + } + make_md5(md5, hostname, len, port, pServerLine); + } else +#endif // SPLIT_DNS + make_md5(md5, hostname, len, port, 0); + + // Attempt to find the result in-line, for level 1 hits + if (!force_dns) { + // find the partition lock + ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets)); + MUTEX_TRY_LOCK(lock, bucket_mutex, thread); + + // If we can get the lock and a level 1 probe succeeds, return + if (lock) { + HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, 0, port, pDS); + if (r) { + Debug("hostdb", "immediate answer for %s", hostname ? hostname : ""); + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat); + (cont->*process_hostdb_info) (r); + return ACTION_RESULT_DONE; + } + } + } + + Debug("hostdb", "delaying force %d answer for %s [timeout %d]", force_dns, hostname, dns_lookup_timeout); + + // Otherwise, create a continuation to do a deeper probe in the background + HostDBContinuation *c = hostDBContAllocator.alloc(); + c->init(hostname, len, 0, port, md5, cont, pDS, false, dns_lookup_timeout); + c->force_dns = force_dns; + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent); + + thread->schedule_in(c, MUTEX_RETRY_DELAY); + + return &c->action; +} + + +static void +do_setby(HostDBInfo * r, HostDBApplicationInfo * app, char *hostname, unsigned int ip) +{ + HostDBRoundRobin *rr = r->rr(); + + if (rr) { + ink_assert(hostname); + for (int i = 0; i < rr->n; i++) { + if (rr->info[i].ip() == ip) { + Debug("hostdb", "immediate setby for %s", hostname ? hostname : ""); + rr->info[i].app.allotment.application1 = app->allotment.application1; + rr->info[i].app.allotment.application2 = app->allotment.application2; + return; + } + } + } else { + if (r->reverse_dns || (!r->round_robin && r->ip() == ip)) { + Debug("hostdb", "immediate setby for %s", hostname ? hostname : ""); + r->app.allotment.application1 = app->allotment.application1; + r->app.allotment.application2 = app->allotment.application2; + } + } +} + + +void +HostDBProcessor::setby(char *hostname, int len, int port, unsigned int ip, HostDBApplicationInfo * app) +{ + if (!hostdb_enable) + return; + + INK_MD5 md5; + + // if it is by name, INK_MD5 the name + // + if (hostname) { + if (!len) + len = strlen(hostname); + make_md5(md5, hostname, len, port); + } else { + + // INK_MD5 the ip, pad on both sizes with 0's + // so that it does not intersect the string space + // + + // suvasv: Changed from this + // uint64_t dummy = ip << 16; + // to uint64_t dummy = ip*64*1024 for bug INKqa10029. + // Problem was that ip << 16 would not work for architectures with + // a different byte order. This takes cares of all byte orders. + uint64_t dummy = ((uint64_t) ip) * 64 * 1024; + md5.encodeBuffer((char *) &dummy, 8); + } + + // Attempt to find the result in-line, for level 1 hits + + ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets)); + EThread *thread = this_ethread(); + MUTEX_TRY_LOCK(lock, mutex, thread); + + if (lock) { + HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, 0); + if (r) + do_setby(r, app, hostname, ip); + return; + } + // Create a continuation to do a deaper probe in the background + + HostDBContinuation *c = hostDBContAllocator.alloc(); + c->init(hostname, len, ip, port, md5, NULL); + c->app.allotment.application1 = app->allotment.application1; + c->app.allotment.application2 = app->allotment.application2; + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::setbyEvent); + thread->schedule_in(c, MUTEX_RETRY_DELAY); +} + + +int +HostDBContinuation::setbyEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, 0); + + if (r) + do_setby(r, &app, name, ip); + hostdb_cont_free(this); + return EVENT_DONE; +} + + +static int +remove_round_robin(HostDBInfo * r, char *hostname, unsigned int ip) +{ + if (r) { + if (!r->round_robin) + return false; + HostDBRoundRobin *rr = r->rr(); + if (!rr) + return false; + for (int i = 0; i < rr->good; i++) { + if (rr->info[i].ip() == ip) { + Debug("hostdb", "Deleting %u.%u.%u.%u from '%s' round robin DNS entry", + ((unsigned char *) &ip)[0], ((unsigned char *) &ip)[1], + ((unsigned char *) &ip)[2], ((unsigned char *) &ip)[3], hostname); + HostDBInfo tmp = rr->info[i]; + rr->info[i] = rr->info[rr->good - 1]; + rr->info[rr->good - 1] = tmp; + rr->good--; + if (rr->good <= 0) { + hostDB.delete_block(r); + return false; + } else { + if (diags->on("hostdb")) { + int bufsize = (HOST_DB_MAX_ROUND_ROBIN_INFO * 16) * 2; + char *rr_ip_list = (char *) alloca(bufsize); + char *p = rr_ip_list; + for (int n = 0; n < rr->good; n++) { + unsigned int rr_ip = rr->info[n].ip(); + unsigned char *pip = (unsigned char *) &rr_ip; + int nbytes = snprintf(p, bufsize, "%hhu.%hhu.%hhu.%hhu ", pip[0], pip[1], pip[2], pip[3]); + p += nbytes; + bufsize -= nbytes; + } + Note("'%s' round robin DNS entry updated, entries=%d, IP list: %s", hostname, rr->good, rr_ip_list); + } + } + return true; + } + } + } + return false; +} + + +Action * +HostDBProcessor::failed_connect_on_ip_for_name(Continuation * cont, unsigned int ip, char *hostname, int len, int port) +{ + INK_MD5 md5; + char *pServerLine = 0; + void *pDS = 0; + +#ifdef SPLIT_DNS + SplitDNS *pSD = 0; + if (hostname && SplitDNSConfig::isSplitDNSEnabled()) { + pSD = SplitDNSConfig::acquire(); + + if (0 != pSD) { + pDS = pSD->getDNSRecord(hostname); + pServerLine = ((DNSServer *) pDS)->x_dns_ip_line; + } + SplitDNSConfig::release(pSD); + } +#endif // SPLIT_DNS + + make_md5(md5, hostname, len, port, pServerLine); + ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets)); + EThread *thread = this_ethread(); + MUTEX_TRY_LOCK(lock, mutex, thread); + if (lock) { + if (!hostdb_enable || NULL == pDS) { + if (cont) + cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL); + return ACTION_RESULT_DONE; + } +#ifdef SPLIT_DNS + HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, pDS); +#else + HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, 0); +#endif + bool res = (remove_round_robin(r, hostname, ip) ? true : false); + if (cont) + cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) &ip : (void *) NULL); + return ACTION_RESULT_DONE; + } + HostDBContinuation *c = hostDBContAllocator.alloc(); + c->init(hostname, len, ip, port, md5, cont, pDS); + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::removeEvent); + thread->schedule_in(c, MUTEX_RETRY_DELAY); + return &c->action; +} + + +int +HostDBContinuation::removeEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + Continuation *cont = action.continuation; + + MUTEX_TRY_LOCK(lock, cont ? (ProxyMutex *) cont->mutex : (ProxyMutex *) NULL, e->ethread); + if (!lock) { + e->schedule_in(HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + if (!action.cancelled) { + if (!hostdb_enable) { + if (cont) + cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL); + } else { + HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, m_pDS); + bool res = (remove_round_robin(r, name, ip) ? true : false); + if (cont) + cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) &ip : (void *) NULL); + } + } + hostdb_cont_free(this); + return EVENT_DONE; +} + + +// Lookup done, insert into the local table, return data to the +// calling continuation or to the calling cluster node. +// +HostDBInfo * +HostDBContinuation::lookup_done(int aip, char *aname, bool around_robin, unsigned int ttl_seconds, SRVHosts * srv) +{ + HostDBInfo *i = NULL; + + ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding); + if (!aip || !aname || !aname[0]) { + if (is_byname()) { + Debug("hostdb", "lookup_done() failed for '%s'", name); + } else if (is_srv()) { + Debug("dns_srv", "SRV failed for '%s'", name); + } else { + Debug("hostdb", "failed for %u.%u.%u.%u", + ((unsigned char *) &ip)[0], ((unsigned char *) &ip)[1], + ((unsigned char *) &ip)[2], ((unsigned char *) &ip)[3]); + } + i = insert(hostdb_ip_fail_timeout_interval); // currently ... 0 + i->round_robin = false; + i->reverse_dns = !is_byname() && !is_srv(); + } else { + switch (hostdb_ttl_mode) { + default: + ink_assert(!"bad TTL mode"); + case TTL_OBEY: + break; + case TTL_IGNORE: + ttl_seconds = hostdb_ip_timeout_interval * 60; + break; + case TTL_MIN: + if (hostdb_ip_timeout_interval * 60 < ttl_seconds) + ttl_seconds = hostdb_ip_timeout_interval * 60; + break; + case TTL_MAX: + if (hostdb_ip_timeout_interval * 60 > ttl_seconds) + ttl_seconds = hostdb_ip_timeout_interval * 60; + break; + } + HOSTDB_SUM_DYN_STAT(hostdb_ttl_stat, ttl_seconds); + if (!ttl_seconds) + ttl_seconds = 1; // www.barnsandnobel.com is lame + i = insert(ttl_seconds); + if (is_byname()) { + Debug("hostdb", "done %u.%u.%u.%u TTL %d", + ((unsigned char *) &aip)[0], ((unsigned char *) &aip)[1], + ((unsigned char *) &aip)[2], ((unsigned char *) &aip)[3], ttl_seconds); + i->ip() = aip; + i->round_robin = around_robin; + i->reverse_dns = false; + if (name != aname) { + ink_strncpy(name, aname, MAXDNAME); + } + i->is_srv = false; + } else if (is_srv()) { + + i->ip() = aip; /* this doesnt matter w. srv records -- setting to 1 so Md5 works */ + + i->reverse_dns = false; + + if (srv) { //failed case: srv == NULL + i->srv_count = srv->getCount(); + } else { + i->srv_count = 0; + } + + if (i->srv_count <= 0) { + i->round_robin = false; + } else { + i->round_robin = true; + } + + i->is_srv = true; + + if (name != aname) { + ink_strncpy(name, aname, MAXDNAME); + } + + } else { + Debug("hostdb", "done '%s' TTL %d", aname, ttl_seconds); + const size_t s_size = strlen(aname) + 1; + void *s = hostDB.alloc(&i->data.hostname_offset, s_size); + if (s) { + ink_strncpy((char *) s, aname, s_size); + i->round_robin = false; + i->reverse_dns = true; + i->is_srv = false; + } else { + ink_assert(!"out of room in hostdb data area"); + Warning("out of room in hostdb for reverse DNS data"); + hostDB.delete_block(i); + return NULL; + } + } + } +#ifdef NON_MODULAR + if (from_cont) + do_put_response(from, i, from_cont); +#endif + ink_assert(!i->round_robin || !i->reverse_dns); + return i; +} + + +int +HostDBContinuation::dnsPendingEvent(int event, Event * e) +{ + ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding); + if (timeout) { + timeout->cancel(this); + timeout = NULL; + } + if (event == EVENT_INTERVAL) { + // we timed out, return a failure to the user + MUTEX_TRY_LOCK_FOR(lock, action.mutex, ((Event *) e)->ethread, action.continuation); + if (!lock) { + timeout = eventProcessor.schedule_in(this, HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + if (!action.cancelled && action.continuation) + action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); + hostDB.pending_dns_for_hash(md5).remove(this); + hostdb_cont_free(this); + return EVENT_DONE; + } else { + SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent); + return probeEvent(EVENT_INTERVAL, NULL); + } +} + +static int +restore_info(HostDBInfo * r, HostDBInfo * old_r, HostDBInfo & old_info, HostDBRoundRobin * old_rr_data) +{ + if (old_rr_data) { + for (int j = 0; j < old_rr_data->n; j++) + if (old_rr_data->info[j].ip() == r->ip()) { + r->app = old_rr_data->info[j].app; + return true; + } + } else if (old_r) + if (old_info.ip() == r->ip()) { + r->app = old_info.app; + return true; + } + return false; +} + + +// DNS lookup result state +// +int +HostDBContinuation::dnsEvent(int event, HostEnt * e) +{ + ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding); + if (timeout) { + timeout->cancel(this); + timeout = NULL; + } + EThread *thread = mutex->thread_holding; + if (event == EVENT_INTERVAL) { + if (!action.continuation) { + // give up on insert, it has been too long + remove_trigger_pending_dns(); + hostdb_cont_free(this); + return EVENT_DONE; + } + MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation); + if (!lock) { + timeout = thread->schedule_in(this, HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + if (!action.cancelled && action.continuation) + action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); + action = NULL; + // do not exit yet, wait to see if we can insert into DB + timeout = thread->schedule_in(this, HRTIME_SECONDS(hostdb_insert_timeout)); + return EVENT_DONE; + } else { + bool failed = !e; + + bool rr; + if (is_srv()) { + rr = !failed && (e->srv_hosts.getCount() > 0); + } else + rr = !failed && e->ent.h_addr_list[1]; + + pending_action = NULL; + + ttl = failed ? 0 : e->ttl / 60; + int ttl_seconds = failed ? 0 : e->ttl; //ebalsa: moving to second accuracy + + HostDBInfo *old_r = probe(mutex, md5, name, namelen, ip, port, m_pDS, true); + HostDBInfo old_info; + if (old_r) + old_info = *old_r; + HostDBRoundRobin *old_rr_data = old_r ? old_r->rr() : NULL; + + int n = 0, nn = 0, first = -1; + if (rr) { + if (is_srv() && !failed) { + n = e->srv_hosts.getCount(); + } else { + for (; nn < HOST_DB_MAX_ROUND_ROBIN_INFO && e->ent.h_addr_list[nn]; nn++) + if (*(unsigned int *) e->ent.h_addr_list[nn]) { + if (first < 0) + first = nn; + n++; + } else + Warning("0.0.0.0 removed from round-robin list for '%s'", name); + if (first < 0) { + failed = true; + rr = false; + } + } + } else { + first = 0; + } + + HostDBInfo *r = NULL; + if (is_byname()) + r = + lookup_done(failed ? 0 : *(unsigned int *) e->ent.h_addr_list[first], name, rr, ttl_seconds, + failed ? 0 : &e->srv_hosts); + else if (is_srv()) + r = lookup_done(1, /* junk: FIXME: is the code in lookup_done() wrong to NEED this? */ + name, /* hostname */ + rr, /* is round robin, doesnt matter for SRV since we recheck getCount() inside lookup_done() */ + ttl_seconds, /* ttl in seconds */ + failed ? 0 : &e->srv_hosts); + else + r = lookup_done(failed ? 0 : ip, failed ? name : e->ent.h_name, false, ttl_seconds, failed ? 0 : &e->srv_hosts); + + if (rr) { + int s = HostDBRoundRobin::size(n, is_srv()); + HostDBRoundRobin *rr_data = (HostDBRoundRobin *) hostDB.alloc(&r->app.rr.offset, s); + Debug("hostdb", "allocating %d bytes for %d RR at %lX %d", s, n, rr_data, r->app.rr.offset); + if (rr_data) { + int i = 0, ii = 0; + if (is_srv()) { + SortableQueue *q = e->srv_hosts.getHosts(); + if (q) { + for (i = 0; i < n; i++) { + + SRV *t = q->dequeue(); + + rr_data->info[i].ip() = 1; + rr_data->info[i].round_robin = 0; + rr_data->info[i].reverse_dns = 0; + + rr_data->info[i].srv_weight = t->getWeight(); + rr_data->info[i].srv_priority = t->getPriority(); + rr_data->info[i].srv_port = t->getPort(); + + ink_strncpy(rr_data->rr_srv_hosts[i], t->getHost(), MAXDNAME); + rr_data->rr_srv_hosts[i][MAXDNAME - 1] = '\0'; + rr_data->info[i].is_srv = true; + + rr_data->info[i].full = 1; + rr_data->info[i].md5_high = r->md5_high; + rr_data->info[i].md5_low = r->md5_low; + rr_data->info[i].md5_low_low = r->md5_low_low; + SRVAllocator.free(t); + Debug("dns_srv", "inserted SRV RR record into HostDB with TTL: %d seconds", ttl_seconds); + } + } + } else { + for (; ii < nn; ii++) { + if (*(unsigned int *) e->ent.h_addr_list[ii]) { + rr_data->info[i].ip() = *(unsigned int *) e->ent.h_addr_list[ii]; + rr_data->info[i].full = 1; + rr_data->info[i].round_robin = 0; + rr_data->info[i].reverse_dns = 0; + rr_data->info[i].md5_high = r->md5_high; + rr_data->info[i].md5_low = r->md5_low; + rr_data->info[i].md5_low_low = r->md5_low_low; + if (!restore_info(&rr_data->info[i], old_r, old_info, old_rr_data)) { + rr_data->info[i].app.allotment.application1 = 0; + rr_data->info[i].app.allotment.application2 = 0; + } + i++; + } + } + } + rr_data->good = rr_data->n = n; + rr_data->current = 0; + } else { + ink_assert(!"out of room in hostdb data area"); + Warning("out of room in hostdb for round-robin DNS data"); + r->round_robin = 0; + } + } + if (!failed && !rr) + restore_info(r, old_r, old_info, old_rr_data); + ink_assert(!r || !r->round_robin || !r->reverse_dns); + ink_assert(failed || !r->round_robin || r->app.rr.offset); + +#ifdef NON_MODULAR + // if we are not the owner, put on the owner + // + ClusterMachine *m = cluster_machine_at_depth(master_hash(md5)); + if (m) + do_put_response(m, r, NULL); +#endif + + // try to callback the user + // + if (action.continuation) { + MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation); + if (!lock) { + remove_trigger_pending_dns(); + SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent); + thread->schedule_in(this, HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + if (!action.cancelled) + reply_to_cont(action.continuation, r); + } + // wake up everyone else who is waiting + remove_trigger_pending_dns(); + + // all done + // + hostdb_cont_free(this); + return EVENT_DONE; + } +} + + +#ifdef NON_MODULAR +// +// HostDB Get Message +// Used to lookup host information on a remote node in the cluster +// +struct HostDB_get_message +{ + INK_MD5 md5; + unsigned int ip; + int port; + Continuation *cont; + int namelen; + char name[MAXDNAME]; +}; + + +// +// Make a get message +// +int +HostDBContinuation::make_get_message(char *buf, int size) +{ + ink_assert(size >= (int) sizeof(HostDB_get_message)); + + HostDB_get_message *msg = (HostDB_get_message *) buf; + msg->md5 = md5; + msg->port = htonl(port); + msg->ip = htonl(ip); + msg->cont = this; + + // name + ink_strncpy(msg->name, name, sizeof(msg->name)); + + // length + int len = sizeof(HostDB_get_message) - MAXDNAME + strlen(name) + 1; + + return len; +} + + +// +// Make and send a get message +// +bool HostDBContinuation::do_get_response(Event * e) +{ + NOWARN_UNUSED(e); + if (!hostdb_cluster) + return false; + + // find an appropriate Machine + // + ClusterMachine * + m = NULL; + + if (hostdb_migrate_on_demand) + m = cluster_machine_at_depth(master_hash(md5), &probe_depth, past_probes); + else { + if (probe_depth) + return false; + m = cluster_machine_at_depth(master_hash(md5)); + probe_depth = 1; + } + + if (!m) + return false; + + // Make message + // + HostDB_get_message + msg; + memset(&msg, 0, sizeof(msg)); + int + len = make_get_message((char *) &msg, sizeof(HostDB_get_message)); + + // Setup this continuation, with a timeout + // + remoteHostDBQueue[key_partition()].enqueue(this); + SET_HANDLER((HostDBContHandler) & HostDBContinuation::clusterEvent); + timeout = mutex->thread_holding->schedule_in(this, HOST_DB_CLUSTER_TIMEOUT); + + // Send the message + // + clusterProcessor.invoke_remote(m, GET_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len); + + return true; +} + + +// +// HostDB Put Message +// This message is used in a response to a cluster node for +// Host inforamation. +// +struct HostDB_put_message +{ + INK_MD5 + md5; + unsigned int + ip; + unsigned int + ttl; + int + port; + unsigned int + missing: + 1; + unsigned int + round_robin: + 1; + Continuation * + cont; + unsigned int + application1; + unsigned int + application2; + int + namelen; + char + name[MAXDNAME]; +}; + + +// +// Build the put message +// +int +HostDBContinuation::make_put_message(HostDBInfo * r, Continuation * c, char *buf, int size) +{ + ink_assert(size >= (int) sizeof(HostDB_put_message)); + + HostDB_put_message *msg = (HostDB_put_message *) buf; + memset(msg, 0, sizeof(HostDB_put_message)); + + msg->md5 = md5; + msg->cont = c; + if (r) { + msg->ip = htonl(r->ip()); + msg->application1 = r->app.allotment.application1; + msg->application2 = r->app.allotment.application2; + msg->missing = false; + msg->round_robin = r->round_robin; + msg->ttl = r->ip_time_remaining(); + } else { + msg->missing = true; + } + + // name + ink_strncpy(msg->name, name, sizeof(msg->name)); + msg->port = port; + + // length + int len = sizeof(HostDB_put_message) - MAXDNAME + strlen(name) + 1; + + return len; +} + + +// +// Build the put message and send it +// +void +HostDBContinuation::do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * c) +{ + // don't remote fill round-robin DNS entries + // if configured not to cluster them + if (!c && r->round_robin && !hostdb_cluster_round_robin) + return; + + HostDB_put_message msg; + int len = make_put_message(r, c, (char *) &msg, sizeof(HostDB_put_message)); + + clusterProcessor.invoke_remote(m, PUT_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len); + +} +#endif // NON_MODULAR + + +// +// Probe state +// +int +HostDBContinuation::probeEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + ink_assert(!link.prev && !link.next); + EThread *t = e ? e->ethread : this_ethread(); + + MUTEX_TRY_LOCK_FOR(lock, action.mutex, t, action.continuation); + if (!lock) { + mutex->thread_holding->schedule_in(this, HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + + if (action.cancelled) { + hostdb_cont_free(this); + return EVENT_DONE; + } + + if (!hostdb_enable || (!*name && !ip)) { + if (action.continuation) + action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL); +#ifdef NON_MODULAR + if (from) + do_put_response(from, 0, from_cont); +#endif + hostdb_cont_free(this); + return EVENT_DONE; + } + + if (!force_dns) { + + // Do the probe + // + HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, m_pDS); + + if (r) + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat); + +#ifdef NON_MODULAR + if (action.continuation && r) + reply_to_cont(action.continuation, r); + + // Respond to any remote node + // + if (from) + do_put_response(from, r, from_cont); +#endif + + // If it suceeds or it was a remote probe, we are done + // + if (r || from) { + hostdb_cont_free(this); + return EVENT_DONE; + } +#ifdef NON_MODULAR + // If it failed, do a remote probe + // + if (do_get_response(e)) + return EVENT_CONT; +#endif + } + // If there are no remote nodes to probe, do a DNS lookup + // + do_dns(); + return EVENT_DONE; +} + + +int +HostDBContinuation::set_check_pending_dns() +{ + Queue &q = hostDB.pending_dns_for_hash(md5); + HostDBContinuation *c = q.head; + for (; c; c = (HostDBContinuation *) c->link.next) { + if (md5 == c->md5) { + Debug("hostdb", "enqueuing additional request"); + q.enqueue(this); + return false; + } + } + q.enqueue(this); + return true; +} + + +void +HostDBContinuation::remove_trigger_pending_dns() +{ + Queue &q = hostDB.pending_dns_for_hash(md5); + q.remove(this); + HostDBContinuation *c = q.head; + Queue qq; + while (c) { + HostDBContinuation *n = (HostDBContinuation *) c->link.next; + if (md5 == c->md5) { + Debug("hostdb", "dequeuing additional request"); + q.remove(c); + qq.enqueue(c); + } + c = n; + } + while ((c = qq.dequeue())) + c->handleEvent(EVENT_IMMEDIATE, NULL); +} + + +// +// Query the DNS processor +// +void +HostDBContinuation::do_dns() +{ + ink_assert(!action.cancelled); + if (is_byname()) { + Debug("hostdb", "DNS %s", name); + unsigned int tip = ink_inet_addr(name); + // check 127.0.0.1 format + if ((int) tip != -1) { + if (action.continuation) { + HostDBInfo *r = lookup_done(tip, name, false, HOST_DB_MAX_TTL, NULL); + reply_to_cont(action.continuation, r); + } + hostdb_cont_free(this); + return; + } + } + if (hostdb_lookup_timeout) + timeout = mutex->thread_holding->schedule_in(this, HRTIME_SECONDS(hostdb_lookup_timeout)); + else + timeout = NULL; + if (set_check_pending_dns()) { + SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsEvent); + if (is_byname()) { + DNSHandler *dnsH = 0; +#ifdef SPLIT_DNS + if (m_pDS) + dnsH = (DNSHandler *) (((DNSServer *) (m_pDS))->x_dnsH); +#endif + pending_action = dnsProcessor.gethostbyname(this, name, dnsH, dns_lookup_timeout); + } else if (is_srv()) { + DNSHandler *dnsH = 0; + Debug("dns_srv", "SRV lookup of %s", name); + pending_action = dnsProcessor.getSRVbyname(this, name, dnsH, dns_lookup_timeout); + } else { + Debug("hostdb", "DNS IP %u.%u.%u.%u", + ((unsigned char *) &ip)[0], ((unsigned char *) &ip)[1], + ((unsigned char *) &ip)[2], ((unsigned char *) &ip)[3]); + pending_action = dnsProcessor.gethostbyaddr(this, ip, dns_lookup_timeout); + } + } else { + SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsPendingEvent); + } +} + +#ifdef NON_MODULAR + + +// +// Handle the response (put message) +// +int +HostDBContinuation::clusterResponseEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + if (from_cont) { + HostDBContinuation *c; + for (c = (HostDBContinuation *) remoteHostDBQueue[key_partition()].head; c; c = (HostDBContinuation *) c->link.next) + if (c == from_cont) + break; + + // Check to see that we have not already timed out + // + if (c) { + action = c; + from_cont = 0; + MUTEX_TRY_LOCK(lock, c->mutex, e->ethread); + MUTEX_TRY_LOCK(lock2, c->action.mutex, e->ethread); + if (!lock || !lock2) { + e->schedule_in(HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + bool failed = missing || (round_robin && !hostdb_cluster_round_robin); + action.continuation->handleEvent(EVENT_HOST_DB_GET_RESPONSE, failed ? 0 : this); + } + } else { + action = 0; + // just a remote fill + ink_assert(!missing); + lookup_done(ip, name, false, ttl, NULL); + } + hostdb_cont_free(this); + return EVENT_DONE; +} + + +// +// Wait for the response (put message) +// +int +HostDBContinuation::clusterEvent(int event, Event * e) +{ + // remove ourselves from the queue + // + remoteHostDBQueue[key_partition()].remove(this); + + switch (event) { + default: + ink_assert(!"bad case"); + hostdb_cont_free(this); + return EVENT_DONE; + + // handle the put response, e is really a HostDBContinuation * + // + case EVENT_HOST_DB_GET_RESPONSE: + if (timeout) { + timeout->cancel(this); + timeout = NULL; + } + if (e) { + HostDBContinuation *c = (HostDBContinuation *) e; + HostDBInfo *r = lookup_done(c->ip, c->name, false, c->ttl, NULL); + r->app.allotment.application1 = c->app.allotment.application1; + r->app.allotment.application2 = c->app.allotment.application2; + + HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat); + + if (!action.cancelled) { + if (reply_to_cont(action.continuation, r)) { + // if we are not the owner and neither was the sender, + // fill the owner + // + if (hostdb_migrate_on_demand) { + ClusterMachine *m = cluster_machine_at_depth(master_hash(md5)); + if (m && m != c->from) + do_put_response(m, r, NULL); + } + } + } + hostdb_cont_free(this); + return EVENT_DONE; + } + return failed_cluster_request(e); + + // did not get the put message in time + // + case EVENT_INTERVAL:{ + MUTEX_TRY_LOCK_FOR(lock, action.mutex, e->ethread, action.continuation); + if (!lock) { + e->schedule_in(HOST_DB_RETRY_PERIOD); + return EVENT_CONT; + } + return failed_cluster_request(e); + } + } +} + + +int +HostDBContinuation::failed_cluster_request(Event * e) +{ + if (action.cancelled) { + hostdb_cont_free(this); + return EVENT_DONE; + } + // Attempt another remote probe + // + if (do_get_response(e)) + return EVENT_CONT; + + // Otherwise, do a DNS lookup + // + do_dns(); + return EVENT_DONE; +} + + +void +get_hostinfo_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + NOWARN_UNUSED(len); + void *pDS = 0; + HostDB_get_message *msg = (HostDB_get_message *) data; + +#ifdef SPLIT_DNS + SplitDNS *pSD = 0; + char *hostname = msg->name; + if (hostname && SplitDNSConfig::isSplitDNSEnabled()) { + pSD = SplitDNSConfig::acquire(); + + if (0 != pSD) { + pDS = pSD->getDNSRecord(hostname); + } + SplitDNSConfig::release(pSD); + } +#endif // SPLIT_DNS + + HostDBContinuation *c = hostDBContAllocator.alloc(); + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent); + c->from = from; + c->from_cont = msg->cont; + + /* ----------------------------------------- + we make a big assumption here! we presume + that all the machines in the cluster are + set to use the same configuration for + DNS servers + ----------------------------------------- */ + + + c->init(msg->name, msg->namelen, ntohl(msg->ip), ntohl(msg->port), msg->md5, NULL, pDS); + TEST(printf("get_hostinfo_ClusterFunction %s %d\n", msg->name, msg->ip)); + c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets); + c->action.mutex = c->mutex; + dnsProcessor.thread->schedule_imm(c); +} + + +void +put_hostinfo_ClusterFunction(ClusterMachine * from, void *data, int len) +{ + NOWARN_UNUSED(len); + HostDB_put_message *msg = (HostDB_put_message *) data; + HostDBContinuation *c = hostDBContAllocator.alloc(); + + SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::clusterResponseEvent); + c->init(msg->name, msg->namelen, ntohl(msg->ip), ntohl(msg->port), msg->md5, NULL); + TEST(printf("put_hostinfo_ClusterFunction %s %d\n", msg->name, msg->ip)); + c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets); + c->from_cont = msg->cont; // cannot use action if cont freed due to timeout + c->missing = msg->missing; + c->round_robin = msg->round_robin; + c->ttl = msg->ttl; + c->from = from; + dnsProcessor.thread->schedule_imm(c); +} +#endif // NON_MODULAR + + +// +// Background event +// Just increment the current_interval. Might do other stuff +// here, like move records to the current position in the cluster. +// +int +HostDBContinuation::backgroundEvent(int event, Event * e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + hostdb_current_interval++; + + return EVENT_CONT; +} + +bool HostDBInfo::match(INK_MD5 & md5, int bucket, int buckets) +{ + NOWARN_UNUSED(bucket); + if (md5[1] != md5_high) + return false; + + uint64_t folded_md5 = fold_md5(md5); + uint64_t ttag = folded_md5 / buckets; + + if (!ttag) + ttag = 1; + + struct + { + unsigned int md5_low_low:24; + unsigned int md5_low; + } tmp; + + tmp.md5_low_low = (unsigned int) ttag; + tmp.md5_low = (unsigned int) (ttag >> 24); + + return tmp.md5_low_low == md5_low_low && tmp.md5_low == md5_low; +} + + +char * +HostDBInfo::hostname() +{ + if (!reverse_dns) + return NULL; + + return (char *) hostDB.ptr(&data.hostname_offset, hostDB.ptr_to_partition((char *) this)); +} + + +HostDBRoundRobin * +HostDBInfo::rr() +{ + if (!round_robin) + return NULL; + + HostDBRoundRobin *r = (HostDBRoundRobin *) hostDB.ptr(&app.rr.offset, hostDB.ptr_to_partition((char *) this)); + + if (r && (r->n > HOST_DB_MAX_ROUND_ROBIN_INFO || r->n <= 0 || r->good > HOST_DB_MAX_ROUND_ROBIN_INFO || r->good <= 0)) { + ink_assert(!"bad round-robin"); + return NULL; + } + return r; +} + + +int +HostDBInfo::heap_size() +{ + if (reverse_dns) { + char *h = hostname(); + + if (h) + return strlen(h) + 1; + } else if (round_robin) { + HostDBRoundRobin *r = rr(); + + if (r) + // this is a bit conservative, we might want to resurect them later + return HostDBRoundRobin::size(r->n, this->is_srv); + } + return 0; +} + + +int * +HostDBInfo::heap_offset_ptr() +{ + if (reverse_dns) + return &data.hostname_offset; + + if (round_robin) + return &app.rr.offset; + + return NULL; +} + + +#ifdef NON_MODULAR +ClusterMachine * +HostDBContinuation::master_machine(ClusterConfiguration * cc) +{ + return cc->machine_hash((int) (md5[1] >> 32)); +} +#endif // NON_MODULAR + + +#ifdef NON_MODULAR +struct ShowHostDB; +typedef int (ShowHostDB::*ShowHostDBEventHandler) (int event, Event * data); +struct ShowHostDB: public ShowCont +{ + char *name; + unsigned int ip; + bool force; + + int showMain(int event, Event * e) + { + CHECK_SHOW(begin("HostDB")); + CHECK_SHOW(show("
\n" + "Lookup by name (e.g. trafficserver.apache.org):
\n" + "\n" + "
\n" + "
\n" + "Lookup by IP (e.g. 127.0.0.1):
\n" + "\n" + "
\n" + "
\n" + "Force DNS by name (e.g. trafficserver.apache.org):
\n" + "\n" "
\n")); + return complete(event, e); + } + + + int showLookup(int event, Event * e) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + SET_HANDLER(&ShowHostDB::showLookupDone); + if (name) + hostDBProcessor.getbyname_re(this, name, 0, force ? HostDBProcessor::HOSTDB_FORCE_DNS_ALWAYS : 0); + else + hostDBProcessor.getbyaddr_re(this, ip); + return EVENT_CONT; + } + + + int showOne(HostDBInfo * r, bool rr, int event, Event * e) + { + CHECK_SHOW(show("\n")); + CHECK_SHOW(show("\n", + "Type", r->round_robin ? "Round-Robin" : "", r->reverse_dns ? "Reverse DNS" : "DNS")); + CHECK_SHOW(show("\n", "App1", r->app.allotment.application1)); + CHECK_SHOW(show("\n", "App2", r->app.allotment.application2)); + if (!rr) { + CHECK_SHOW(show("\n", "Stale", r->is_ip_stale()? "Yes" : "No")); + CHECK_SHOW(show("\n", "Timed-Out", r->is_ip_timeout()? "Yes" : "No")); + CHECK_SHOW(show("\n", "TTL", r->ip_time_remaining())); + } + if (r->reverse_dns) { + CHECK_SHOW(show("\n", "Hostname", r->hostname()? r->hostname() : "")); + } else { + CHECK_SHOW(show("\n", "IP", PRINT_IP(r->ip()))); + } + CHECK_SHOW(show("
%s%s%s
%s%u
%s%u
%s%s
%s%s
%s%d
%s%s
%s%u.%u.%u.%u
\n")); + return EVENT_CONT; + } + + + int showLookupDone(int event, Event * e) + { + HostDBInfo *r = (HostDBInfo *) e; + + CHECK_SHOW(begin("HostDB Lookup")); + if (name) { + CHECK_SHOW(show("

%s

\n", name)); + } else { + CHECK_SHOW(show("

%u.%u.%u.%u

\n", PRINT_IP(ip))); + } + if (r) { + showOne(r, false, event, e); + if (r->round_robin) { + HostDBRoundRobin *rr_data = r->rr(); + if (rr_data) { + CHECK_SHOW(show("\n")); + CHECK_SHOW(show("\n", "Total", rr_data->n)); + CHECK_SHOW(show("\n", "Good", rr_data->good)); + CHECK_SHOW(show("\n", "Current", rr_data->current)); + CHECK_SHOW(show("
%s%d
%s%d
%s%d
\n")); + + for (int i = 0; i < rr_data->n; i++) + showOne(&rr_data->info[i], true, event, e); + } + } + } else { + if (name) { + CHECK_SHOW(show("

%u.%u.%u.%u Not Found

\n", PRINT_IP(ip))); + } else { + CHECK_SHOW(show("

%s Not Found

\n", name)); + } + } + return complete(event, e); + } + + +ShowHostDB(Continuation * c, HTTPHdr * h): + ShowCont(c, h), name(0), ip(0), force(0) { + SET_HANDLER(&ShowHostDB::showMain); + } +}; + +#define STR_LEN_EQ_PREFIX(_x,_l,_s) (!ptr_len_ncasecmp(_x,_l,_s,sizeof(_s)-1)) + + +static Action * +register_ShowHostDB(Continuation * c, HTTPHdr * h) +{ + ShowHostDB *s = new ShowHostDB(c, h); + int path_len; + const char *path = h->url_get()->path_get(&path_len); + + SET_CONTINUATION_HANDLER(s, &ShowHostDB::showMain); + if (STR_LEN_EQ_PREFIX(path, path_len, "ip")) { + s->force = !ptr_len_ncasecmp(path + 3, path_len - 3, "force", 5); + int query_len; + const char *query = h->url_get()->query_get(&query_len); + s->sarg = xstrndup(query, query_len); + char *gn = NULL; + if (s->sarg) + gn = (char *)memchr(s->sarg, '=', strlen(s->sarg)); + if (gn) + s->ip = ink_inet_addr(gn + 1); + SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup); + } else if (STR_LEN_EQ_PREFIX(path, path_len, "name")) { + s->force = !ptr_len_ncasecmp(path + 5, path_len - 5, "force", 5); + int query_len; + const char *query = h->url_get()->query_get(&query_len); + s->sarg = xstrndup(query, query_len); + char *gn = NULL; + if (s->sarg) + gn = (char *)memchr(s->sarg, '=', strlen(s->sarg)); + if (gn) + s->name = gn + 1; + SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup); + } + this_ethread()->schedule_imm(s); + return &s->action; +} +#endif // NON_MODULAR + + +#define HOSTDB_TEST_MAX_OUTSTANDING 100 +#define HOSTDB_TEST_LENGTH 100000 + +struct HostDBTestReverse; +typedef int (HostDBTestReverse::*HostDBTestReverseHandler) (int, void *); +struct HostDBTestReverse: public Continuation +{ + int outstanding; + int total; +#if TS_HAS_LRAND48_R + struct drand48_data dr; +#endif + + int mainEvent(int event, Event * e) + { + if (event == EVENT_HOST_DB_LOOKUP) { + HostDBInfo *i = (HostDBInfo *) e; + if (i) + printf("HostDBTestReverse: reversed %s\n", i->hostname()); + outstanding--; + } + while (outstanding < HOSTDB_TEST_MAX_OUTSTANDING && total < HOSTDB_TEST_LENGTH) + { + long l = 0; +#if TS_HAS_LRAND48_R + lrand48_r(&dr, &l); +#else + l = lrand48(); +#endif + unsigned int ip = (unsigned int) l; + outstanding++; + total++; + if (!(outstanding % 1000)) + printf("HostDBTestReverse: %d\n", total); + hostDBProcessor.getbyaddr_re(this, ip); + } + if (!outstanding) { + printf("HostDBTestReverse: done\n"); + delete this; + } + return EVENT_CONT; + } +HostDBTestReverse():Continuation(new_ProxyMutex()), outstanding(0), total(0) { + SET_HANDLER((HostDBTestReverseHandler) & HostDBTestReverse::mainEvent); +#if TS_HAS_SRAND48_R + srand48_r(time(NULL), &dr); +#else + srand48(time(NULL)); +#endif + } +}; + + +#if TS_HAS_TESTS +void +run_HostDBTest() +{ + if (is_action_tag_set("hostdb_test_rr")) + eventProcessor.schedule_every(new HostDBTestRR, HRTIME_SECONDS(1), ET_NET); + if (is_action_tag_set("hostdb_test_reverse")) { + eventProcessor.schedule_imm(new HostDBTestReverse, ET_CACHE); + } +} +#endif + + +RecRawStatBlock *hostdb_rsb; + +void +ink_hostdb_init(ModuleVersion v) +{ + static int init_called = 0; + + ink_release_assert(!checkModuleVersion(v, HOSTDB_MODULE_VERSION)); + if (init_called) + return; + + init_called = 1; + // do one time stuff + // create a stat block for HostDBStats + hostdb_rsb = RecAllocateRawStatBlock((int) HostDB_Stat_Count); + + // + // Register stats + // + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.total_entries", + RECD_INT, RECP_NULL, (int) hostdb_total_entries_stat, RecRawStatSyncCount); + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.total_lookups", + RECD_INT, RECP_NULL, (int) hostdb_total_lookups_stat, RecRawStatSyncSum); + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.total_hits", + RECD_INT, RECP_NON_PERSISTENT, (int) hostdb_total_hits_stat, RecRawStatSyncSum); + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.ttl", RECD_FLOAT, RECP_NULL, (int) hostdb_ttl_stat, RecRawStatSyncAvg); + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.ttl_expires", + RECD_INT, RECP_NULL, (int) hostdb_ttl_expires_stat, RecRawStatSyncSum); + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.re_dns_on_reload", + RECD_INT, RECP_NULL, (int) hostdb_re_dns_on_reload_stat, RecRawStatSyncSum); + + RecRegisterRawStat(hostdb_rsb, RECT_PROCESS, + "proxy.process.hostdb.bytes", RECD_INT, RECP_NULL, (int) hostdb_bytes_stat, RecRawStatSyncCount); +} diff --git a/iocore/hostdb/I_HostDB.h b/iocore/hostdb/I_HostDB.h new file mode 100644 index 00000000..32d8ff83 --- /dev/null +++ b/iocore/hostdb/I_HostDB.h @@ -0,0 +1,52 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + I_HostDB.h + + + ****************************************************************************/ + +#ifndef _I_HostDB_h_ +#define _I_HostDB_h_ + +#ifndef TS_INLINE +#define TS_INLINE +#endif + +#include "I_EventSystem.h" +#include "I_Net.h" +#include "I_Cache.h" + +#include "I_HostDBProcessor.h" + +#define HOSTDB_MODULE_MAJOR_VERSION 1 +#define HOSTDB_MODULE_MINOR_VERSION 0 +#define HOSTDB_MODULE_VERSION makeModuleVersion( \ + HOSTDB_MODULE_MAJOR_VERSION, \ + HOSTDB_MODULE_MINOR_VERSION, \ + PUBLIC_MODULE_HEADER) + +#endif /* _I_HostDB_h_ */ diff --git a/iocore/hostdb/I_HostDBProcessor.h b/iocore/hostdb/I_HostDBProcessor.h new file mode 100644 index 00000000..fd2e4591 --- /dev/null +++ b/iocore/hostdb/I_HostDBProcessor.h @@ -0,0 +1,490 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_HostDBProcessor_h_ +#define _I_HostDBProcessor_h_ + +#include "I_EventSystem.h" +#include "SRV.h" + +// Event returned on a lookup +#define EVENT_HOST_DB_LOOKUP (HOSTDB_EVENT_EVENTS_START+0) +#define EVENT_HOST_DB_IP_REMOVED (HOSTDB_EVENT_EVENTS_START+1) +#define EVENT_HOST_DB_GET_RESPONSE (HOSTDB_EVENT_EVENTS_START+2) + +#define EVENT_SRV_LOOKUP (SRV_EVENT_EVENTS_START+0) +#define EVENT_SRV_IP_REMOVED (SRV_EVENT_EVENTS_START+1) +#define EVENT_SRV_GET_RESPONSE (SRV_EVENT_EVENTS_START+2) + +#define PATH_NAME_MAX 511 +#define HOST_DB_MAX_ROUND_ROBIN_INFO 16 + +// +// Data +// +struct HostDBContinuation; + +// +// The host database stores host information, most notably the +// IP address. +// +// Since host information is relatively small, we can afford to have +// a reasonable size memory cache, and use a (relatively) sparce +// disk representation to decrease # of seeks. +// +extern int hostdb_enable; +extern unsigned int hostdb_current_interval; +extern unsigned int hostdb_ip_stale_interval; +extern unsigned int hostdb_ip_timeout_interval; +extern unsigned int hostdb_ip_fail_timeout_interval; +extern unsigned int hostdb_serve_stale_but_revalidate; + + +// +// Types +// + +// +// This structure contains the host information required by +// the application. Except for the initial fields it +// is treated as opacque by the database. +// + +union HostDBApplicationInfo +{ + struct application_data_allotment + { + unsigned int application1; + unsigned int application2; + } allotment; + + ////////////////////////////////////////////////////////// + // http server attributes in the host database // + // // + // http_version - one of HttpVersion_t // + // pipeline_max - max pipeline. (up to 127). // + // 0 - no keep alive // + // 1 - no pipeline, only keepalive // + // keep_alive_timeout - in seconds. (up to 63 seconds). // + // last_failure - UNIX time for the last time // + // we tried the server & failed // + // fail_count - Number of times we tried and // + // and failed to contact the host // + ////////////////////////////////////////////////////////// + struct http_server_attr + { + unsigned int http_version:3; + unsigned int pipeline_max:7; + unsigned int keepalive_timeout:6; + unsigned int fail_count:8; + unsigned int unused1:8; + unsigned int last_failure:32; + } http_data; + + enum HttpVersion_t + { + HTTP_VERSION_UNDEFINED = 0, + HTTP_VERSION_09 = 1, + HTTP_VERSION_10 = 2, + HTTP_VERSION_11 = 3 + }; + + struct application_data_rr + { + int offset; + } rr; +}; + +struct HostDBRoundRobin; + +struct HostDBInfo +{ + // Public Interface + unsigned int &ip() { + return data.ip; + } + + char *hostname(); + char *srvname(); + HostDBRoundRobin *rr(); + + /** Indicate that the HostDBInfo is BAD and should be deleted. */ + void bad() + { + full = 0; + } + + + /** Check the HostDBInfo or selected RR entry of a HostDBInfo is ok. */ + int ok(bool byname, HostDBInfo * rr = NULL) { + if (rr) { + if (!byname || + rr->md5_high != md5_high || + rr->md5_low != md5_low || rr->md5_low_low != md5_low_low || rr->reverse_dns || !rr->ip()) + goto Lbad; + } else if (byname) { + if (reverse_dns) + goto Lbad; + if (!ip()) + goto Lbad; + } else { + if (!reverse_dns) + goto Lbad; + if (!hostname()) + goto Lbad; + } + return 1; + Lbad: + bad(); + return 0; + } + + /** + Application specific data. NOTE: We need an integral number of these + per block. This structure is 32 bytes. (at 200k hosts = 8 Meg). Which + gives us 7 bytes of application information. + + */ + HostDBApplicationInfo app; + + unsigned int ip_interval() + { + return (hostdb_current_interval - ip_timestamp) & 0x7FFFFFFF; + } + + int ip_time_remaining() + { + return (int) ip_timeout_interval - (int) ((hostdb_current_interval - ip_timestamp) & 0x7FFFFFFF); + } + + bool is_ip_stale() { + if (ip_timeout_interval >= 2 * hostdb_ip_stale_interval) + return ip_interval() >= hostdb_ip_stale_interval; + else + return false; + } + + bool is_ip_timeout() { + return ip_interval() >= ip_timeout_interval; + } + + bool is_ip_fail_timeout() { + return ip_interval() >= hostdb_ip_fail_timeout_interval; + } + + void refresh_ip() + { + ip_timestamp = hostdb_current_interval; + } + + bool serve_stale_but_revalidate() { + // the option is disabled + if (hostdb_serve_stale_but_revalidate <= 0) + return false; + + // ip_timeout_interval == DNS TTL + // hostdb_serve_stale_but_revalidate == number of seconds + // ip_interval() is the number of seconds between now() and when the entry was inserted + if ((ip_timeout_interval + hostdb_serve_stale_but_revalidate) > ip_interval()) { + Debug("hostdb", "serving stale entry %d | %d | %d as requested by config", + ip_timeout_interval, hostdb_serve_stale_but_revalidate, ip_interval()); + return true; + } + // otherwise, the entry is too old + return false; + } + + + /** + These are the only fields which will be inserted into the + database. Any new user fields must be added to this function. + + */ + void set_from(HostDBInfo & info) + { + ip() = info.ip(); + ip_timestamp = info.ip_timestamp; + ip_timeout_interval = info.ip_timeout_interval; + round_robin = info.round_robin; + reverse_dns = info.reverse_dns; + app.allotment.application1 = info.app.allotment.application1; + app.allotment.application2 = info.app.allotment.application2; + } + + + // + // Private + // + union + { + unsigned int ip; + int hostname_offset; + // int srv_host_offset; + uint64_t dummy_pad; + } data; + + unsigned int srv_weight:16; + unsigned int srv_priority:16; + unsigned int srv_port:16; + unsigned int srv_count:15; + unsigned int is_srv:1; + + unsigned int ip_timestamp; + // limited to 0x1FFFFF (24 days) + unsigned int ip_timeout_interval; + + unsigned int full:1; + unsigned int backed:1; // duplicated in lower level + unsigned int deleted:1; + unsigned int hits:3; + + unsigned int round_robin:1; + unsigned int reverse_dns:1; + + unsigned int md5_low_low:24; + unsigned int md5_low; + + uint64_t md5_high; + + sockaddr_in6 ip6; + + bool failed() { return !ip(); } + void set_failed() { ip() = 0; } + + void set_deleted() { deleted = 1; } + bool is_deleted() const { return deleted; } + + bool is_empty() const { return !full; } + + void set_empty() + { + full = 0; + md5_high = 0; + md5_low = 0; + md5_low_low = 0; + is_srv = 0; + srv_weight = 0; + srv_priority = 0; + srv_port = 0; + srv_count = 0; + } + + void set_full(uint64_t folded_md5, int buckets) + { + uint64_t ttag = folded_md5 / buckets; + + if (!ttag) + ttag = 1; + md5_low_low = (unsigned int) ttag; + md5_low = (unsigned int) (ttag >> 24); + full = 1; + } + + void reset() + { + ip() = 0; + app.allotment.application1 = 0; + app.allotment.application2 = 0; + backed = 0; + deleted = 0; + hits = 0; + round_robin = 0; + reverse_dns = 0; + } + + uint64_t tag() { + uint64_t f = md5_low; + return (f << 24) + md5_low_low; + } + + bool match(INK_MD5 &, int, int); + int heap_size(); + int *heap_offset_ptr(); + +HostDBInfo() + : srv_weight(0), srv_priority(0), srv_port(0), srv_count(0), is_srv(0), + ip_timestamp(0), + ip_timeout_interval(0), full(0), backed(0), deleted(0), hits(0), round_robin(0), reverse_dns(0), md5_low_low(0), + md5_low(0), md5_high(0) { +#ifdef PURIFY + memset(&app, 0, sizeof(app)); +#else + app.allotment.application1 = 0; + app.allotment.application2 = 0; +#endif + ip() = 0; + + return; + } +}; + + +struct HostDBRoundRobin +{ + /** Total number (to compute space used). */ + short n; + + /** Number which have not failed a connect. */ + short good; + + unsigned short current; + + HostDBInfo info[HOST_DB_MAX_ROUND_ROBIN_INFO]; + char rr_srv_hosts[HOST_DB_MAX_ROUND_ROBIN_INFO][MAXDNAME]; + + static int size(int nn, bool using_srv) + { + if (using_srv) { + /* sizeof this struct + minus + unused round-robin entries [info] + minus + unused srv host data [rr_srv_hosts] + */ + return (int) ((sizeof(HostDBRoundRobin)) - + (sizeof(HostDBInfo) * (HOST_DB_MAX_ROUND_ROBIN_INFO - nn)) - + (sizeof(char) * MAXDNAME * (HOST_DB_MAX_ROUND_ROBIN_INFO - nn))); + } else { + return (int) (sizeof(HostDBRoundRobin) - + sizeof(HostDBInfo) * (HOST_DB_MAX_ROUND_ROBIN_INFO - nn) - + sizeof(char) * MAXDNAME * HOST_DB_MAX_ROUND_ROBIN_INFO); + } + } + + HostDBInfo *find_ip(unsigned int ip); + HostDBInfo *select_best(unsigned int client_ip, HostDBInfo * r = NULL); + + HostDBInfo *select_best_http(unsigned int client_ip, time_t now, int32_t fail_window); + + HostDBInfo *increment_round_robin() + { + bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO); + + if (bad) { + ink_assert(!"bad round robin size"); + return NULL; + } + current++; + return NULL; + } + + HostDBRoundRobin() + : n(0), good(0), current(0) + { } + +}; + +struct HostDBCache; + +// Prototype for inline completion functionf or +// getbyname_imm() +typedef void (Continuation::*process_hostdb_info_pfn) (HostDBInfo * r); +typedef void (Continuation::*process_srv_info_pfn) (HostDBInfo * r); + + +/** The Host Databse access interface. */ +struct HostDBProcessor: public Processor +{ + // Public Interface + + // Lookup Hostinfo by name + // cont->handleEvent( EVENT_HOST_DB_LOOKUP, HostDBInfo * ); on success + // cont->handleEVent( EVENT_HOST_DB_LOOKUP, 0); on failure + // Failure occurs when the host cannot be DNS-ed + // NOTE: Will call the continuation back before returning if data is in the + // cache. The HostDBInfo * becomes invalid when the callback returns. + // The HostDBInfo may be changed during the callback. + + enum + { HOSTDB_DO_NOT_FORCE_DNS = 0, + HOSTDB_ROUND_ROBIN = 0, + HOSTDB_FORCE_DNS_RELOAD = 1, + HOSTDB_FORCE_DNS_ALWAYS = 2, + HOSTDB_DO_NOT_ROUND_ROBIN = 4 + }; + + HostDBProcessor() + { } + + inkcoreapi Action *getbyname_re(Continuation * cont, char *hostname, int len = 0, int port = 0, + int flags = HOSTDB_DO_NOT_FORCE_DNS); + + Action *getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info, char *hostname, int len = 0, + int port = 0, int flags = HOSTDB_DO_NOT_FORCE_DNS, int timeout = 0); + + Action *getbyname_imm(Continuation * cont, process_hostdb_info_pfn process_hostdb_info, char *hostname, int len = 0, + int port = 0, int flags = HOSTDB_DO_NOT_FORCE_DNS, int timeout = 0); + + + /** Lookup Hostinfo by addr */ + Action *getbyaddr_re(Continuation * cont, unsigned int aip) + { + return getby(cont, NULL, 0, 0, aip, false); + } + + + /** + If you were unable to connect to an IP address associated with a + particular hostname, call this function and that IP address will + be marked "bad" and if the host is using round-robin DNS, next time + you will get a different IP address. + + */ + Action *failed_connect_on_ip_for_name(Continuation * cont, + unsigned int aip, char *hostname, int len = 0, int port = 0); + + /** Set the application information (fire-and-forget). */ + void setbyname_appinfo(char *hostname, int len, int port, HostDBApplicationInfo * app) + { + setby(hostname, len, port, 0, app); + } + + void setbyaddr_appinfo(unsigned int ip, HostDBApplicationInfo * app) + { + setby(0, 0, 0, ip, app); + } + + /** Configuration. */ + static int hostdb_strict_round_robin; + + // Processor Interface + /* hostdb does not use any dedicated event threads + * currently. Dont pass any value to start + */ + int start(int no_of_additional_event_threads = 0); + + // Private + HostDBCache *cache(); + Action *getby(Continuation * cont, char *hostname, int len, int port, + unsigned int ip, bool aforce_dns, int timeout = 0); + void setby(char *hostname, int len, int port, unsigned int aip, HostDBApplicationInfo * app); + +}; + +void run_HostDBTest(); + +extern inkcoreapi HostDBProcessor hostDBProcessor; + +void ink_hostdb_init(ModuleVersion version); + +#endif diff --git a/iocore/hostdb/Inline.cc b/iocore/hostdb/Inline.cc new file mode 100644 index 00000000..b30d4116 --- /dev/null +++ b/iocore/hostdb/Inline.cc @@ -0,0 +1,33 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Inline Functions as globals for users using only the interface + * + */ +#define TS_INLINE +#define INLINE_CC + +#include "P_HostDB.h" + + diff --git a/iocore/hostdb/Makefile.am b/iocore/hostdb/Makefile.am new file mode 100644 index 00000000..337dec14 --- /dev/null +++ b/iocore/hostdb/Makefile.am @@ -0,0 +1,50 @@ +# Makefile.am for the traffic/iocore/hostdb hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if STANDALONE_IOCORE +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records +else +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/proxy/http \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/mgmt/preparse +endif + + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +EXTRA_DIST = I_HostDB.h + +noinst_LIBRARIES = libinkhostdb.a + +libinkhostdb_a_SOURCES = \ + HostDB.cc \ + I_HostDBProcessor.h \ + MultiCache.cc \ + P_HostDB.h \ + P_HostDBProcessor.h \ + P_MultiCache.h \ + Inline.cc + diff --git a/iocore/hostdb/Makefile.in b/iocore/hostdb/Makefile.in new file mode 100644 index 00000000..4623d582 --- /dev/null +++ b/iocore/hostdb/Makefile.in @@ -0,0 +1,717 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/hostdb hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = iocore/hostdb +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinkhostdb_a_AR = $(AR) $(ARFLAGS) +libinkhostdb_a_LIBADD = +am_libinkhostdb_a_OBJECTS = HostDB.$(OBJEXT) MultiCache.$(OBJEXT) \ + Inline.$(OBJEXT) +libinkhostdb_a_OBJECTS = $(am_libinkhostdb_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinkhostdb_a_SOURCES) +DIST_SOURCES = $(libinkhostdb_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +@STANDALONE_IOCORE_FALSE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_FALSE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/lib/records \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/hdrs \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/http \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/utils \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/preparse + +@STANDALONE_IOCORE_TRUE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_TRUE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_TRUE@ -I$(top_srcdir)/lib/records + +EXTRA_DIST = I_HostDB.h +noinst_LIBRARIES = libinkhostdb.a +libinkhostdb_a_SOURCES = \ + HostDB.cc \ + I_HostDBProcessor.h \ + MultiCache.cc \ + P_HostDB.h \ + P_HostDBProcessor.h \ + P_MultiCache.h \ + Inline.cc + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/hostdb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/hostdb/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinkhostdb.a: $(libinkhostdb_a_OBJECTS) $(libinkhostdb_a_DEPENDENCIES) + -rm -f libinkhostdb.a + $(libinkhostdb_a_AR) libinkhostdb.a $(libinkhostdb_a_OBJECTS) $(libinkhostdb_a_LIBADD) + $(RANLIB) libinkhostdb.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HostDB.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiCache.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/hostdb/MultiCache.cc b/iocore/hostdb/MultiCache.cc new file mode 100644 index 00000000..c5c3616b --- /dev/null +++ b/iocore/hostdb/MultiCache.cc @@ -0,0 +1,1503 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + MultiCache.cc + + + ****************************************************************************/ + +#include "libts.h" +#include "I_Layout.h" +#ifdef NON_MODULAR +#include "P_HostDB.h" +#else +//extern const char *system_config_directory; +#endif + +#include "P_MultiCache.h" +#include "P_EventSystem.h" // FIXME: need to have this in I_* header files. + +//dxu: disable all Diags.h's functions +//#define Note + +#define MULTI_CACHE_PAUSE_TIME HRTIME_MSECONDS(1000) + +MultiCacheBase::MultiCacheBase() + : store(0), mapped_header(NULL), data(0), lowest_level_data(0), miss_stat(0), buckets_per_partitionF8(0) +{ + filename[0] = 0; + memset(hit_stat, 0, sizeof(hit_stat)); + memset(unsunk, 0, sizeof(unsunk)); + for (int i = 0; i < MULTI_CACHE_PARTITIONS; i++) + unsunk[i].mc = this; +} + +inline int +store_verify(Store *store) +{ + if (!store) + return 0; + for (int i = 0; i < store->n_disks; i++) + for (Span * sd = store->disk[i]; sd; sd = sd->link.next) { + if (!sd->file_pathname && sd->offset) + return 0; + } + return 1; +} + +MultiCacheHeader::MultiCacheHeader() + : magic(MULTI_CACHE_MAGIC_NUMBER), levels(0), + tag_bits(0), max_hits(0), elementsize(0), + buckets(0), totalelements(0), totalsize(0), nominal_elements(0), heap_size(0), heap_halfspace(0) +{ + memset(level_offset, 0, sizeof(level_offset)); + memset(bucketsize, 0, sizeof(bucketsize)); + memset(elements, 0, sizeof(elements)); + heap_used[0] = 8; + heap_used[1] = 8; + version.ink_major = MULTI_CACHE_MAJOR_VERSION; + version.ink_minor = MULTI_CACHE_MINOR_VERSION; +} + +static inline int +bytes_to_blocks(int64_t b) +{ + return (int) ((b + (STORE_BLOCK_SIZE - 1)) / STORE_BLOCK_SIZE); +} + +inline int +MultiCacheBase::blocks_in_level(int level) +{ + int64_t sumbytes = 0; + int prevblocks = 0; + int b = 0; + for (int i = 0; i <= level; i++) { + sumbytes += buckets * ((int64_t) bucketsize[i]); + int sumblocks = bytes_to_blocks(sumbytes); + b = sumblocks - prevblocks; + prevblocks = sumblocks; + } + return b; +} + +// +// Initialize MultiCache +// The outermost level of the cache contains ~aelements. +// The higher levels (lower in number) contain fewer. +// +int +MultiCacheBase::initialize(Store *astore, char *afilename, + int aelements, int abuckets, int alevels, + int level0_elements_per_bucket, + int level1_elements_per_bucket, int level2_elements_per_bucket) +{ + int64_t size = 0; + + Debug("multicache", "initializing %s with %d elements, %d buckets and %d levels", afilename, aelements, abuckets, alevels); + ink_assert(alevels < 4); + levels = alevels; + elementsize = get_elementsize(); + totalelements = 0; + nominal_elements = aelements; + buckets = abuckets; + + ink_strlcpy(filename, afilename, sizeof(filename)); + // + // Allocate level 2 as the outermost + // + if (levels > 2) { + if (!buckets) { + buckets = aelements / level2_elements_per_bucket; + if (buckets < MULTI_CACHE_PARTITIONS) + buckets = MULTI_CACHE_PARTITIONS; + } + if (levels == 3) + level2_elements_per_bucket = aelements / buckets; + elements[2] = level2_elements_per_bucket; + totalelements += buckets * level2_elements_per_bucket; + bucketsize[2] = elementsize * level2_elements_per_bucket; + size += (int64_t) bucketsize[2] * (int64_t) buckets; + + if (!(level2_elements_per_bucket / level1_elements_per_bucket)) { + Warning("Size change too large, unable to reconfigure"); + return -1; + } + + aelements /= (level2_elements_per_bucket / level1_elements_per_bucket); + } + // + // Allocate level 1 + // + if (levels > 1) { + if (!buckets) { + buckets = aelements / level1_elements_per_bucket; + if (buckets < MULTI_CACHE_PARTITIONS) + buckets = MULTI_CACHE_PARTITIONS; + } + if (levels == 2) + level1_elements_per_bucket = aelements / buckets; + elements[1] = level1_elements_per_bucket; + totalelements += buckets * level1_elements_per_bucket; + bucketsize[1] = elementsize * level1_elements_per_bucket; + size += (int64_t) bucketsize[1] * (int64_t) buckets; + if (!(level1_elements_per_bucket / level0_elements_per_bucket)) { + Warning("Size change too large, unable to reconfigure"); + return -2; + } + aelements /= (level1_elements_per_bucket / level0_elements_per_bucket); + } + // + // Allocate level 0 + // + if (!buckets) { + buckets = aelements / level0_elements_per_bucket; + if (buckets < MULTI_CACHE_PARTITIONS) + buckets = MULTI_CACHE_PARTITIONS; + } + if (levels == 1) + level0_elements_per_bucket = aelements / buckets; + elements[0] = level0_elements_per_bucket; + totalelements += buckets * level0_elements_per_bucket; + bucketsize[0] = elementsize * level0_elements_per_bucket; + size += (int64_t) bucketsize[0] * (int64_t) buckets; + + buckets_per_partitionF8 = (buckets << 8) / MULTI_CACHE_PARTITIONS; + ink_release_assert(buckets_per_partitionF8); + + unsigned int blocks = (size + (STORE_BLOCK_SIZE - 1)) / STORE_BLOCK_SIZE; + + heap_size = int ((float)totalelements * estimated_heap_bytes_per_entry()); + blocks += bytes_to_blocks(heap_size); + + blocks += 1; // header + totalsize = (int64_t) blocks *(int64_t) STORE_BLOCK_SIZE; + + Debug("multicache", "heap_size = %d, totalelements = %d, totalsize = %d", heap_size, totalelements, totalsize); + + // + // Spread alloc from the store (using storage that can be mmapped) + // + if (store) + delete store; + store = NEW(new Store); + astore->spread_alloc(*store, blocks, true); + unsigned int got = store->total_blocks(); + + if (got < blocks) { + astore->free(*store); + delete store; + store = NULL; + Warning("Configured store too small, unable to reconfigure"); + return -3; + } + totalsize = (STORE_BLOCK_SIZE) * blocks; + + level_offset[1] = buckets * bucketsize[0]; + level_offset[2] = buckets * bucketsize[1] + level_offset[1]; + + if (lowest_level_data) + delete[]lowest_level_data; + lowest_level_data = NEW(new char[lowest_level_data_size()]); + ink_assert(lowest_level_data); + memset(lowest_level_data, 0xFF, lowest_level_data_size()); + + return got; +} + +char * +MultiCacheBase::mmap_region(int blocks, int *fds, char *cur, bool private_flag, int zero_fill) +{ + if (!blocks) + return cur; + int p = 0; + char *res = 0; + for (int i = 0; i < store->n_disks; i++) { + unsigned int target = blocks / (store->n_disks - i); + unsigned int following = store->total_blocks(i + 1); + if (blocks - target > following) + target = blocks - following; + Span *ds = store->disk[i]; + for (int j = 0; j < store->disk[i]->paths(); j++) { + Span *d = ds->nth(j); + + ink_assert(d->is_mmapable()); + + if (target && d->blocks) { + int b = d->blocks; + if (d->blocks > target) + b = target; + d->blocks -= b; + unsigned int nbytes = b * STORE_BLOCK_SIZE; + int fd = fds[p] ? fds[p] : zero_fill; + ink_assert(-1 != fd); + int flags = private_flag ? MAP_PRIVATE : MAP_SHARED_MAP_NORESERVE; + + if (cur) + res = (char *) mmap(cur, nbytes, PROT_READ | PROT_WRITE, MAP_FIXED | flags, fd, d->offset * STORE_BLOCK_SIZE); + else + res = (char *) mmap(cur, nbytes, PROT_READ | PROT_WRITE, flags, fd, d->offset * STORE_BLOCK_SIZE); + + d->offset += b; + + if (res == NULL || res == (caddr_t) MAP_FAILED) + return NULL; + ink_assert(!cur || res == cur); + cur = res + nbytes; + blocks -= b; + } + p++; + } + } + return blocks ? 0 : cur; +} + +void +MultiCacheBase::reset() +{ + if (store) + delete store; + store = 0; + if (lowest_level_data) + delete[]lowest_level_data; + lowest_level_data = 0; + if (data) + unmap_data(); + data = 0; +} + +int +MultiCacheBase::unmap_data() +{ + int res = 0; + if (data) { + res = munmap(data, totalsize); + data = NULL; + return res; + } + return 0; +} + +struct zorch_info +{ + int fd; + int64_t size; + int64_t fsize; + int val; +}; + +static volatile int nzorchers = 0; + +#define MAX_ZORCH_BUFFER (1024 * 1024) + +static void * +_zorch_file(void *arg) +{ + zorch_info *info = (zorch_info *) arg; + int64_t amount; + char *vals; + + if (info) { + if ((vals = (char *) malloc(MAX_ZORCH_BUFFER)) != NULL) { + memset(vals, info->val, MAX_ZORCH_BUFFER); + while (info->fsize < info->size) { + amount = MAX_ZORCH_BUFFER; + if (amount > (info->size - info->fsize)) + amount = info->size - info->fsize; + + if (pwrite(info->fd, vals, amount, info->fsize) < 0) + break; + info->fsize += amount; + } + free(vals); + } + delete info; + ink_atomic_increment((int *) &nzorchers, -1); + } + return NULL; +} + +static int +zorch_file(char *path, int fd, int64_t size, int val) +{ + struct stat stat; + int64_t fsize; + + if (fstat(fd, &stat) < 0) { + return -1; + } + + fsize = stat.st_size; + + if (fsize != size) { + Note("file '%s' size changed from %0.2fMB to %0.2fMB", path, fsize / (1024.0 * 1024.0), size / (1024.0 * 1024.0)); + } + + if (ftruncate(fd, size) < 0) { + return -1; + } + + if (fsize < size) { + zorch_info *info; + + info = new zorch_info; + info->fd = fd; + info->size = size; + info->fsize = fsize; + info->val = val; + + ink_atomic_increment((int *) &nzorchers, 1); + // ink_thread_create (_zorch_file, (void*) info); + _zorch_file((void *) info); + } + + return 0; +} + +int +MultiCacheBase::mmap_data(bool private_flag, bool zero_fill) +{ + int fds[MULTI_CACHE_MAX_FILES] = { 0 }; + int n_fds = 0; + int i = 0; + + // open files + // + if (!store || !store->n_disks) + goto Lvalloc; + for (i = 0; i < store->n_disks; i++) { + Span *ds = store->disk[i]; + for (int j = 0; j < store->disk[i]->paths(); j++) { + char path[PATH_NAME_MAX + 1]; + Span *d = ds->nth(j); + int r = d->path(filename, NULL, path, PATH_NAME_MAX); + if (r < 0) { + Warning("filename too large '%s'", filename); + goto Labort; + } + fds[n_fds] = socketManager.open(path, O_RDWR | O_CREAT, 0644); + if (fds[n_fds] < 0) { + if (!zero_fill) { + Warning("unable to open file '%s': %d, %s", path, errno, strerror(errno)); + goto Lvalloc; + } + fds[n_fds] = 0; + } + if (!d->file_pathname) { + if (zorch_file(path, fds[n_fds], (int64_t) d->blocks * (int64_t) STORE_BLOCK_SIZE, 0)) { + Warning("unable to set file size '%s' to %" PRId64 ": %d, %s", + (int64_t) d->blocks * STORE_BLOCK_SIZE, path, errno, strerror(errno)); + goto Lvalloc; + } + } + n_fds++; + } + } + + data = 0; + + + // mmap levels + // + { + // make a copy of the store + Store tStore; + store->dup(tStore); + Store *saved = store; + store = &tStore; + + char *cur = 0; + int fd = -1; + +// find a good address to start +#if !defined(darwin) + fd = socketManager.open("/dev/zero", O_RDONLY, 0645); + if (fd < 0) { + store = saved; + Warning("unable to open /dev/zero: %d, %s", errno, strerror(errno)); + goto Labort; + } +#endif + + // lots of useless stuff +#if defined(darwin) + cur = (char *) mmap(0, totalsize, PROT_READ, MAP_SHARED_MAP_NORESERVE | MAP_ANON, -1, 0); +#else + cur = (char *) mmap(0, totalsize, PROT_READ, MAP_SHARED_MAP_NORESERVE, fd, 0); +#endif + if (cur == NULL || cur == (caddr_t) MAP_FAILED) { + store = saved; +#if defined(darwin) + Warning("unable to mmap anonymous region for %u bytes: %d, %s", totalsize, errno, strerror(errno)); +#else + Warning("unable to mmap /dev/zero for %u bytes: %d, %s", totalsize, errno, strerror(errno)); + close(fd); +#endif + goto Labort; + } + if (munmap(cur, totalsize)) { + store = saved; +#if defined(darwin) + Warning("unable to munmap anonymous region for %u bytes: %d, %s", totalsize, errno, strerror(errno)); +#else + Warning("unable to munmap /dev/zero for %u bytes: %d, %s", totalsize, errno, strerror(errno)); + close(fd); +#endif + goto Labort; + } + data = cur; + + cur = mmap_region(blocks_in_level(0), fds, cur, private_flag, fd); + if (!cur) { + store = saved; + goto Labort; + } + if (levels > 1) + cur = mmap_region(blocks_in_level(1), fds, cur, private_flag, fd); + if (!cur) { + store = saved; + goto Labort; + } + if (levels > 2) + cur = mmap_region(blocks_in_level(2), fds, cur, private_flag, fd); + if (!cur) { + store = saved; + goto Labort; + } + + if (heap_size) { + heap = cur; + cur = mmap_region(bytes_to_blocks(heap_size), fds, cur, private_flag, fd); + if (!cur) { + store = saved; + goto Labort; + } + } + mapped_header = (MultiCacheHeader *) cur; + if (!mmap_region(1, fds, cur, private_flag, fd)) { + store = saved; + goto Labort; + } +#if !defined(darwin) + ink_assert(!socketManager.close(fd)); +#endif + store = saved; + } + + + for (i = 0; i < n_fds; i++) + if (fds[i] >= 0) + ink_assert(!socketManager.close(fds[i])); + return 0; +Lvalloc: + { + if (data) + free(data); + char *cur = 0; + data = (char *) valloc(totalsize); + cur = data + STORE_BLOCK_SIZE * blocks_in_level(0); + if (levels > 1) + cur = data + STORE_BLOCK_SIZE * blocks_in_level(1); + if (levels > 2) + cur = data + STORE_BLOCK_SIZE * blocks_in_level(2); + if (heap_size) { + heap = cur; + cur += bytes_to_blocks(heap_size) * STORE_BLOCK_SIZE; + } + mapped_header = (MultiCacheHeader *) cur; + for (i = 0; i < n_fds; i++) + if (fds[i] >= 0) + socketManager.close(fds[i]); + return 0; + } +Labort: + for (i = 0; i < n_fds; i++) + if (fds[i] >= 0) + socketManager.close(fds[i]); + return -1; +} + +void +MultiCacheBase::clear() +{ + memset(data, 0, totalsize); + heap_used[0] = 8; + heap_used[1] = 8; + heap_halfspace = 0; + *mapped_header = *(MultiCacheHeader *) this; +} + +void +MultiCacheBase::clear_but_heap() +{ + memset(data, 0, totalelements * elementsize); + *mapped_header = *(MultiCacheHeader *) this; +} + +int +MultiCacheBase::read_config(const char *config_filename, Store & s, char *fn, int *pi, int *pbuck) +{ + int scratch; + char p[PATH_NAME_MAX + 1], buf[256]; + char i[PATH_NAME_MAX + 1]; + + ink_filepath_make(i, sizeof(i), system_config_directory, "internal/"); + Layout::relative_to(p, sizeof(p), i, config_filename); + + int fd =::open(p, O_RDONLY); + if (fd < 0) + return 0; + + if (ink_file_fd_readline(fd, sizeof(buf), buf) <= 0) + return -1; + // coverity[secure_coding] + if (sscanf(buf, "%d\n", pi ? pi : &scratch) != 1) + return -1; + + if (ink_file_fd_readline(fd, sizeof(buf), buf) <= 0) + return -1; + // coverity[secure_coding] + if (sscanf(buf, "%d\n", pbuck ? pbuck : &scratch) != 1) + return -1; + + if (ink_file_fd_readline(fd, sizeof(buf), buf) <= 0) + return -1; + // coverity[secure_coding] + if (sscanf(buf, "%d\n", &heap_size) != 1) + return -1; + + if (s.read(fd, fn) < 0) + return -1; + ::close(fd); + + return 1; +} + +int +MultiCacheBase::write_config(const char *config_filename, int nominal_size, int abuckets) +{ + char p[PATH_NAME_MAX + 1], buf[256]; + char i[PATH_NAME_MAX + 1]; + int fd, retcode = -1; + + ink_filepath_make(i, sizeof(i), system_config_directory, "internal/"); + Layout::relative_to(p, sizeof(p), i, config_filename); + + // XXX: Shouldn't that be 0664? + // + if ((fd =::open(p, O_CREAT | O_WRONLY | O_TRUNC, 0666)) >= 0) { + snprintf(buf, sizeof(buf) - 1, "%d\n%d\n%d\n", nominal_size, abuckets, heap_size); + buf[sizeof(buf) - 1] = 0; + if (ink_file_fd_writestring(fd, buf) != -1 && store->write(fd, filename) >= 0) + retcode = 0; + ::close(fd); + } else + Warning("unable to open '%s' for write: %d, %s", p, errno, strerror(errno)); + + return retcode; +} + +int +MultiCacheBase::open(Store *s, const char *config_filename, char *db_filename, int db_size, + bool reconfigure, bool fix, bool silent) +{ + int ret = 0; + const char *err = NULL; + char *serr = NULL; + char t_db_filename[PATH_NAME_MAX]; + int t_db_size = 0; + int t_db_buckets = 0; + int change = 0; + + t_db_filename[0] = 0; + + // Set up cache + { + Store tStore; + int res = read_config(config_filename, tStore, t_db_filename, + &t_db_size, &t_db_buckets); + ink_assert(store_verify(&tStore)); + if (res < 0) + goto LfailRead; + if (!res) { + if (!reconfigure || !db_filename || !db_size) + goto LfailConfig; + if (initialize(s, db_filename, db_size) <= 0) + goto LfailInit; + write_config(config_filename, db_size, buckets); + if (mmap_data() < 0) + goto LfailMap; + clear(); + } else { + + // don't know how to rebuild from this problem + ink_assert(!db_filename || !strcmp(t_db_filename, db_filename)); + if (!db_filename) + db_filename = t_db_filename; + + // Has the size changed? + change = (db_size >= 0) ? (db_size - t_db_size) : 0; + if (db_size < 0) + db_size = t_db_size; + if (change && !reconfigure) + goto LfailConfig; + + Store cStore; + tStore.dup(cStore); + + // Try to get back our storage + Store diff; + s->try_realloc(cStore, diff); + if (diff.n_disks && !reconfigure) + goto LfailConfig; + + // Do we need to do a reconfigure? + if (diff.n_disks || change) { + // find a new store to old the amount of space we need + + int delta = change; + if (diff.n_disks) + delta += diff.total_blocks(); + + if (delta) { + if (delta > 0) { + Store freeStore; + stealStore(freeStore, delta); + Store more; + freeStore.spread_alloc(more, delta); + if (delta > (int) more.total_blocks()) + goto LfailReconfig; + Store more_diff; + s->try_realloc(more, more_diff); + if (more_diff.n_disks) + goto LfailReconfig; + cStore.add(more); + if (more.clear(db_filename, false) < 0) + goto LfailReconfig; + } + if (delta < 0) { + Store removed; + cStore.spread_alloc(removed, -delta); + } + } + cStore.sort(); + if (initialize(&cStore, db_filename, db_size, t_db_buckets) <= 0) + goto LfailInit; + + ink_assert(store_verify(store)); + + if (write_config(config_filename, db_size, buckets) < 0) + goto LfailWrite; + + ink_assert(store_verify(store)); + + // rebuild + MultiCacheBase *old = dup(); + if (old->initialize(&tStore, t_db_filename, t_db_size, t_db_buckets) <= 0) { + delete old; + goto LfailInit; + } + + if (rebuild(*old)) { + delete old; + goto LfailRebuild; + } + ink_assert(store_verify(store)); + delete old; + + } else { + if (initialize(&tStore, db_filename, db_size, t_db_buckets) <= 0) + goto LfailFix; + ink_assert(store_verify(store)); + if (mmap_data() < 0) + goto LfailMap; + if (!verify_header()) + goto LheaderCorrupt; + *(MultiCacheHeader *) this = *mapped_header; + ink_assert(store_verify(store)); + + if (fix) + if (check(config_filename, true) < 0) + goto LfailFix; + } + } + } + if (store) + ink_assert(store_verify(store)); +Lcontinue: + return ret; + +LheaderCorrupt: + err = "header missing/corrupt"; + goto Lfail; + +LfailWrite: + err = "unable to write"; + serr = strerror(errno); + goto Lfail; + +LfailRead: + err = "unable to read"; + serr = strerror(errno); + goto Lfail; + +LfailInit: + err = "unable to initialize database (too little storage)\n"; + goto Lfail; + +LfailConfig: + err = "configuration changed"; + goto Lfail; + +LfailReconfig: + err = "unable to reconfigure"; + goto Lfail; + +LfailRebuild: + err = "unable to rebuild"; + goto Lfail; + +LfailFix: + err = "unable to fix"; + goto Lfail; + +LfailMap: + err = "unable to mmap"; + serr = strerror(errno); + goto Lfail; + +Lfail: + { + unmap_data(); + if (!silent) { + char msg[PATH_NAME_MAX + 1024]; + if (reconfigure) { + snprintf(msg, PATH_NAME_MAX + 1024, "%s: [%s] %s: disabling database\n" + "You may need to 'reconfigure' your cache manually. Please refer to\n" + "the 'Configuration' chapter in the manual.", err, config_filename, serr ? serr : ""); + } else { + snprintf(msg, PATH_NAME_MAX + 1024, "%s: [%s] %s: reinitializing database", err, config_filename, + serr ? serr : ""); + } + IOCORE_SignalWarning(REC_SIGNAL_CONFIG_ERROR, msg); + } + } + ret = -1; + goto Lcontinue; +} + +bool +MultiCacheBase::verify_header() +{ + return + mapped_header->magic == magic && + mapped_header->version.ink_major == version.ink_major && + mapped_header->version.ink_minor == version.ink_minor && + mapped_header->levels == levels && + mapped_header->tag_bits == tag_bits && + mapped_header->max_hits == max_hits && + mapped_header->elementsize == elementsize && + mapped_header->buckets == buckets && + mapped_header->level_offset[0] == level_offset[0] && + mapped_header->level_offset[1] == level_offset[1] && + mapped_header->level_offset[2] == level_offset[2] && + mapped_header->elements[0] == elements[0] && + mapped_header->elements[1] == elements[1] && + mapped_header->elements[2] == elements[2] && + mapped_header->bucketsize[0] == bucketsize[0] && + mapped_header->bucketsize[1] == bucketsize[1] && + mapped_header->bucketsize[2] == bucketsize[2] && + mapped_header->totalelements == totalelements && + mapped_header->totalsize == totalsize && mapped_header->nominal_elements == nominal_elements; +} + +void +MultiCacheBase::print_info(FILE *fp) +{ // STDIO OK + fprintf(fp, " Elements: %-10d\n", totalelements); + fprintf(fp, " Size (bytes): %-10u\n", totalsize); +} + + +// +// We need to preserve the buckets +// while moving the existing data into the new locations. +// +// if data == NULL we are rebuilding (as opposed to check or fix) +// +int +MultiCacheBase::rebuild(MultiCacheBase & old, int kind) +{ + char *new_data = 0; + + ink_assert(store_verify(store)); + ink_assert(store_verify(old.store)); + + // map in a chunk of space to use as scratch (check) + // or to copy the database to. + int fd = socketManager.open("/dev/zero", O_RDONLY); + if (fd < 0) { + Warning("unable to open /dev/zero: %d, %s", errno, strerror(errno)); + return -1; + } + + new_data = (char *) mmap(0, old.totalsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + + ink_assert(data != new_data); + if (new_data == NULL || new_data == (caddr_t) MAP_FAILED) { + Warning("unable to mmap /dev/zero for %u bytes: %d, %s", totalsize,errno, strerror(errno)); + return -1; + } + ::close(fd); + // if we are rebuilding get the original data + + if (!data) { + ink_assert(kind == MC_REBUILD); + if (old.mmap_data(true, true) < 0) + return -1; + memcpy(new_data, old.data, old.totalsize); + old.unmap_data(); + // now map the new location + if (mmap_data() < 0) + return -1; + // old.data is the copy + old.data = new_data; + } else { + ink_assert(kind == MC_REBUILD_CHECK || kind == MC_REBUILD_FIX); + if (kind == MC_REBUILD_CHECK) { + // old.data is the original, data is the copy + old.data = data; + data = new_data; + } else { + memcpy(new_data, data, old.totalsize); + // old.data is the copy, data is the original + old.data = new_data; + } + } + + ink_assert(buckets == old.buckets); + + FILE *diag_output_fp = stderr; + + RebuildMC r; + + r.data = old.data; + + r.rebuild = kind == MC_REBUILD; + r.check = kind == MC_REBUILD_CHECK; + r.fix = kind == MC_REBUILD_FIX; + + r.deleted = 0; + r.backed = 0; + r.duplicates = 0; + r.stale = 0; + r.corrupt = 0; + r.good = 0; + r.total = 0; + + if (r.rebuild) + fprintf(diag_output_fp, "New:\n"); + print_info(diag_output_fp); + if (r.rebuild || r.fix) { + fprintf(diag_output_fp, "Old:\n"); + old.print_info(diag_output_fp); + clear_but_heap(); + } + + fprintf(diag_output_fp, " [processing element.. "); + + int scan = 0; + for (int l = old.levels - 1; l >= 0; l--) + for (int b = 0; b < old.buckets; b++) { + r.partition = partition_of_bucket(b); + for (int e = 0; e < old.elements[l]; e++) { + scan++; + if (!(scan & 0x7FFF)) + fprintf(diag_output_fp, "%d ", scan); + char *x = old.data + old.level_offset[l] + b * old.bucketsize[l] + e * elementsize; + rebuild_element(b, x, r); + } + } + if (scan & 0x7FFF) + printf("done]\n"); + if (r.rebuild || r.fix) + for (int p = 0; p < MULTI_CACHE_PARTITIONS; p++) + sync_partition(p); + + fprintf(diag_output_fp, " Usage Summary\n"); + fprintf(diag_output_fp, "\tTotal: %-10d\n", r.total); + if (r.good) + fprintf(diag_output_fp, "\tGood: %.2f%% (%d)\n", r.total ? ((r.good * 100.0) / r.total) : 0, r.good); + if (r.deleted) + fprintf(diag_output_fp, "\tDeleted: %5.2f%% (%d)\n", + r.deleted ? ((r.deleted * 100.0) / r.total) : 0.0, r.deleted); + if (r.backed) + fprintf(diag_output_fp, "\tBacked: %5.2f%% (%d)\n", r.backed ? ((r.backed * 100.0) / r.total) : 0.0, r.backed); + if (r.duplicates) + fprintf(diag_output_fp, "\tDuplicates: %5.2f%% (%d)\n", + r.duplicates ? ((r.duplicates * 100.0) / r.total) : 0.0, r.duplicates); + if (r.stale) + fprintf(diag_output_fp, "\tStale: %5.2f%% (%d)\n", r.stale ? ((r.stale * 100.0) / r.total) : 0.0, r.stale); + if (r.corrupt) + fprintf(diag_output_fp, "\tCorrupt: %5.2f%% (%d)\n", + r.corrupt ? ((r.corrupt * 100.0) / r.total) : 0.0, r.corrupt); + + old.reset(); + + return 0; +} + +int +MultiCacheBase::check(const char *config_filename, bool fix) +{ + // rebuild + Store tStore; + char t_db_filename[PATH_NAME_MAX]; + t_db_filename[0] = 0; + int t_db_size = 0, t_db_buckets = 0; + if (read_config(config_filename, tStore, t_db_filename, &t_db_size, &t_db_buckets) <= 0) + return -1; + + MultiCacheBase *old = dup(); + + if (old->initialize(&tStore, filename, nominal_elements, buckets) <= 0) { + delete old; + return -1; + } + + int res = rebuild(*old, fix ? MC_REBUILD_FIX : MC_REBUILD_CHECK); + delete old; + return res; +} + +int +MultiCacheBase::sync_heap(int part) +{ + if (heap_size) { + int b_per_part = heap_size / MULTI_CACHE_PARTITIONS; + if (safe_msync(data + level_offset[2] + buckets * bucketsize[2] + + b_per_part * part, b_per_part, data + totalsize, MS_SYNC) < 0) + return -1; + } + return 0; +} + +// +// Sync a single partition +// +// Since we delete from the higher levels +// and insert into the lower levels, +// start with the higher levels to reduce the risk of duplicates. +// +int +MultiCacheBase::sync_partition(int partition) +{ + int res = 0; + int b = first_bucket_of_partition(partition); + int n = buckets_of_partition(partition); + // L3 + if (levels > 2) { + if (safe_msync(data + level_offset[2] + b * bucketsize[2], n * bucketsize[2], data + totalsize, MS_SYNC) < 0) + res = -1; + } + // L2 + if (levels > 1) { + if (safe_msync(data + level_offset[1] + b * bucketsize[1], n * bucketsize[1], data + totalsize, MS_SYNC) < 0) + res = -1; + } + // L1 + if (safe_msync(data + b * bucketsize[0], n * bucketsize[0], data + totalsize, MS_SYNC) < 0) + res = -1; + return res; +} + +int +MultiCacheBase::sync_header() +{ + *mapped_header = *(MultiCacheHeader *) this; + return safe_msync((char *) mapped_header, STORE_BLOCK_SIZE, (char *) mapped_header + STORE_BLOCK_SIZE, MS_SYNC); +} + +int +MultiCacheBase::sync_all() +{ + int res = 0, i = 0; + for (i = 0; i < MULTI_CACHE_PARTITIONS; i++) + if (sync_heap(i) < 0) + res = -1; + for (i = 0; i < MULTI_CACHE_PARTITIONS; i++) + if (sync_partition(i) < 0) + res = -1; + if (sync_header()) + res = -1; + return res; +} + +// +// Syncs MulitCache +// +struct MultiCacheSync; +typedef int (MultiCacheSync::*MCacheSyncHandler) (int, void *); +struct MultiCacheSync: public Continuation +{ + int partition; + MultiCacheBase *mc; + Continuation *cont; + int before_used; + + int heapEvent(int event, Event *e) + { + if (!partition) { + before_used = mc->heap_used[mc->heap_halfspace]; + mc->header_snap = *(MultiCacheHeader *) mc; + } + if (partition < MULTI_CACHE_PARTITIONS) + { + mc->sync_heap(partition++); + e->schedule_imm(); + return EVENT_CONT; + } + *mc->mapped_header = mc->header_snap; + ink_assert(!safe_msync((char *) mc->mapped_header, STORE_BLOCK_SIZE, + (char *) mc->mapped_header + STORE_BLOCK_SIZE, MS_SYNC)); + partition = 0; + SET_HANDLER((MCacheSyncHandler) & MultiCacheSync::mcEvent); + return mcEvent(event, e); + } + + int mcEvent(int event, Event *e) + { + (void) event; + if (partition >= MULTI_CACHE_PARTITIONS) { + cont->handleEvent(MULTI_CACHE_EVENT_SYNC, 0); + Debug("multicache", "MultiCacheSync done (%d, %d)", mc->heap_used[0], mc->heap_used[1]); + delete this; + return EVENT_DONE; + } + mc->fixup_heap_offsets(partition, before_used); + mc->sync_partition(partition); + partition++; + mutex = e->ethread->mutex; + SET_HANDLER((MCacheSyncHandler) & MultiCacheSync::pauseEvent); +#ifdef MULTI_CACHE_PAUSE_TIME + e->schedule_in(MULTI_CACHE_PAUSE_TIME); +#else + e->schedule_imm(); +#endif + return EVENT_CONT; + } + + int pauseEvent(int event, Event *e) + { + (void) event; + (void) e; + if (partition < MULTI_CACHE_PARTITIONS) + mutex = mc->locks[partition]; + else + mutex = cont->mutex; + SET_HANDLER((MCacheSyncHandler) & MultiCacheSync::mcEvent); + e->schedule_imm(); + return EVENT_CONT; + } + +MultiCacheSync(Continuation *acont, MultiCacheBase *amc): + Continuation(amc->locks[0]), partition(0), mc(amc), cont(acont), before_used(0) { + mutex = mc->locks[partition]; + SET_HANDLER((MCacheSyncHandler) & MultiCacheSync::heapEvent); + } +}; + +// +// Heap code +// + +UnsunkPtrRegistry * +MultiCacheBase::fixup_heap_offsets(int partition, int before_used, UnsunkPtrRegistry *r, int base) +{ + if (!r) + r = &unsunk[partition]; + bool found = 0; + for (int i = 0; i < r->n; i++) { + UnsunkPtr & p = r->ptrs[i]; + if (p.offset) { + Debug("multicache", "fixup p.offset %d offset %d %d part %d", + p.offset, *p.poffset, (char *) p.poffset - data, partition); + if (*p.poffset == -(i + base) - 1) { + if (halfspace_of(p.offset) != heap_halfspace) { + ink_assert(0); + *p.poffset = 0; + } else { + if (p.offset < before_used) { + *p.poffset = p.offset + 1; + ink_assert(*p.poffset); + } else + continue; + } + } else { + Debug("multicache", + "not found %d i %d base %d *p.poffset = %d, rr = %d\n", (char *) p.poffset - data, i, base, *p.poffset); + } + p.offset = 0; + p.poffset = (int *) r->next_free; + r->next_free = &p; + found = true; + } + } + if (r->next) { + int s = MULTI_CACHE_UNSUNK_PTR_BLOCK_SIZE(totalelements); + r->next = fixup_heap_offsets(partition, before_used, r->next, base + s); + } + if (!r->next && !found && r != &unsunk[partition]) { + delete r; + return NULL; + } + return r; +} + +struct OffsetTable +{ + int new_offset; + int *poffset; +}; + +struct MultiCacheHeapGC; +typedef int (MultiCacheHeapGC::*MCacheHeapGCHandler) (int, void *); +struct MultiCacheHeapGC: public Continuation +{ + Continuation *cont; + MultiCacheBase *mc; + int partition; + int n_offsets; + OffsetTable *offset_table; + + int startEvent(int event, Event *e) + { + (void) event; + if (partition < MULTI_CACHE_PARTITIONS) + { + + // copy heap data + + char *before = mc->heap + mc->heap_used[mc->heap_halfspace]; + mc->copy_heap(partition, this); + char *after = mc->heap + mc->heap_used[mc->heap_halfspace]; + + // sync new heap data and header (used) + + if (after - before > 0) + { + ink_assert(!safe_msync(before, after - before, mc->heap + mc->totalsize, MS_SYNC)); + ink_assert(!safe_msync((char *) mc->mapped_header, STORE_BLOCK_SIZE, + (char *) mc->mapped_header + STORE_BLOCK_SIZE, MS_SYNC)); + } + // update table to point to new entries + + for (int i = 0; i < n_offsets; i++) { + int *i1, i2; + // BAD CODE GENERATION ON THE ALPHA + //*(offset_table[i].poffset) = offset_table[i].new_offset + 1; + i1 = offset_table[i].poffset; + i2 = offset_table[i].new_offset + 1; + *i1 = i2; + } + n_offsets = 0; + mc->sync_partition(partition); + partition++; + if (partition < MULTI_CACHE_PARTITIONS) + mutex = mc->locks[partition]; + else + mutex = cont->mutex; +#ifdef MULTI_CACHE_PAUSE_TIME + e->schedule_in(MULTI_CACHE_PAUSE_TIME); +#else + e->schedule_imm(); +#endif + return EVENT_CONT; + } + mc->heap_used[mc->heap_halfspace ? 0 : 1] = 8; // skip 0 + cont->handleEvent(MULTI_CACHE_EVENT_SYNC, 0); + Debug("multicache", "MultiCacheHeapGC done"); + delete this; + return EVENT_DONE; + } + +MultiCacheHeapGC(Continuation *acont, MultiCacheBase *amc): + Continuation(amc->locks[0]), cont(acont), mc(amc), partition(0), n_offsets(0) { + + SET_HANDLER((MCacheHeapGCHandler) & MultiCacheHeapGC::startEvent); + offset_table = (OffsetTable *) + xmalloc(sizeof(OffsetTable) * + ((mc->totalelements / MULTI_CACHE_PARTITIONS) + mc->elements[mc->levels - 1] * 3 + 1)); + // flip halfspaces + mutex = mc->locks[partition]; + mc->heap_halfspace = mc->heap_halfspace ? 0 : 1; + } + ~MultiCacheHeapGC() { + xfree(offset_table); + } +}; + +void +MultiCacheBase::sync_partitions(Continuation *cont) +{ + // don't try to sync if we were not correctly initialized + if (data && mapped_header) { + if (heap_used[heap_halfspace] > halfspace_size() * MULTI_CACHE_HEAP_HIGH_WATER) + eventProcessor.schedule_imm(NEW(new MultiCacheHeapGC(cont, this)), ET_CALL); + else + eventProcessor.schedule_imm(NEW(new MultiCacheSync(cont, this)), ET_CALL); + } +} + +void +MultiCacheBase::copy_heap_data(char *src, int s, int *pi, int partition, MultiCacheHeapGC *gc) +{ + char *dest = (char *) alloc(NULL, s); + Debug("multicache", "copy %X to %X", src, dest); + if (dest) { + memcpy(dest, src, s); + if (*pi < 0) { // already in the unsunk ptr registry, ok to change there + UnsunkPtr *ptr = unsunk[partition].ptr(-*pi - 1); + if (ptr->poffset == pi) + ptr->offset = dest - heap; + else { + ink_assert(0); + *pi = 0; + } + } else { + gc->offset_table[gc->n_offsets].new_offset = dest - heap; + gc->offset_table[gc->n_offsets].poffset = pi; + gc->n_offsets++; + } + } else { + ink_assert(0); + *pi = 0; + } +} + +UnsunkPtrRegistry::UnsunkPtrRegistry() +:mc(NULL), n(0), ptrs(NULL), next_free(NULL), next(NULL) +{ +} + +UnsunkPtrRegistry::~UnsunkPtrRegistry() +{ + if (ptrs) + xfree(ptrs); +} + +void +UnsunkPtrRegistry::alloc_data() +{ + int bs = MULTI_CACHE_UNSUNK_PTR_BLOCK_SIZE(mc->totalelements); + size_t s = bs * sizeof(UnsunkPtr); + ptrs = (UnsunkPtr *) xmalloc(s); + for (int i = 0; i < bs; i++) { + ptrs[i].offset = 0; + ptrs[i].poffset = (int *) &ptrs[i + 1]; + } + ptrs[bs - 1].poffset = NULL; + next_free = ptrs; + n = bs; +} + +UnsunkPtr * +UnsunkPtrRegistry::alloc(int *poffset, int base) +{ + if (next_free) { + UnsunkPtr *res = next_free; + next_free = (UnsunkPtr *) next_free->poffset; + *poffset = -(base + (res - ptrs)) - 1; + ink_assert(*poffset); + return res; + } else { + if (!ptrs) { + alloc_data(); + return alloc(poffset, base); + } + if (!next) { + next = NEW(new UnsunkPtrRegistry); + next->mc = mc; + } + int s = MULTI_CACHE_UNSUNK_PTR_BLOCK_SIZE(mc->totalelements); + return next->alloc(poffset, base + s); + } +} + +void * +MultiCacheBase::alloc(int *poffset, int asize) +{ + int h = heap_halfspace; + int size = (asize + MULTI_CACHE_HEAP_ALIGNMENT - 1) & ~(MULTI_CACHE_HEAP_ALIGNMENT - 1); + int o = ink_atomic_increment((int *) &heap_used[h], size); + + if (o + size > halfspace_size()) { + ink_atomic_increment((int *) &heap_used[h], -size); + ink_assert(!"out of space"); + if (poffset) + *poffset = 0; + return NULL; + } + int offset = (h ? halfspace_size() : 0) + o; + char *p = heap + offset; + if (poffset) { + int part = ptr_to_partition((char *) poffset); + if (part < 0) + return NULL; + UnsunkPtr *up = unsunk[part].alloc(poffset); + up->offset = offset; + up->poffset = poffset; + Debug("multicache", "alloc unsunk %d at %d part %d offset %d", *poffset, (char *) poffset - data, part, offset); + } + return (void *) p; +} + +UnsunkPtr * +UnsunkPtrRegistry::ptr(int i) +{ + if (i >= n) { + if (!next) + return NULL; + else + return next->ptr(i - n); + } else { + if (!ptrs) + return NULL; + return &ptrs[i]; + } +} + +void * +MultiCacheBase::ptr(int *poffset, int partition) +{ + int o = *poffset; + Debug("multicache", "ptr %d part %d %d", (char *) poffset - data, partition, o); + if (o > 0) { + if (!valid_offset(o)) { + ink_assert(!"bad offset"); + *poffset = 0; + return NULL; + } + return (void *) (heap + o - 1); + } + if (!o) + return NULL; + UnsunkPtr *p = unsunk[partition].ptr(-o - 1); + if (!p) + return NULL; + if (p->poffset != poffset) + return NULL; + return (void *) (heap + p->offset); +} + +void +MultiCacheBase::update(int *poffset, int *old_poffset) +{ + int o = *poffset; + Debug("multicache", "updating %d %d", (char *) poffset - data, o); + if (o > 0) { + if (!valid_offset(o)) { + ink_assert(!"bad poffset"); + *poffset = 0; + } + return; + } + if (!o) + return; + + int part = ptr_to_partition((char *) poffset); + + if (part < 0) + return; + + UnsunkPtr *p = unsunk[part].ptr(-*old_poffset - 1); + if (!p || p->poffset != old_poffset) { + *poffset = 0; + return; + } + ink_assert(p->poffset != poffset); + UnsunkPtr *n = unsunk[part].alloc(poffset); + n->poffset = poffset; + n->offset = p->offset; +} + +int +MultiCacheBase::ptr_to_partition(char *ptr) +{ + int o = ptr - data; + if (o < level_offset[0]) + return -1; + if (o < level_offset[1]) + return partition_of_bucket((o - level_offset[0]) / bucketsize[0]); + if (o < level_offset[2]) + return partition_of_bucket((o - level_offset[1]) / bucketsize[1]); + if (o < level_offset[2] + elements[2] * elementsize) + return partition_of_bucket((o - level_offset[2]) / bucketsize[2]); + return -1; +} + + +void +stealStore(Store & s, int blocks) +{ + if (s.read_config()) + return; + Store tStore; + MultiCacheBase dummy; + if (dummy.read_config("hostdb.config", tStore) > 0) { + Store dStore; + s.try_realloc(tStore, dStore); + } + tStore.delete_all(); + if (dummy.read_config("dir.config", tStore) > 0) { + Store dStore; + s.try_realloc(tStore, dStore); + } + tStore.delete_all(); + if (dummy.read_config("alt.config", tStore) > 0) { + Store dStore; + s.try_realloc(tStore, dStore); + } + // grab some end portion of some block... so as not to damage the + // pool header + int d = 0; + while (d < s.n_disks) { + Span *ds = s.disk[d]; + while (ds) { + if (!blocks) + ds->blocks = 0; + else { + int b = blocks; + if ((int) ds->blocks < blocks) + b = ds->blocks; + if (ds->file_pathname) + ds->offset += (ds->blocks - b); + ds->blocks = b; + blocks -= b; + } + ds = ds->link.next; + } + d++; + } +} diff --git a/iocore/hostdb/P_HostDB.h b/iocore/hostdb/P_HostDB.h new file mode 100644 index 00000000..202d6fe1 --- /dev/null +++ b/iocore/hostdb/P_HostDB.h @@ -0,0 +1,66 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_HostDB.h + + + ****************************************************************************/ + +#ifndef _P_HostDB_h_ +#define _P_HostDB_h_ + +#ifndef INLINE_CC +#undef TS_INLINE +#define TS_INLINE inline +#endif + +#include "libts.h" + +#ifdef SPLIT_DNS +#include "P_SplitDNS.h" +#include "P_Cluster.h" +#endif + +#include "P_EventSystem.h" + +#include "I_HostDB.h" + +// HostDB files +#include "P_DNS.h" +#include "P_MultiCache.h" +#include "P_HostDBProcessor.h" + + +#undef HOSTDB_MODULE_VERSION +#define HOSTDB_MODULE_VERSION makeModuleVersion( \ + HOSTDB_MODULE_MAJOR_VERSION, \ + HOSTDB_MODULE_MINOR_VERSION, \ + PRIVATE_MODULE_HEADER) +HostDBInfo *probe(ProxyMutex * mutex, + INK_MD5 & md5, char *hostname, int len, + int ip, int port, void *pDS, bool ignore_timeout = false, bool is_srv_lookup = false); + +void make_md5(INK_MD5 & md5, char *hostname, int len, int port, char *pDNSServers = 0, int srv = 0); +#endif diff --git a/iocore/hostdb/P_HostDBProcessor.h b/iocore/hostdb/P_HostDBProcessor.h new file mode 100644 index 00000000..9460eba5 --- /dev/null +++ b/iocore/hostdb/P_HostDBProcessor.h @@ -0,0 +1,398 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + P_HostDBProcessor.h + ****************************************************************************/ + +#ifndef _P_HostDBProcessor_h_ +#define _P_HostDBProcessor_h_ + +#include "I_HostDBProcessor.h" + + +#define HOSTDB_CLIENT_IP_HASH(_client_ip,_ip) (((_client_ip >> 16)^_client_ip^_ip^(_ip>>16))&0xFFFF) + +// +// Constants +// + +#define HOST_DB_HITS_BITS 3 +#define HOST_DB_TAG_BITS 56 + +#define CONFIGURATION_HISTORY_PROBE_DEPTH 1 + +// Bump this any time hostdb format is changed +#define HOST_DB_CACHE_MAJOR_VERSION 2 +#define HOST_DB_CACHE_MINOR_VERSION 0 + +#define DEFAULT_HOST_DB_FILENAME "host.db" +#define DEFAULT_HOST_DB_SIZE (1<<14) +// Resolution of timeouts +#define HOST_DB_TIMEOUT_INTERVAL HRTIME_SECOND +// Timeout DNS every 24 hours by default if ttl_mode is enabled +#define HOST_DB_IP_TIMEOUT (24*60*60) +// DNS entries should be revalidated every 12 hours +#define HOST_DB_IP_STALE (12*60*60) +// DNS entries which failed lookup, should be revalidated every hour +#define HOST_DB_IP_FAIL_TIMEOUT (60*60) + +//#define HOST_DB_MAX_INTERVAL (0x7FFFFFFF) +#define HOST_DB_MAX_TTL (0x1FFFFF) //24 days + +// +// Constants +// + +// period to wait for a remote probe... +#define HOST_DB_CLUSTER_TIMEOUT HRTIME_MSECONDS(5000) +#define HOST_DB_RETRY_PERIOD HRTIME_MSECONDS(20) + +//#define TEST(_x) _x +#define TEST(_x) + + +#ifdef _HOSTDB_CC_ +template struct MultiCache ; +#endif /* _HOSTDB_CC_ */ + +struct ClusterMachine; +struct HostEnt; +struct ClusterConfiguration; + +// Stats +enum HostDB_Stats +{ + hostdb_total_entries_stat, + hostdb_total_lookups_stat, + hostdb_total_hits_stat, // D == total hits + hostdb_ttl_stat, // D average TTL + hostdb_ttl_expires_stat, // D == TTL Expires + hostdb_re_dns_on_reload_stat, + hostdb_bytes_stat, + HostDB_Stat_Count +}; + + +struct RecRawStatBlock; +extern RecRawStatBlock *hostdb_rsb; + +// Stat Macros + +#define HOSTDB_DEBUG_COUNT_DYN_STAT(_x, _y) \ +RecIncrRawStatCount(hostdb_rsb, mutex->thread_holding, (int)_x, _y) + +#define HOSTDB_INCREMENT_DYN_STAT(_x) \ +RecIncrRawStatSum(hostdb_rsb, mutex->thread_holding, (int)_x, 1) + +#define HOSTDB_DECREMENT_DYN_STAT(_x) \ +RecIncrRawStatSum(hostdb_rsb, mutex->thread_holding, (int)_x, -1) + +#define HOSTDB_SUM_DYN_STAT(_x, _r) \ +RecIncrRawStatSum(hostdb_rsb, mutex->thread_holding, (int)_x, _r) + +#define HOSTDB_READ_DYN_STAT(_x, _count, _sum) do {\ +RecGetRawStatSum(hostdb_rsb, (int)_x, &_sum); \ +RecGetRawStatCount(hostdb_rsb, (int)_x, &_count); \ +} while (0) + +#define HOSTDB_SET_DYN_COUNT(_x, _count) \ +RecSetRawStatCount(hostdb_rsb, _x, _count); + +#define HOSTDB_INCREMENT_THREAD_DYN_STAT(_s, _t) \ + RecIncrRawStatSum(hostdb_rsb, _t, (int) _s, 1); + +#define HOSTDB_DECREMENT_THREAD_DYN_STAT(_s, _t) \ + RecIncrRawStatSum(hostdb_rsb, _t, (int) _s, -1); + + +// +// HostDBCache (Private) +// +struct HostDBCache: public MultiCache +{ + int rebuild_callout(HostDBInfo * e, RebuildMC & r); + int start(int flags = 0); + MultiCacheBase *dup() + { + return NEW(new HostDBCache); + } + + // This accounts for an average of 2 HostDBInfo per DNS cache (for round-robin etc.) + virtual size_t estimated_heap_bytes_per_entry() const { return sizeof(HostDBInfo) * 2; } + + Queue pending_dns[MULTI_CACHE_PARTITIONS]; + Queue &pending_dns_for_hash(INK_MD5 & md5); + HostDBCache(); +}; + +inline HostDBInfo * +HostDBRoundRobin::find_ip(unsigned int ip) +{ + bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO); + if (bad) { + ink_assert(!"bad round robin size"); + return NULL; + } + + for (int i = 0; i < good; i++) { + if (ip == info[i].ip()) { + return &info[i]; + } + } + + return NULL; +} + +inline HostDBInfo * +HostDBRoundRobin::select_best(unsigned int client_ip, HostDBInfo * r) +{ + (void) r; + bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO); + if (bad) { + ink_assert(!"bad round robin size"); + return NULL; + } + int best = 0; + if (HostDBProcessor::hostdb_strict_round_robin) { + best = current++ % good; + } else { + unsigned int ip = info[0].ip(); + unsigned int best_hash = HOSTDB_CLIENT_IP_HASH(client_ip, ip); + for (int i = 1; i < good; i++) { + ip = info[i].ip(); + unsigned int h = HOSTDB_CLIENT_IP_HASH(client_ip, ip); + if (best_hash < h) { + best = i; + best_hash = h; + } + } + } + return &info[best]; +} + +inline HostDBInfo * +HostDBRoundRobin::select_best_http(unsigned int client_ip, time_t now, int32_t fail_window) +{ + bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO); + if (bad) { + ink_assert(!"bad round robin size"); + return NULL; + } + + int best_any = 0; + int best_up = -1; + + if (HostDBProcessor::hostdb_strict_round_robin) { + best_up = current++ % good; + } else { + unsigned int best_hash_any = 0; + unsigned int best_hash_up = 0; + unsigned int ip; + for (int i = 0; i < good; i++) { + ip = info[i].ip(); + unsigned int h = HOSTDB_CLIENT_IP_HASH(client_ip, ip); + if (best_hash_any <= h) { + best_any = i; + best_hash_any = h; + } + if (info[i].app.http_data.last_failure == 0 || + (unsigned int) (now - fail_window) > info[i].app.http_data.last_failure) { + // Entry is marked up + if (best_hash_up <= h) { + best_up = i; + best_hash_up = h; + } + } else { + // Entry is marked down. Make sure some nasty clock skew + // did not occur. Use the retry time to set an upper bound + // as to how far in the future we should tolerate bogus last + // failure times. This sets the upper bound that we would ever + // consider a server down to 2*down_server_timeout + if (now + fail_window < (int32_t) (info[i].app.http_data.last_failure)) { +#ifdef DEBUG + // because this region is mmaped, I cann't get anything + // useful from the structure in core files, therefore + // copy the revelvant info to the stack so it will + // be readble in the core + HostDBInfo current_info; + HostDBRoundRobin current_rr; + memcpy(¤t_info, &info[i], sizeof(HostDBInfo)); + memcpy(¤t_rr, this, sizeof(HostDBRoundRobin)); +#endif + ink_assert(!"extreme clock skew"); + info[i].app.http_data.last_failure = 0; + } + } + } + } + + if (best_up != -1) { + ink_assert(best_up >= 0 && best_up < good); + return &info[best_up]; + } else { + ink_assert(best_any >= 0 && best_any < good); + return &info[best_any]; + } +} + +// +// Types +// + +// +// Handles a HostDB lookup request +// +struct HostDBContinuation; +typedef int (HostDBContinuation::*HostDBContHandler) (int, void *); + +struct HostDBContinuation: public Continuation +{ + Action action; + unsigned int ip; + unsigned int ttl; + int port; + bool is_srv_lookup; + int dns_lookup_timeout; + INK_MD5 md5; + Event *timeout; + ClusterMachine *from; + Continuation *from_cont; + HostDBApplicationInfo app; + int probe_depth; + ClusterMachine *past_probes[CONFIGURATION_HISTORY_PROBE_DEPTH]; + int namelen; + char name[MAXDNAME]; + void *m_pDS; + Action *pending_action; + + unsigned int missing:1; + unsigned int force_dns:1; + unsigned int round_robin:1; + + int probeEvent(int event, Event * e); + int clusterEvent(int event, Event * e); + int clusterResponseEvent(int event, Event * e); + int dnsEvent(int event, HostEnt * e); + int dnsPendingEvent(int event, Event * e); + int backgroundEvent(int event, Event * e); + int retryEvent(int event, Event * e); + int removeEvent(int event, Event * e); + int setbyEvent(int event, Event * e); + + void do_dns(); + bool is_byname() + { + return ((*name && !is_srv_lookup) ? true : false); + } + bool is_srv() + { + return ((*name && is_srv_lookup) ? true : false); + } + HostDBInfo *lookup_done(int aip, char *aname, bool round_robin, unsigned int attl, SRVHosts * s = NULL); + bool do_get_response(Event * e); + void do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * cont); + int failed_cluster_request(Event * e); + int key_partition(); + void remove_trigger_pending_dns(); + int set_check_pending_dns(); + + ClusterMachine *master_machine(ClusterConfiguration * cc); + + HostDBInfo *insert(unsigned int attl); + + void init(char *hostname, int len, int aip, int port, INK_MD5 & amd5, + Continuation * cont, void *pDS = 0, bool is_srv = false, int timeout = 0); + int make_get_message(char *buf, int len); + int make_put_message(HostDBInfo * r, Continuation * c, char *buf, int len); + +HostDBContinuation(): + Continuation(NULL), ip(0), ttl(0), port(0), + is_srv_lookup(false), dns_lookup_timeout(0), + timeout(0), from(0), + from_cont(0), probe_depth(0), namelen(0), missing(false), force_dns(false), round_robin(false) { + memset(name, 0, MAXDNAME); + md5.b[0] = 0; + md5.b[1] = 0; + SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent); + } +}; + +// +// Data +// + +extern int hostdb_enable; +extern int hostdb_migrate_on_demand; +extern int hostdb_cluster; +extern int hostdb_cluster_round_robin; +extern int hostdb_lookup_timeout; +extern int hostdb_insert_timeout; +extern int hostdb_re_dns_on_reload; + +// 0 = obey, 1 = ignore, 2 = min(X,ttl), 3 = max(X,ttl) +enum +{ TTL_OBEY, TTL_IGNORE, TTL_MIN, TTL_MAX }; +extern int hostdb_ttl_mode; + +extern unsigned int hostdb_current_interval; +extern unsigned int hostdb_ip_stale_interval; +extern unsigned int hostdb_ip_timeout_interval; +extern unsigned int hostdb_ip_fail_timeout_interval; +extern int hostdb_size; +extern char hostdb_filename[PATH_NAME_MAX + 1]; + +//extern int hostdb_timestamp; +extern int hostdb_sync_frequency; +extern int hostdb_disable_reverse_lookup; + +// Static configuration information +extern HostDBCache hostDB; + +//extern Queue remoteHostDBQueue[MULTI_CACHE_PARTITIONS]; + +inline unsigned int +master_hash(INK_MD5 & md5) +{ + return (int) (md5[1] >> 32); +} + +inline bool +is_dotted_form_hostname(char *c) +{ + return -1 != (int) ink_inet_addr(c); +} + +inline Queue & +HostDBCache::pending_dns_for_hash(INK_MD5 & md5) +{ + return pending_dns[partition_of_bucket((int) (fold_md5(md5) % hostDB.buckets))]; +} + +inline int +HostDBContinuation::key_partition() +{ + return hostDB.partition_of_bucket(fold_md5(md5) % hostDB.buckets); +} + +#endif /* _P_HostDBProcessor_h_ */ diff --git a/iocore/hostdb/P_MultiCache.h b/iocore/hostdb/P_MultiCache.h new file mode 100644 index 00000000..deee6c49 --- /dev/null +++ b/iocore/hostdb/P_MultiCache.h @@ -0,0 +1,692 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + MultiCache.h + + + ****************************************************************************/ + + +#ifndef _MultiCache_h_ +#define _MultiCache_h_ + +#include "I_EventSystem.h" +#include "I_Store.h" + +#ifndef PATH_NAME_MAX +#define PATH_NAME_MAX 511 +#endif + +// +// Constants +// + +#define MULTI_CACHE_MAX_LEVELS 3 +#define MULTI_CACHE_MAX_BUCKET_SIZE 256 +#define MULTI_CACHE_MAX_FILES 256 +#define MULTI_CACHE_PARTITIONS 64 + +#define MULTI_CACHE_EVENT_SYNC MULTI_CACHE_EVENT_EVENTS_START + + +// for heap_offset() and heap_size(), indicates no data +#define MULTI_CACHE_HEAP_NONE -1 + +#define MULTI_CACHE_MAGIC_NUMBER 0x0BAD2D8 + +// Update these if there is a change to MultiCacheBase +// There is a separate HOST_DB_CACHE_[MAJOR|MINOR]_VERSION +#define MULTI_CACHE_MAJOR_VERSION 2 +#define MULTI_CACHE_MINOR_VERSION 0 + +#define MULTI_CACHE_HEAP_HIGH_WATER 0.8 + +#define MULTI_CACHE_HEAP_INITIAL sizeof(uint32_t) +#define MULTI_CACHE_HEAP_ALIGNMENT 8 + +// unused.. possible optimization +#define MULTI_CACHE_OFFSET_PARITION(_x) ((_x)%MULTI_CACHE_PARTITIONS) +#define MULTI_CACHE_OFFSET_INDEX(_x) ((_x)/MULTI_CACHE_PARTITIONS) +#define MULTI_CACHE_OFFSET(_p,_o) ((_p) + (_o) * MULTI_CACHE_PARTITIONS) + +class ProxyMutex; +class Continuation; + +// +// Types +// + +// MultiCacheBlock +// This is an abstract class which simply documents the operations +// required by the templated cache operations. + + +struct MultiCacheBlock +{ + uint64_t tag(); + bool is_deleted(); + void set_deleted(); + bool is_empty(); + void set_empty(); + void reset(); + void set_full(uint64_t folded_md5, int buckets); + int heap_size() + { + return 0; + } + int *heap_offset_ptr() + { + return NULL; + } +}; + +struct RebuildMC +{ + bool rebuild; + bool check; + bool fix; + char *data; + int partition; + + int deleted; + int backed; + int duplicates; + int corrupt; + int stale; + int good; + int total; +}; + +struct MultiCacheHeader +{ + unsigned int magic; + VersionNumber version; + + int levels; + + int tag_bits; + int max_hits; + int elementsize; + + int buckets; + int level_offset[MULTI_CACHE_MAX_LEVELS]; + int elements[MULTI_CACHE_MAX_LEVELS]; + int bucketsize[MULTI_CACHE_MAX_LEVELS]; + + int totalelements; + unsigned int totalsize; + + int nominal_elements; + + // optional heap + int heap_size; + volatile int heap_halfspace; + volatile int heap_used[2]; + + MultiCacheHeader(); +}; + +// size of block of unsunk pointers with respect to the number of +// elements +#define MULTI_CACHE_UNSUNK_PTR_BLOCK_SIZE(_e) \ + ((_e / 8) / MULTI_CACHE_PARTITIONS) + +struct UnsunkPtr +{ + int offset; + int *poffset; // doubles as freelist pointer +}; + +struct MultiCacheBase; + +struct UnsunkPtrRegistry +{ + MultiCacheBase *mc; + int n; + UnsunkPtr *ptrs; + UnsunkPtr *next_free; + UnsunkPtrRegistry *next; + + UnsunkPtr *ptr(int i); + UnsunkPtr *alloc(int *p, int base = 0); + void alloc_data(); + + UnsunkPtrRegistry(); + ~UnsunkPtrRegistry(); +}; + +// +// Broken SunCC +// +#define PtrMutex Ptr + +// +// used by windows only - to keep track +// of mapping handles +// +struct Unmaper +{ + void *hMap; + char *pAddr; +}; + +typedef int three_ints[3]; +typedef int two_ints[2]; + +struct MultiCacheHeapGC; + +struct MultiCacheBase: public MultiCacheHeader +{ + Store *store; + char filename[PATH_NAME_MAX + 1]; + MultiCacheHeader *mapped_header; + + MultiCacheHeader header_snap; + +#ifdef _WIN32 + // windows exclusive // + int m_nEntry; + Unmaper m_mUnmapTable[MULTI_CACHE_MAX_FILES]; +#endif + + // mmap-ed region + // + char *data; + char *lowest_level_data; + + // equal to data + level_offset[3] + bucketsize[3] * buckets; + char *heap; + + // interface functions + // + int halfspace_size() + { + return heap_size / 2; + } + + // Stats support + // + int hit_stat[MULTI_CACHE_MAX_LEVELS]; + int miss_stat; + + int lowest_level_data_size() + { + return (buckets + 3) / 4; + } + int lowest_level(int bucket) + { + int i = (unsigned char) lowest_level_data[bucket / 4]; + return 3 & (i >> (buckets % 4)); + } + void set_lowest_level(int bucket, int lowest) + { + unsigned char p = (unsigned char) lowest_level_data[bucket / 4]; + p &= ~(3 << (buckets % 4)); + p |= (lowest & 3) << (buckets % 4); + lowest_level_data[bucket / 4] = (char) p; + } + + // Fixed point, 8 bits shifted left + int buckets_per_partitionF8; + + int partition_of_bucket(int b) + { + return ((b << 8) + 0xFF) / buckets_per_partitionF8; + } + int first_bucket_of_partition(int p) + { + return ((buckets_per_partitionF8 * p) >> 8); + } + int last_bucket_of_partition(int p) + { + return first_bucket_of_partition(p + 1) - 1; + } + int buckets_of_partition(int p) + { + return last_bucket_of_partition(p) - first_bucket_of_partition(p) + 1; + } + + int open(Store * store, const char *config_filename, + char *db_filename = NULL, int db_size = -1, bool reconfigure = false, bool fix = false, bool silent = false); + + // 1 for success, 0 for no config file, -1 for failure + int read_config(const char *config_filename, Store & store, char *fn = NULL, int *pi = NULL, int *pbuckets = NULL); + int write_config(const char *config_filename, int nominal_size, int buckets); + int initialize(Store * store, char *filename, int elements, + int buckets = 0, int levels = 2, + int level0_elements_per_bucket = 4, + int level1_elements_per_bucket = 32, int level2_elements_per_bucket = 0); + int mmap_data(bool private_flag = false, bool zero_fill = false); + char *mmap_region(int blocks, int *fds, char *cur, bool private_flag, int zero_fill = 0); + int blocks_in_level(int level); + + bool verify_header(); + + int unmap_data(); + void reset(); + void clear(); // this zeros the data + void clear_but_heap(); + + virtual MultiCacheBase *dup() + { + ink_assert(0); + return NULL; + } + + virtual size_t estimated_heap_bytes_per_entry() const { return 0; } + + void print_info(FILE * fp); + + // + // Rebuild the database, also perform checks, and fixups + // ** cannot be called on a running system ** + // "this" must be initialized. + // +#define MC_REBUILD 0 +#define MC_REBUILD_CHECK 1 +#define MC_REBUILD_FIX 2 + int rebuild(MultiCacheBase & old, int kind = MC_REBUILD); // 0 on success + + virtual void rebuild_element(int buck, char *elem, RebuildMC & r) + { + (void) buck; + (void) elem; + (void) r; + ink_assert(0); + } + + // + // Check the database + // ** cannot be called on a running system ** + // assumes that the configuration is correct + // + int check(const char *config_filename, bool fix = false); + + ProxyMutex *lock_for_bucket(int bucket) + { + return locks[partition_of_bucket(bucket)]; + } + uint64_t make_tag(uint64_t folded_md5) + { + uint64_t ttag = folded_md5 / (uint64_t) buckets; +#if !defined (_WIN32) + if (!ttag) + return 1LL; +#else + if (!ttag) + return 1i 64; +#endif + // beeping gcc 2.7.2 is broken + if (tag_bits > 32) { + uint64_t mask = 0x100000000LL << (tag_bits - 32); + mask = mask - 1; + return ttag & mask; + } else { +#if !defined (_WIN32) + uint64_t mask = 1LL; +#else + uint64_t mask = 1i 64; +#endif + mask <<= tag_bits; + mask = mask - 1; + return ttag & mask; + } + } + + int sync_all(); + int sync_heap(int part); // part varies between 0 and MULTI_CACHE_PARTITIONS + int sync_header(); + int sync_partition(int partition); + void sync_partitions(Continuation * cont); + + MultiCacheBase(); + virtual ~ MultiCacheBase() { + reset(); + } + + virtual int get_elementsize() + { + ink_assert(0); + return 0; + } + + // Heap support + UnsunkPtrRegistry unsunk[MULTI_CACHE_PARTITIONS]; + + // -1 on error + int ptr_to_partition(char *); + // the user must pass in the offset field within the + // MultiCacheBlock object. The offset will be inserted + // into the object on success and a pointer to the data + // returned. On failure, NULL is returned; + void *alloc(int *poffset, int size); + void update(int *poffset, int *old_poffset); + void *ptr(int *poffset, int partition); + int valid_offset(int offset) + { + int max; + if (offset < halfspace_size()) + max = heap_used[0]; + else + max = halfspace_size() + heap_used[1]; + return offset < max; + } + int valid_heap_pointer(char *p) + { + if (p < heap + halfspace_size()) + return p < heap + heap_used[0]; + else + return p < heap + halfspace_size() + heap_used[1]; + } + void copy_heap_data(char *src, int s, int *pi, int partition, MultiCacheHeapGC * gc); + int halfspace_of(int o) + { + return o < halfspace_size()? 0 : 1; + } + UnsunkPtrRegistry *fixup_heap_offsets(int partition, int before_used, UnsunkPtrRegistry * r = NULL, int base = 0); + + virtual void copy_heap(int partition, MultiCacheHeapGC * gc) + { + (void) partition; + (void) gc; + } + + // + // Private + // + void alloc_mutexes() + { + for (int i = 0; i < MULTI_CACHE_PARTITIONS; i++) + locks[i] = new_ProxyMutex(); + } + PtrMutex locks[MULTI_CACHE_PARTITIONS]; // 1 lock per (buckets/partitions) +}; + +template struct MultiCache: public MultiCacheBase +{ + int get_elementsize() + { + return sizeof(C); + } + + MultiCacheBase *dup() + { + return NEW(new MultiCache); + } + + void rebuild_element(int buck, char *elem, RebuildMC & r); + // -1 is corrupt, 0 == void (do not insert), 1 is OK + virtual int rebuild_callout(C * c, RebuildMC & r) + { + (void) c; + (void) r; + return 1; + } + + virtual void rebuild_insert_callout(C * c, RebuildMC & r) + { + (void) c; + (void) r; + } + + // + // template operations + // + int level_of_block(C * b); + bool match(uint64_t folded_md5, C * block); + C *cache_bucket(uint64_t folded_md5, int level); + C *insert_block(uint64_t folded_md5, C * new_block, int level); + void flush(C * b, int bucket, int level); + void delete_block(C * block); + C *lookup_block(uint64_t folded_md5, int level); + void copy_heap(int paritition, MultiCacheHeapGC *); +}; + +inline uint64_t +fold_md5(INK_MD5 & md5) +{ + return (md5.fold()); +} + +template inline int MultiCache::level_of_block(C * b) +{ + if ((char *) b - data >= level_offset[1]) { + if ((char *) b - data >= level_offset[2]) + return 2; + return 1; + } + return 0; +} + +template inline C * MultiCache::cache_bucket(uint64_t folded_md5, int level) +{ + int bucket = (int) (folded_md5 % buckets); + char *offset = data + level_offset[level] + bucketsize[level] * bucket; + return (C *) offset; +} + +// +// Insert an entry +// +template inline C * MultiCache::insert_block(uint64_t folded_md5, C * new_block, int level) +{ + C *b = cache_bucket(folded_md5, level); + C *block = NULL, *empty = NULL; + int bucket = (int) (folded_md5 % buckets); + int hits = 0; + + // Find the entry + // + uint64_t tag = make_tag(folded_md5); + int n_empty = 0; + + for (block = b; block < b + elements[level]; block++) { + if (block->is_empty() && !empty) { + n_empty++; + empty = block; + } + if (tag == block->tag()) + goto Lfound; + hits += block->hits; + } + if (empty) { + block = empty; + goto Lfound; + } + + { + C *best = NULL; + int again = 1; + do { + // Find an entry previously backed to a higher level. + // self scale the hits number within the bucket + // + unsigned int dec = 0; + if (hits > ((max_hits / 2) + 1) * elements[level]) + dec = 1; + for (block = b; block < b + elements[level]; block++) { + if (block->backed && (!best || best->hits > block->hits)) + best = block; + if (block->hits) + block->hits -= dec; + } + if (best) { + block = best; + goto Lfound; + } + flush(b, bucket, level); + } while (again--); + ink_assert(!"cache flush failure"); + } + +Lfound: + if (new_block) { + *block = *new_block; + int *hop = new_block->heap_offset_ptr(); + if (hop) + update(block->heap_offset_ptr(), hop); + block->backed = 0; + } else + block->reset(); + block->set_full(folded_md5, buckets); + ink_assert(block->tag() == tag); + return block; +} + +#define REBUILD_FOLDED_MD5(_cl) \ +((_cl->tag() * (uint64_t)buckets + (uint64_t)bucket)) + +// +// This function ejects some number of entries. +// +template inline void MultiCache::flush(C * b, int bucket, int level) +{ + C *block = NULL; + if (level < levels - 1) { + if (level >= lowest_level(bucket)) + set_lowest_level(bucket, level + 1); + for (block = b; block < b + elements[level]; block++) { + ink_assert(!block->is_empty()); + insert_block(REBUILD_FOLDED_MD5(block), block, level + 1); + block->backed = true; + } + } else { + for (block = b; block < b + elements[level]; block++) + if (!block->is_empty()) + block->backed = true; + } +} + +// +// Match a cache line and a folded md5 key +// +template inline bool MultiCache::match(uint64_t folded_md5, C * block) +{ + return block->tag() == make_tag(folded_md5); +} + +// +// This code is a bit of a mess and should probably be rewritten +// +template inline void MultiCache::delete_block(C * b) +{ + if (b->backed) { + int l = level_of_block(b); + if (l < levels - 1) { + int bucket = (((char *) b - data) - level_offset[l]) / bucketsize[l]; + C *x = (C *) (data + level_offset[l + 1] + bucket * bucketsize[l + 1]); + for (C * y = x; y < x + elements[l + 1]; y++) + if (b->tag() == y->tag()) + delete_block(y); + } + } + b->set_empty(); +} + +// +// Lookup an entry up to some level in the cache +// +template inline C * MultiCache::lookup_block(uint64_t folded_md5, int level) +{ + C *b = cache_bucket(folded_md5, 0); + uint64_t tag = make_tag(folded_md5); + int i = 0; + // Level 0 + for (i = 0; i < elements[0]; i++) + if (tag == b[i].tag()) + return &b[i]; + if (level <= 0) + return NULL; + // Level 1 + b = cache_bucket(folded_md5, 1); + for (i = 0; i < elements[1]; i++) + if (tag == b[i].tag()) + return &b[i]; + if (level <= 1) + return NULL; + // Level 2 + b = cache_bucket(folded_md5, 2); + for (i = 0; i < elements[2]; i++) + if (tag == b[i].tag()) + return &b[i]; + return NULL; +} + +template inline void MultiCache::rebuild_element(int bucket, char *elem, RebuildMC & r) +{ + C *e = (C *) elem; + if (!e->is_empty()) { + r.total++; + if (e->is_deleted()) + r.deleted++; + if (e->backed) + r.backed++; + int res = rebuild_callout(e, r); + if (res < 0) + r.corrupt++; + else if (!res) + r.stale++; + else { + r.good++; + if (lookup_block(REBUILD_FOLDED_MD5(e), levels - 1)) + if (!e->backed) + r.duplicates++; + C *new_e = insert_block(REBUILD_FOLDED_MD5(e), e, 0); + rebuild_insert_callout(new_e, r); + } + } +} + +template inline void MultiCache::copy_heap(int partition, MultiCacheHeapGC * gc) +{ + int b = first_bucket_of_partition(partition); + int n = buckets_of_partition(partition); + for (int level = 0; level < levels; level++) { + int e = n * elements[level]; + char *d = data + level_offset[level] + b * bucketsize[level]; + C *x = (C *) d; + for (int i = 0; i < e; i++) { + int s = x[i].heap_size(); + if (s) { + int *pi = x[i].heap_offset_ptr(); + if (pi) { + char *src = (char *) ptr(pi, partition); + if (src) { + if (heap_halfspace) { + if (src >= heap + halfspace_size()) + continue; + } else if (src < heap + halfspace_size()) + continue; + copy_heap_data(src, s, pi, partition, gc); + } + } + } + } + } +} + +// store either free or in the cache, can be stolen for reconfiguration +void stealStore(Store & s, int blocks); +#endif /* _MultiCache_h_ */ diff --git a/iocore/hostdb/include/Machine.h b/iocore/hostdb/include/Machine.h new file mode 100644 index 00000000..f85c2709 --- /dev/null +++ b/iocore/hostdb/include/Machine.h @@ -0,0 +1,146 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Machine.h + + + ****************************************************************************/ + + +// +// The Machine is the set of processes which share part of an +// address space. +// + +#ifndef _Machine_h +#define _Machine_h + +// +// Timeout the Machine * this amount of time after they +// fall out of the current configuration that are deleted. +// +#define MACHINE_TIMEOUT (HRTIME_DAY*2) + + +// +// This is the time processors should delay before freeing up resouces +// which are shared with other threads in non-long running operations. +// For example, a Machine * is returned by the hash and used to do +// a remote invoke. For the pointer to remain valid (or be recognized as +// invalid) he resource should not be raclaimed for NO_RACE_DELAY. +// +// Long running operations should use more sophisticated synchronization. +// +#define NO_RACE_DELAY HRTIME_HOUR // a long long time + +//#include "Connection.h" + +class ClusterHandler; // Leave this a class - VC++ gets very anal ~SR + +struct Machine:Server +{ + bool dead; + char *hostname; + int hostname_len; + // + // The network address of the current machine, + // stored in network byte order + // + unsigned int ip; + int cluster_port; + + Link link; + + // default for localhost + Machine(char *hostname = NULL, unsigned int ip = 0, int acluster_port = 0); + ~Machine(); + + // Cluster message protocol version + uint16_t msg_proto_major; + uint16_t msg_proto_minor; + + // Private data for ClusterProcessor + // + ClusterHandler *clusterHandler; +}; + +struct MachineListElement +{ + unsigned int ip; + int port; +}; +struct MachineList +{ + int n; + MachineListElement machine[1]; + MachineListElement *find(unsigned int ip, int port = 0) { + for (int i = 0; i < n; i++) + if (machine[i].ip == ip && (!port || machine[i].port == port)) + return &machine[i]; + return NULL; + } +}; + +MachineList *read_MachineList(char *filename, int test_fd = -1); +void free_MachineList(MachineList * l); + +#ifdef FIXME_CONFIG +struct clusterConfigFile:configFile +{ +#ifndef INK_NO_CLUSTER + char *parseFile(int fd) + { + return (char *) read_MachineList(NULL, fd); + } +#endif +}; +#endif + +inkcoreapi Machine *this_machine(); +void create_this_machine(); + +void free_Machine(Machine * m); + +MachineList *the_machines_config(); +MachineList *the_cluster_config(); +extern ProxyMutex *the_cluster_config_mutex; + +#define INK_GETHOSTBYNAME_R_DATA_SIZE 10000 +struct ink_gethostbyname_r_data +{ + int herrno; + struct hostent ent; + char buf[INK_GETHOSTBYNAME_R_DATA_SIZE]; +}; + +struct hostent *ink_gethostbyname_r(char *hostname, ink_gethostbyname_r_data * data); +// +// Private +// +extern MachineList *machines_config; +extern MachineList *cluster_config; + + +#endif /* _Machine_h */ diff --git a/iocore/hostdb/test_I_HostDB.cc b/iocore/hostdb/test_I_HostDB.cc new file mode 100644 index 00000000..71b717c0 --- /dev/null +++ b/iocore/hostdb/test_I_HostDB.cc @@ -0,0 +1,148 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include "I_HostDB.h" +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" +//#define USE_SOCKS + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i, e; + char *p, *dt, *at; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + +class HostDBTest:Continuation +{ + + +}; + +main() +{ + init_diags("net_test", NULL); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + ink_net_init(NET_SYSTEM_MODULE_VERSION); + ink_hostdb_init(HOSTDB_MODULE_VERSION); + signal(SIGPIPE, SIG_IGN); + + eventProcessor.start(2); + netProcessor.start(); + + printf("hello world\n"); + + hostDBProcessor.start(); + + + this_ethread()->execute(); +} diff --git a/iocore/hostdb/test_P_HostDB.cc b/iocore/hostdb/test_P_HostDB.cc new file mode 100644 index 00000000..d33d64f7 --- /dev/null +++ b/iocore/hostdb/test_P_HostDB.cc @@ -0,0 +1,83 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_HostDB.h" + +Diags *diags; +struct NetTesterSM:public Continuation +{ + VIO *read_vio; + IOBufferReader *reader; + NetVConnection *vc; + MIOBuffer *buf; + + NetTesterSM(ProxyMutex * _mutex, NetVConnection * _vc):Continuation(_mutex) + { + MUTEX_TRY_LOCK(lock, mutex, _vc->thread); + ink_release_assert(lock); + vc = _vc; + SET_HANDLER(&NetTesterSM::handle_read); + buf = new_MIOBuffer(8); + reader = buf->alloc_reader(); + read_vio = vc->do_io_read(this, INT64_MAX, buf); + } + + + int handle_read(int event, void *data) + { + int r; + char *str; + switch (event) { + case VC_EVENT_READ_READY: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + printf("%s", str); + fflush(stdout); + break; + case VC_EVENT_READ_COMPLETE: + /* FALLSTHROUGH */ + case VC_EVENT_EOS: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + printf("%s", str); + fflush(stdout); + case VC_EVENT_ERROR: + vc->do_io_close(); + // fixme + // handle timeout events + break; + default: + ink_release_assert(!"unknown event"); + + } + return EVENT_CONT; + } + + +}; + +main() +{ +} diff --git a/iocore/net/Connection.cc b/iocore/net/Connection.cc new file mode 100644 index 00000000..92c1fcbf --- /dev/null +++ b/iocore/net/Connection.cc @@ -0,0 +1,361 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + Connections + + Commonality across all platforms -- move out as required. + +**************************************************************************/ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "libts.h" + +#include "P_Net.h" + +#define SET_TCP_NO_DELAY +#define SET_NO_LINGER +// set in the OS +// #define RECV_BUF_SIZE (1024*64) +// #define SEND_BUF_SIZE (1024*64) +#define FIRST_RANDOM_PORT 16000 +#define LAST_RANDOM_PORT 32000 + +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) + +int +get_listen_backlog(void) +{ + int listen_backlog = 1024; + + IOCORE_ReadConfigInteger(listen_backlog, "proxy.config.net.listen_backlog"); + return listen_backlog; +} + + +// +// Functions +// +char const* +NetVCOptions::toString(addr_bind_style s) { + return ANY_ADDR == s ? "any" + : INTF_ADDR == s ? "interface" + : "foreign" + ; +} + +Connection::Connection() + : fd(NO_FD) + , is_bound(false) + , is_connected(false) +{ + memset(&sa, 0, sizeof(struct sockaddr_storage)); +} + + +Connection::~Connection() +{ + close(); +} + + +int +Server::accept(Connection * c) +{ + int res = 0; + socklen_t sz = sizeof(c->sa); + + res = socketManager.accept(fd, (struct sockaddr *)&c->sa, &sz); + if (res < 0) + return res; + c->fd = res; + +#ifdef SET_CLOSE_ON_EXEC + if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0) + goto Lerror; +#endif + if ((res = safe_nonblocking(c->fd)) < 0) + goto Lerror; +#ifdef SEND_BUF_SIZE + socketManager.set_sndbuf_size(c->fd, SEND_BUF_SIZE); +#endif +#ifdef SET_SO_KEEPALIVE + // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0) + goto Lerror; +#endif + + return 0; +Lerror: + c->close(); + return res; +} + + +int +Connection::close() +{ + is_connected = false; + is_bound = false; + // don't close any of the standards + if (fd >= 2) { + int fd_save = fd; + fd = NO_FD; + return socketManager.close(fd_save); + } else { + fd = NO_FD; + return -EBADF; + } +} + +int +Server::setup_fd_for_listen(bool non_blocking, int recv_bufsize, int send_bufsize) +{ + int res = 0; +#ifdef SEND_BUF_SIZE + { + int send_buf_size = SEND_BUF_SIZE; + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &send_buf_size, sizeof(int)) < 0)) + goto Lerror; + } +#endif +#ifdef RECV_BUF_SIZE + { + int recv_buf_size = RECV_BUF_SIZE; + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buf_size, sizeof(int))) < 0) + goto Lerror; + } +#endif + + if (recv_bufsize) { + // coverity[negative_sink_in_call] + if (socketManager.set_rcvbuf_size(fd, recv_bufsize)) { + // Round down until success + int rbufsz = ROUNDUP(recv_bufsize, 1024); + while (rbufsz) { + if (socketManager.set_rcvbuf_size(fd, rbufsz)) { + rbufsz -= 1024; + } else { + break; + } + } + } + } + if (send_bufsize) { + if (socketManager.set_sndbuf_size(fd, send_bufsize)) { + // Round down until success + int sbufsz = ROUNDUP(send_bufsize, 1024); + while (sbufsz) { + if (socketManager.set_sndbuf_size(fd, sbufsz)) { + sbufsz -= 1024; + } else { + break; + } + } + } + } +#ifdef SET_NO_LINGER + { + struct linger l; + l.l_onoff = 0; + l.l_linger = 0; + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l))) < 0) + goto Lerror; + } +#endif +#ifdef SET_TCP_NO_DELAY + if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0) + goto Lerror; +#endif +#ifdef SET_SO_KEEPALIVE + // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0) + goto Lerror; +#endif + +#if defined(linux) + if (NetProcessor::accept_mss > 0) + if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *) &NetProcessor::accept_mss, sizeof(int)) < 0)) + goto Lerror; +#endif + + /* + * dg: this has been removed since the ISS patch under solaris seems + * to not like the socket being listened on twice. This is first done + * in the manager when the socket is created. + */ + if (non_blocking) + if ((res = safe_nonblocking(fd)) < 0) + goto Lerror; + { + int namelen = sizeof(sa); + if ((res = safe_getsockname(fd, (struct sockaddr *) &sa, &namelen))) + goto Lerror; + } + return 0; +Lerror: + res = -errno; + // coverity[check_after_sink] + if (fd != NO_FD) + close(); + return res; +} + + +int +Server::listen(int port_number, int domain, bool non_blocking, int recv_bufsize, int send_bufsize) +{ + ink_assert(fd == NO_FD); + int res = 0; + int gai_errno = 0; + + char port[6] = {'\0'}; + struct addrinfo hints; + struct addrinfo *ai_res = NULL; + struct addrinfo *ai = NULL; + socklen_t addrlen = 0; // keep track of length of socket address info + snprintf(port, sizeof(port), "%d", port_number); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = domain; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST|AI_ADDRCONFIG; + gai_errno = getaddrinfo(accept_ip_str, port, &hints, &ai_res); + if(0 != gai_errno) { + Error("getaddrinfo error %i: %s", gai_errno, gai_strerror(gai_errno)); + return -1; + } + + ai = ai_res; + + res = socketManager.socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + + memset(&sa, 0, sizeof(sa)); + addrlen = ai->ai_addrlen; // save value for later since ai will be freed asap + memcpy(&sa, ai->ai_addr, ai->ai_addrlen); + + freeaddrinfo(ai_res); + + if (res < 0) + return res; + fd = res; + +#ifdef SEND_BUF_SIZE + { + int send_buf_size = SEND_BUF_SIZE; + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &send_buf_size, sizeof(int)) < 0)) + goto Lerror; + } +#endif +#ifdef RECV_BUF_SIZE + { + int recv_buf_size = RECV_BUF_SIZE; + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &recv_buf_size, sizeof(int))) < 0) + goto Lerror; + } +#endif + + if (recv_bufsize) { + if (socketManager.set_rcvbuf_size(fd, recv_bufsize)) { + // Round down until success + int rbufsz = ROUNDUP(recv_bufsize, 1024); + while (rbufsz) { + if (socketManager.set_rcvbuf_size(fd, rbufsz)) { + rbufsz -= 1024; + } else { + break; + } + } + } + } + if (send_bufsize) { + if (socketManager.set_sndbuf_size(fd, send_bufsize)) { + // Round down until success + int sbufsz = ROUNDUP(send_bufsize, 1024); + while (sbufsz) { + if (socketManager.set_sndbuf_size(fd, sbufsz)) { + sbufsz -= 1024; + } else { + break; + } + } + } + } +#ifdef SET_CLOSE_ON_EXEC + if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0) + goto Lerror; +#endif + +#ifdef SET_NO_LINGER + { + struct linger l; + l.l_onoff = 0; + l.l_linger = 0; + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &l, sizeof(l))) < 0) + goto Lerror; + } +#endif + + if (domain == AF_INET6 && (res = safe_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, ON, sizeof(int))) < 0) + goto Lerror; + + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ON, sizeof(int))) < 0) + goto Lerror; + + if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &sa, addrlen, IPPROTO_TCP)) < 0) { + goto Lerror; + } +#ifdef SET_TCP_NO_DELAY + if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int))) < 0) + goto Lerror; +#endif +#ifdef SET_SO_KEEPALIVE + // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int))) < 0) + goto Lerror; +#endif + +#if defined(linux) + if (NetProcessor::accept_mss > 0) + if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_MAXSEG, (char *) &NetProcessor::accept_mss, sizeof(int))) < 0) + goto Lerror; +#endif + + if ((res = safe_listen(fd, get_listen_backlog())) < 0) + goto Lerror; + if (non_blocking) + if ((res = safe_nonblocking(fd)) < 0) + goto Lerror; + if (!port_number) { + int namelen = sizeof(sa); + if ((res = safe_getsockname(fd, (struct sockaddr *) &sa, &namelen))) + goto Lerror; + } + return 0; + +Lerror: + if (fd != NO_FD) + close(); + Error("Could not bind or listen to port %d (error: %d)", port_number, res); + return res; +} diff --git a/iocore/net/I_Net.h b/iocore/net/I_Net.h new file mode 100644 index 00000000..2b79dfd4 --- /dev/null +++ b/iocore/net/I_Net.h @@ -0,0 +1,101 @@ +/** @file + + Net subsystem + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Net subsystem is a layer on top the operations sytem network apis. It + provides an interface for accepting/creating new connection oriented + (TCP) and connection less (UDP) connetions and for reading/writing + data through these. The net system can manage 1000s of connections + very efficiently. Another advantage of using the net system is that + the SMs dont have be concerned about differences in the net apis of + various operations systems. + + SMs use the netProcessor global object of the Net System to create new + connections or to accept incoming connections. When a new connection + is created the SM gets a NetVConnection which is a handle for the + underlying connections. The SM can then use the NetVConnection to get + properties of the connection, read and write data. Net system also + has socks and ssl support. + + */ +#ifndef __I_NET_H_ +#define __I_NET_H_ + +#ifndef TS_INLINE +#define TS_INLINE +#endif + +#include "I_Version.h" +#include "I_EventSystem.h" +#include + +#define NET_SYSTEM_MODULE_MAJOR_VERSION 1 +#define NET_SYSTEM_MODULE_MINOR_VERSION 0 +#define NET_SYSTEM_MODULE_VERSION makeModuleVersion( \ + NET_SYSTEM_MODULE_MAJOR_VERSION, \ + NET_SYSTEM_MODULE_MINOR_VERSION, \ + PUBLIC_MODULE_HEADER) + +/** For commenting out portions of code temporarily. */ +#define NET_FIXME + +// Temporary definitions +#ifdef NET_FIXME +#define ACCEPTEX_POOL_SIZE 1 +#endif + +#define NO_FD (-1) + +#define NET_EVENT_OPEN (NET_EVENT_EVENTS_START) +#define NET_EVENT_OPEN_FAILED (NET_EVENT_EVENTS_START+1) +#define NET_EVENT_ACCEPT (NET_EVENT_EVENTS_START+2) +#define NET_EVENT_ACCEPT_SUCCEED (NET_EVENT_EVENTS_START+3) +#define NET_EVENT_ACCEPT_FAILED (NET_EVENT_EVENTS_START+4) +#define NET_EVENT_CANCEL (NET_EVENT_EVENTS_START+5) +#define NET_EVENT_DATAGRAM_READ_COMPLETE (NET_EVENT_EVENTS_START+6) +#define NET_EVENT_DATAGRAM_READ_ERROR (NET_EVENT_EVENTS_START+7) +#define NET_EVENT_DATAGRAM_WRITE_COMPLETE (NET_EVENT_EVENTS_START+8) +#define NET_EVENT_DATAGRAM_WRITE_ERROR (NET_EVENT_EVENTS_START+9) +#define NET_EVENT_DATAGRAM_READ_READY (NET_EVENT_EVENTS_START+10) +#define NET_EVENT_DATAGRAM_OPEN (NET_EVENT_EVENTS_START+11) +#define NET_EVENT_DATAGRAM_ERROR (NET_EVENT_EVENTS_START+12) +#define NET_EVENT_ACCEPT_INTERNAL (NET_EVENT_EVENTS_START+22) +#define NET_EVENT_CONNECT_INTERNAL (NET_EVENT_EVENTS_START+23) + +#define MAIN_ACCEPT_PORT -1 + +/* + * Net system uses event threads + * so, the net thread group id is the event thread group id + */ + +#define ET_NET ET_CALL + +//struct socks_conf_struct; +#include "I_NetConfig.h" +#include "I_NetVConnection.h" +#include "I_NetProcessor.h" +#include "I_UDPNet.h" + +void ink_net_init(ModuleVersion version); +#endif diff --git a/iocore/net/I_NetConfig.h b/iocore/net/I_NetConfig.h new file mode 100644 index 00000000..4d4223f9 --- /dev/null +++ b/iocore/net/I_NetConfig.h @@ -0,0 +1,64 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __I_NETCONFIG_H__ +#define __I_NETCONFIG_H__ + +/* + * Temporary file specifying all configurable parameters for the + * net sub system. + * For the default values look at NetConfig.cc + */ +#if defined(solaris) +#define DEFAULT_POLL_TIMEOUT 30 /* mseconds */ +#else +#define DEFAULT_POLL_TIMEOUT 10 /* mseconds */ +#endif + +extern int net_config_poll_timeout; +extern int net_config_fds_throttle; +extern int net_config_listen_backlog; + +// SSL config +extern int net_config_ssl_mode; +extern int net_config_sslAccelerator; +extern int net_config_ssl_accept_port_number; +extern int net_config_clientCertLevel; +extern const char *net_config_atallaAccelLibPath; +extern const char *net_config_ncipherAccelLibPath; +extern const char *net_config_cswiftAccelLibPath; +extern const char *net_config_serverCertFilename; +extern const char *net_config_serverCertRelativePath; +extern const char *net_config_multicert_config_file; +extern char *net_config_ssl_server_private_key_filename; +extern char *net_config_ssl_server_private_key_path; +extern char *net_config_CACertFilename; +extern char *net_config_CACertRelativePath; +extern int net_config_clientVerify; +extern char *net_config_ssl_client_cert_filename; +extern const char *net_config_ssl_client_cert_path; +extern char *net_config_ssl_client_private_key_filename; +extern char *net_config_ssl_client_private_key_path; +extern char *net_config_clientCACertFilename; +extern char *net_config_clientCACertRelativePath; +#endif diff --git a/iocore/net/I_NetProcessor.h b/iocore/net/I_NetProcessor.h new file mode 100644 index 00000000..2a055972 --- /dev/null +++ b/iocore/net/I_NetProcessor.h @@ -0,0 +1,317 @@ +/** @file + + This file implements an I/O Processor for network I/O + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef __I_NETPROCESSOR_H__ +#define __I_NETPROCESSOR_H__ + +#include "I_EventSystem.h" +#include "I_Socks.h" +struct socks_conf_struct; +#define NET_CONNECT_TIMEOUT (30*1000) + +struct NetVCOptions; + +/** + This is the heart of the Net system. Provides common network APIs, + like accept, connect etc. It performs network I/O on behalf of a + state machine. + +*/ +class NetProcessor:public Processor +{ +public: + /** Options for @c accept. + */ + struct AcceptOptions { + typedef AcceptOptions self; ///< Self reference type. + + /// Port on which to listen. + /// 0 => don't care, which is useful if the socket is already bound. + int port; + /// Should we use accept threads? If so, how many? + int accept_threads; + /// Communication domain (default: AF_INET) + int domain; + /// Event type to generate on accept. + EventType etype; + /** If @c true, the continuation is called back with + @c NET_EVENT_ACCEPT_SUCCEED, + or @c NET_EVENT_ACCEPT_FAILED on success and failure resp. + */ + bool f_callback_on_open; + + /// Socket receive buffer size. + /// 0 => OS default. + int recv_bufsize; + /// Socket transmit buffer size. + /// 0 => OS default. + int send_bufsize; + /// Socket options for @c sockopt. + /// 0 => do not set options. + uint32_t sockopt_flags; + /// Transparency on related connection to origin server. + bool f_outbound_transparent; + /** Transparency on client (user agent) connection. + @internal This is irrelevant at a socket level (since inbound + transparency must be set up when the listen socket is created) + but it's critical that the connection handling logic knows + whether the inbound (client / user agent) connection is + transparent. + */ + bool f_inbound_transparent; + + /// Default constructor. + /// Instance is constructed with default values. + AcceptOptions() { this->reset(); } + /// Reset all values to defaults. + self& reset(); + }; + + /** + Accept connections on a port. + + Callbacks: + - cont->handleEvent( NET_EVENT_ACCEPT, NetVConnection *) is + called for each new connection + - cont->handleEvent(EVENT_ERROR,-errno) on a bad error + + Re-entrant callbacks (based on callback_on_open flag): + - cont->handleEvent(NET_EVENT_ACCEPT_SUCCEED, 0) on successful + accept init + - cont->handleEvent(NET_EVENT_ACCEPT_FAILED, 0) on accept + init failure + + @param cont Continuation to be called back with events this + continuation is not locked on callbacks and so the handler must + be re-entrant. + @param port port to bind for accept. + @param domain communication domain + @param frequent_accept if true, accept is done on all event + threads and throttle limit is imposed if false, accept is done + just on one thread and no throttling is done. + @param accept_ip DEPRECATED. + @param accept_ip_str for IPv6 Address + @param callback_on_open if true, cont is called back with + NET_EVENT_ACCEPT_SUCCEED, or NET_EVENT_ACCEPT_FAILED on success + and failure resp. + @param listen_socket_in if passed, used for listening. + @param accept_pool_size NT specific, better left unspecified. + @param accept_only can be used to customize accept, accept a + connection only if there is some data to be read. This works + only on supported platforms (NT & Win2K currently). + @param bound_sockaddr returns the sockaddr for the listen fd. + @param bound_sockaddr_size size of the sockaddr returned. + @param recv_bufsize used to set recv buffer size for accepted + connections (Works only on selected platforms ??). + @param send_bufsize used to set send buffer size for accepted + connections (Works only on selected platforms ??). + @param sockopt_flag can be used to define additional socket option. + @param etype Event Thread group to accept on. + @return Action, that can be cancelled to cancel the accept. The + port becomes free immediately. + + */ + inkcoreapi virtual Action * accept(Continuation * cont, int port, int domain = AF_INET, int accept_threads = -1, + bool frequent_accept = false, + // not used + unsigned int accept_ip = INADDR_ANY, char *accept_ip_str = NULL, bool callback_on_open = false, + SOCKET listen_socket_in = NO_FD, // NT only + int accept_pool_size = ACCEPTEX_POOL_SIZE, // NT only + bool accept_only = false, + sockaddr * bound_sockaddr = 0, + int *bound_sockaddr_size = 0, + int recv_bufsize = 0, + int send_bufsize = 0, uint32_t sockopt_flag = 0, EventType etype = ET_NET); + + /** + Accepts incoming connections on port. Accept connections on port. + Accept is done on all net threads and throttle limit is imposed + if frequent_accept flag is true. This is similar to the accept + method described above. The only difference is that the list + of parameter that is takes is limited. + + Callbacks: + - cont->handleEvent( NET_EVENT_ACCEPT, NetVConnection *) is called for each new connection + - cont->handleEvent(EVENT_ERROR,-errno) on a bad error + + Re-entrant callbacks (based on callback_on_open flag): + - cont->handleEvent(NET_EVENT_ACCEPT_SUCCEED, 0) on successful accept init + - cont->handleEvent(NET_EVENT_ACCEPT_FAILED, 0) on accept init failure + + @param cont Continuation to be called back with events this + continuation is not locked on callbacks and so the handler must + be re-entrant. + @param listen_socket_in if passed, used for listening. + @param port port to bind for accept. + @param bound_sockaddr returns the sockaddr for the listen fd. + @param bound_sockaddr_size size of the sockaddr returned. + @param accept_only can be used to customize accept, accept a + connection only if there is some data to be read. This works + only on supported platforms (NT & Win2K currently). + @param recv_bufsize used to set recv buffer size for accepted + connections (Works only on selected platforms ??). + @param send_bufsize used to set send buffer size for accepted + connections (Works only on selected platforms ??). + @param sockopt_flag can be used to define additional socket option. + @param etype Event Thread group to accept on. + @param callback_on_open if true, cont is called back with + NET_EVENT_ACCEPT_SUCCEED, or NET_EVENT_ACCEPT_FAILED on success + and failure resp. + @return Action, that can be cancelled to cancel the accept. The + port becomes free immediately. + + */ + virtual Action *main_accept(Continuation * cont, SOCKET listen_socket_in, sockaddr * bound_sockaddr = NULL, + int *bound_sockaddr_size = NULL, bool accept_only = false, bool localhost_only = false, + AcceptOptions const& opt = DEFAULT_ACCEPT_OPTIONS); + + /** + Open a NetVConnection for connection oriented I/O. Connects + through sockserver if netprocessor is configured to use socks + or is socks parameters to the call are set. + + Re-entrant callbacks: + - On success calls: c->handleEvent(NET_EVENT_OPEN, NetVConnection *) + - On failure calls: c->handleEvent(NET_EVENT_OPEN_FAILED, -errno) + + @note Connection may not have been established when cont is + call back with success. If this behaviour is desired use + synchronous connect connet_s method. + + @see connect_s() + + @param cont Continuation to be called back with events. + @param ip machine to connect to. + @param port port to connect to. + @param options @see NetVCOptions. + + */ + + inkcoreapi Action *connect_re(Continuation * cont, + unsigned int ip, int port, NetVCOptions * options = NULL); + + /** + Open a NetVConnection for connection oriented I/O. This call + is simliar to connect method except that the cont is called + back only after the connections has been established. In the + case of connect the cont could be called back with NET_EVENT_OPEN + event and OS could still be in the process of establishing the + connection. Re-entrant Callbacks: same as connect. If unix + asynchronous type connect is desired use connect_re(). + + @param cont Continuation to be called back with events. + @param ip machine to connect to. + @param port port to connect to. + @param timeout for connect, the cont will get NET_EVENT_OPEN_FAILED + if connection could not be established for timeout msecs. The + default is 30 secs. + @param options @see NetVCOptions. + + @see connect_re() + + */ + Action *connect_s(Continuation * cont, + unsigned int ip, + int port, + int timeout = NET_CONNECT_TIMEOUT, NetVCOptions * opts = NULL); + + /** + Starts the Netprocessor. This has to be called before doing any + other net call. + + @param number_of_net_threads is not used. The net processor + uses the Event Processor threads for its activity. + + */ + virtual int start(int number_of_net_threads = 0 /* uses event threads */ ) = 0; + + /** Private constructor. */ + NetProcessor() + { + }; + + /** Private destructor. */ + virtual ~ NetProcessor() { + }; + + /** This is MSS for connections we accept (client connections). */ + static int accept_mss; + + // + // The following are required by the SOCKS protocol: + // + // Either the configuration variables will give your a regular + // expression for all the names that are to go through the SOCKS + // server, or will give you a list of domain names which should *not* go + // through SOCKS. If the SOCKS option is set to false then, these + // variables (regular expression or list) should be set + // appropriately. If it is set to TRUE then, in addition to supplying + // the regular expression or the list, the user should also give the + // the ip address and port number for the SOCKS server (use + // appropriate defaults) + + /* shared by regular netprocessor and ssl netprocessor */ + static socks_conf_struct *socks_conf_stuff; + + /// Default options instance. + static AcceptOptions const DEFAULT_ACCEPT_OPTIONS; + +private: + + /** @note Not implemented. */ + virtual int stop() + { + ink_release_assert(!"NetProcessor::stop not implemented"); + return 1; + } + + NetProcessor(const NetProcessor &); + NetProcessor & operator =(const NetProcessor &); + +}; + + +/** + Global NetProcessor singleton object for making net calls. All + net processor calls like connect, accept, etc are made using this + object. + + @code + netProcesors.accept(my_cont, ...); + netProcessor.connect_re(my_cont, ...); + @endcode + +*/ +extern inkcoreapi NetProcessor& netProcessor; + +/** + Global netProcessor singleton object for making ssl enabled net + calls. As far as the SM is concerned this behaves excatly like + netProcessor. The only difference is that the connections are + over ssl. + +*/ +extern inkcoreapi NetProcessor& sslNetProcessor; + +#endif diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h new file mode 100644 index 00000000..20bbf4d4 --- /dev/null +++ b/iocore/net/I_NetVConnection.h @@ -0,0 +1,492 @@ +/** @file + + This file implements an I/O Processor for network I/O + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef __NETVCONNECTION_H__ +#define __NETVCONNECTION_H__ + +#include "I_Action.h" +#include "I_VConnection.h" +#include "I_Event.h" +#include "List.h" +#include "I_IOBuffer.h" +#include "I_Socks.h" + +#define CONNECT_SUCCESS 1 +#define CONNECT_FAILURE 0 + +#define SSL_EVENT_SERVER 0 +#define SSL_EVENT_CLIENT 1 + +enum NetDataType +{ + NET_DATA_ATTRIBUTES = VCONNECTION_NET_DATA_BASE +}; + +/** Holds client options for NetVConnection. + + This class holds various options a user can specify for + NetVConnection. Various clients need many slightly different + features. This is an attempt to prevent out of control growth of + the connection method signatures. + + Only options of interest need to be explicitly set -- + the rest get sensible default values. +*/ +struct NetVCOptions { + typedef NetVCOptions self; ///< Self reference type. + + /// Values for valid IP protocols. + enum ip_protocol_t { + USE_TCP, ///< TCP protocol. + USE_UDP ///< UDP protocol. + }; + + /// IP protocol to use on socket. + ip_protocol_t ip_proto; + + /** The set of ways in which the local address should be bound. + + @note The difference between @c INTF_ADDR and @c FOREIGN_ADDR is + whether transparency is enabled on the socket. It is the + client's responsibility to set this correctly based on whether the + address in @a local_addr is associated with an interface on the + local system, or is owned by a foreign system. A binding style + of @c ANY_ADDR causes the value in @a local_addr to be ignored. + + @see local_addr + @see addr_binding + */ + enum addr_bind_style { + ANY_ADDR, ///< Bind to any available local address (don't care, default). + INTF_ADDR, ///< Bind to the interface address in @a local_addr. + FOREIGN_ADDR ///< Bind to foreign address in @a local_addr. + }; + + /// The set of ways in which the local port should be bound. + enum port_bind_style { + ANY_PORT, ///< Bind to any available local port (don't care, default). + FIXED_PORT ///< Bind to the port in @a local_port. + }; + + /// Port to use for local side of connection. + /// @note Ignored if @a port_binding is @c ANY_PORT. + /// @see port_binding + uint16_t local_port; + /// How to bind local port. + /// @note Default is @c ANY_PORT. + port_bind_style port_binding; + /// Address to use for local side of connection. + /// @note Ignored if @a addr_binding is @c ANY_ADDR. + /// @see addr_binding + uint32_t local_addr; + /// How to bind the local address. + /// @note Default is @c ANY_ADDR. + addr_bind_style addr_binding; + + /// Make the socket blocking on I/O (default: @c false) + bool f_blocking; + /// Make socket block on connect (default: @c false) + bool f_blocking_connect; + + /// Control use of SOCKS. + /// Set to @c NO_SOCKS to disable use of SOCKS. Otherwise SOCKS is + /// used if available. + unsigned char socks_support; + /// Version of SOCKS to use. + unsigned char socks_version; + + int socket_recv_bufsize; + int socket_send_bufsize; + + /// Configuration options for sockets. + /// @note These are not identical to internal socket options but + /// specifically defined for configuration. These are mask values + /// and so must be powers of 2. + uint32_t sockopt_flags; + /// Value for TCP no delay for @c sockopt_flags. + static uint32_t const SOCK_OPT_NO_DELAY = 1; + /// Value for keep alive for @c sockopt_flags. + static uint32_t const SOCK_OPT_KEEP_ALIVE = 2; + + EventType etype; + + /// Reset all values to defaults. + void reset(); + + void set_sock_param(int _recv_bufsize, int _send_bufsize, unsigned long _opt_flags); + + NetVCOptions() { + reset(); + } + + /// @name Debugging + //@{ + /// Convert @a s to its string equivalent. + static char const* toString(addr_bind_style s); + //@} +}; + +/** + A VConnection for a network socket. Abstraction for a net connection. + Similar to a socket descriptor VConnections are IO handles to + streams. In one sense, they serve a purpose similar to file + descriptors. Unlike file descriptors, VConnections allow for a + stream IO to be done based on a single read or write call. + +*/ +class NetVConnection:public VConnection +{ +public: + + /** + Initiates read. Thread safe, may be called when not handling + an event from the NetVConnection, or the NetVConnection creation + callback. + + Callbacks: non-reentrant, c's lock taken during callbacks. + + + + + + +
c->handleEvent(VC_EVENT_READ_READY, vio)data added to buffer
c->handleEvent(VC_EVENT_READ_COMPLETE, vio)finished reading nbytes of data
c->handleEvent(VC_EVENT_EOS, vio)the stream has been shutdown
c->handleEvent(VC_EVENT_ERROR, vio)error
+ + The vio returned during callbacks is the same as the one returned + by do_io_read(). The vio can be changed only during call backs + from the vconnection. + + @param c continuation to be called back after (partial) read + @param nbytes no of bytes to read, if unknown set to INT64_MAX + @param buf buffer to put the data into + @return vio + + */ + virtual VIO * do_io_read(Continuation * c, int64_t nbytes, MIOBuffer * buf) = 0; + + /** + Initiates write. Thread-safe, may be called when not handling + an event from the NetVConnection, or the NetVConnection creation + callback. + + Callbacks: non-reentrant, c's lock taken during callbacks. + + + + + + + + + + + + + + +
c->handleEvent(VC_EVENT_WRITE_READY, vio)signifies data has written from the reader or there are no bytes available for the reader to write.
c->handleEvent(VC_EVENT_WRITE_COMPLETE, vio)signifies the amount of data indicated by nbytes has been read from the buffer
c->handleEvent(VC_EVENT_ERROR, vio)signified that error occured during write.
+ + The vio returned during callbacks is the same as the one returned + by do_io_write(). The vio can be changed only during call backs + from the vconnection. The vconnection deallocates the reader + when it is destroyed. + + @param c continuation to be called back after (partial) write + @param nbytes no of bytes to write, if unknown msut be set to INT64_MAX + @param buf source of data + @param owner + @return vio pointer + + */ + virtual VIO *do_io_write(Continuation * c, int64_t nbytes, IOBufferReader * buf, bool owner = false) = 0; + + /** + Closes the vconnection. A state machine MUST call do_io_close() + when it has finished with a VConenction. do_io_close() indicates + that the VConnection can be deallocated. After a close has been + called, the VConnection and underlying processor must NOT send + any more events related to this VConnection to the state machine. + Likeswise, state machine must not access the VConnectuion or + any returned VIOs after calling close. lerrno indicates whether + a close is a normal close or an abort. The difference between + a normal close and an abort depends on the underlying type of + the VConnection. Passing VIO::CLOSE for lerrno indicates a + normal close while passing VIO::ABORT indicates an abort. + + @param lerrno VIO:CLOSE for regular close or VIO::ABORT for aborts + + */ + virtual void do_io_close(int lerrno = -1) = 0; + + /** + Shuts down read side, write side, or both. do_io_shutdown() can + be used to terminate one or both sides of the VConnection. The + howto is one of IO_SHUTDOWN_READ, IO_SHUTDOWN_WRITE, + IO_SHUTDOWN_READWRITE. Once a side of a VConnection is shutdown, + no further I/O can be done on that side of the connections and + the underlying processor MUST NOT send any further events + (INCLUDING TIMOUT EVENTS) to the state machine. The state machine + MUST NOT use any VIOs from a shutdown side of a connection. + Even if both sides of a connection are shutdown, the state + machine MUST still call do_io_close() when it wishes the + VConnection to be deallocated. + + @param howto IO_SHUTDOWN_READ, IO_SHUTDOWN_WRITE, IO_SHUTDOWN_READWRITE + + */ + virtual void do_io_shutdown(ShutdownHowTo_t howto) = 0; + + + /** + Sends out of band messages over the connection. This function + is used to send out of band messages (is this still useful?). + cont is called back with VC_EVENT_OOB_COMPLETE - on successful + send or VC_EVENT_EOS - if the other side has shutdown the + connection. These callbacks could be re-entrant. Only one + send_OOB can be in progress at any time for a VC. + + @param cont to be called back with events. + @param buf message buffer. + @param len length of the message. + + */ + virtual Action *send_OOB(Continuation * cont, char *buf, int len); + + /** + Cancels a scheduled send_OOB. Part of the message could have + been sent already. Not callbacks to the cont are made after + this call. The Action returned by send_OOB should not be accessed + after cancel_OOB. + + */ + virtual void cancel_OOB(); + + //////////////////////////////////////////////////////////// + // Set the timeouts associated with this connection. // + // active_timeout is for the total elasped time of // + // the connection. // + // inactivity_timeout is the elapsed time from the time // + // a read or a write was scheduled during which the // + // connection was unable to sink/provide data. // + // calling these functions repeatedly resets the timeout. // + // These functions are NOT THREAD-SAFE, and may only be // + // called when handing an event from this NetVConnection,// + // or the NetVConnection creation callback. // + //////////////////////////////////////////////////////////// + + /** + Sets time after which SM should be notified. + + Sets the amount of time (in nanoseconds) after which the state + machine using the NetVConnection should receive a + VC_EVENT_ACTIVE_TIMEOUT event. The timeout is value is ignored + if neither the read side nor the write side of the connection + is currently active. The timer is reset if the function is + called repeatedly This call can be used by SMs to make sure + that it does not keep any connections open for a really long + time. + + Timeout symantics: + + Should a timeout occur, the state machine for the read side of + the NetVConnection is signaled first assuming that a read has + been initiated on the NetVConnection and that the read side of + the NetVConnection has not been shutdown. Should either of the + two conditions not be met, the NetProcessor will attempt to + signal the write side. If a timeout is sent to the read side + state machine and its handler, return EVENT_DONE, a timeout + will not be sent to the write side. Should the return from the + handler not be EVENT_DONE and the write side state machine is + different (in terms of pointer comparison) from the read side + state machine, the NetProcessor will try to signal the write + side state machine as well. To signal write side, a write must + have been initiated on it and the write must not have been + shutdown. + + Receiving a timeout is only a notification that the timer has + expired. The NetVConnection is still usable. Further timeouts + of the type signaled will not be generated unless the timeout + is reset via the set_active_timeout() or set_inactivity_timeout() + interfaces. + + */ + virtual void set_active_timeout(ink_hrtime timeout_in) = 0; + + /** + Sets time after which SM should be notified if the requested + IO could not be performed. Sets the amount of time (in nanoseconds), + if the NetVConnection is idle on both the read or write side, + after which the state machine using the NetVConnection should + receive a VC_EVENT_INACTIVITY_TIMEOUT event. Either read or + write traffic will cause timer to be reset. Calling this function + again also resets the timer. The timeout is value is ignored + if neither the read side nor the write side of the connection + is currently active. See section on timeout semantics above. + + */ + virtual void set_inactivity_timeout(ink_hrtime timeout_in) = 0; + + /** + Clears the active timeout. No active timeouts will be sent until + set_active_timeout() is used to reset the active timeout. + + */ + virtual void cancel_active_timeout() = 0; + + /** + Clears the inactivity timeout. No inactivity timeouts will be + sent until set_inactivity_timeout() is used to reset the + inactivity timeout. + + */ + virtual void cancel_inactivity_timeout() = 0; + + /** @return the current active_timeout value in nanosecs */ + virtual ink_hrtime get_active_timeout() = 0; + + /** @return current inactivity_timeout value in nanosecs */ + virtual ink_hrtime get_inactivity_timeout() = 0; + + /** Returns local sockaddr storage. */ + sockaddr_storage const* get_local_addr(); + + /** Returns local ip. */ + unsigned int get_local_ip(); + + /** Returns local port. */ + int get_local_port(); + + /** Returns remote sockaddr storage. */ + sockaddr_storage const* get_remote_addr(); + + /** Returns remote ip. */ + unsigned int get_remote_ip(); + + /** Returns remote port. */ + int get_remote_port(); + + /** Structure holding user options. */ + NetVCOptions options; + + // + // Private + // + + //The following variable used to obtain host addr when transparency + //is enabled by SocksProxy + SocksAddrType socks_addr; + + unsigned int attributes; + EThread *thread; + + /// PRIVATE: The public interface is VIO::reenable() + virtual void reenable(VIO * vio) = 0; + + /// PRIVATE: The public interface is VIO::reenable() + virtual void reenable_re(VIO * vio) = 0; + + /// PRIVATE + virtual ~NetVConnection() {} + + /** + PRIVATE: instances of NetVConnection cannot be created directly + by the state machines. The objects are created by NetProcessor + calls like accept connect_re() etc. The constructor is public + just to avoid compile errors. + + */ + NetVConnection(); + + virtual SOCKET get_socket() = 0; + + /** Set local sock addr struct. */ + virtual void set_local_addr() = 0; + + /** Set remote sock addr struct. */ + virtual void set_remote_addr() = 0; + + // for InkAPI + bool get_is_internal_request() const { + return is_internal_request; + } + + void set_is_internal_request(bool val = false) { + is_internal_request = val; + } + + /// Get the transparency state. + bool get_is_transparent() const { + return is_transparent; + } + /// Set the transparency state. + void set_is_transparent(bool state = true) { + is_transparent = state; + } + + /// Get the current flag state. + bool get_is_other_side_transparent() const { + return is_other_side_transparent; + } + /// Set the flag to @a value. + void set_is_other_side_transparent(bool value = true) { + is_other_side_transparent = value; + } + +private: + NetVConnection(const NetVConnection &); + NetVConnection & operator =(const NetVConnection &); + +protected: + struct sockaddr_storage local_addr; + struct sockaddr_storage remote_addr; + + int got_local_addr; + int got_remote_addr; + + bool is_internal_request; + /// Set if this connection is transparent. + bool is_transparent; + /// Set if the paired connection is (should be) transparent. + /// @internal Currently only used on client side connections + /// to track whether the origin server connection should + /// be transparent. + bool is_other_side_transparent; +}; + +inline +NetVConnection::NetVConnection(): + VConnection(NULL), + attributes(0), + thread(NULL), + got_local_addr(0), + got_remote_addr(0), + is_internal_request(false), + is_transparent(false), + is_other_side_transparent(false) +{ + memset(&local_addr, 0, sizeof(local_addr)); + memset(&remote_addr, 0, sizeof(remote_addr)); +} + +#endif diff --git a/iocore/net/I_Socks.h b/iocore/net/I_Socks.h new file mode 100644 index 00000000..a8aac851 --- /dev/null +++ b/iocore/net/I_Socks.h @@ -0,0 +1,84 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __I_SOCKS_H__ +#define __I_SOCKS_H__ + +#ifdef NON_MODULAR +/*When this is being compiled with TS, we enable more features the use + non modularized stuff. namely: + ip_ranges and multiple socks server support. +*/ +#define SOCKS_WITH_TS +#endif + +#define SOCKS_DEFAULT_VERSION 0 //defined the configuration variable +#define SOCKS4_VERSION 4 +#define SOCKS5_VERSION 5 +#define SOCKS_CONNECT 1 +#define SOCKS4_REQ_LEN 9 +#define SOCKS4_REP_LEN 8 +#define SOCKS5_REP_LEN 262 //maximum possible +#define SOCKS4_REQ_GRANTED 90 +#define SOCKS4_CONN_FAILED 91 +#define SOCKS5_REQ_GRANTED 0 +#define SOCKS5_CONN_FAILED 1 + +enum +{ + //For these two, we need to pick two values which are not used for any of the + //"commands" (eg: CONNECT, BIND) in SOCKS protocols. + NORMAL_SOCKS = 0, + NO_SOCKS = 48 +}; + +enum +{ + SOCKS_ATYPE_NONE = 0, + SOCKS_ATYPE_IPV4 = 1, + SOCKS_ATYPE_FQHN = 3, + SOCKS_ATYPE_IPV6 = 4 +}; + +struct SocksAddrType +{ + unsigned char type; + union + { + //mostly it is ipv4. in other cases we will xalloc(). + unsigned char ipv4[4]; + unsigned char *buf; + } addr; + + void reset(); + SocksAddrType():type(SOCKS_ATYPE_NONE) + { + addr.buf = 0; + } + ~SocksAddrType() + { + reset(); + } +}; + +#endif diff --git a/iocore/net/I_UDPConnection.h b/iocore/net/I_UDPConnection.h new file mode 100644 index 00000000..965003ca --- /dev/null +++ b/iocore/net/I_UDPConnection.h @@ -0,0 +1,113 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + I_UDPConnection.h + UDPConnection interface + + + ****************************************************************************/ + +#ifndef __I_UDPCONNECTION_H_ +#define __I_UDPCONNECTION_H_ + +#include "I_EventSystem.h" +#define INK_ETHERNET_MTU_SIZE 1472 +class UDPPacket; +/** + UDP Connection endpoint + + You can schedule packet to be sent immediately or for the future, + and set up a persistent receive() operation. + */ + +class UDPConnection:public Continuation +{ +public: + virtual ~ UDPConnection() + { + }; + + SOCKET getFd(); + void setBinding(struct sockaddr_in *); + inkcoreapi int getBinding(struct sockaddr_in *); + + void destroy(); + int shouldDestroy(); + /* Returns the b/w allocated to this UDP connection in Mbps */ + double get_allocatedBandwidth(); + /** +

+ Callbacks:
+ cont->handleEvent(NET_EVENT_DATAGRAM_WRITE_ERROR, UDPPacket *) on error +
+ no callback on success. + + @return Action* send can't be cancelled via this Action + @param c continuation to be called back + @param p packet to be sent. + */ + Action *send(Continuation * c, UDPPacket * p); + + /** +

+ Callbacks:
+ cont->handleEvent(NET_EVENT_DATAGRAM_ERROR, UDPConnection *) on error +
+ cont->handleEvent(NET_EVENT_DATAGRAM_READ_READY, Queue<UDPPacketInternal> *) on incoming packets. + + @return Action* Always returns ACTION_RESULT_NONE. Can't be + cancelled via this Action. + @param c continuation to be called back + */ + Action *recv(Continuation * c); + + void Release(); + void AddRef(); + int GetRefCount(); + + int getPortNum(void); + + int GetSendGenerationNumber(); //const + void SetLastSentPktTSSeqNum(int64_t sentSeqNum); + int64_t cancel(); + void setContinuation(Continuation * c); + + /** + Put socket on net queue for read/write polling. + + Not required for UDPConnections created with + UDPNetProcessor::UDPBind + + Required for UDPNetProcessor::UDPCreatePortPairs and + UDPNetProcessor::CreateUDPSocket. They don't do bindToThread() + automatically so that the sockets can be passed to other Continuations. + */ + void bindToThread(Continuation * c); + + virtual void UDPConnection_is_abstract() = 0; +}; + +TS_INLINE UDPConnection *new_UDPConnection(int fd); +#endif //__I_UDPCONNECTION_H_ diff --git a/iocore/net/I_UDPNet.h b/iocore/net/I_UDPNet.h new file mode 100644 index 00000000..1948892d --- /dev/null +++ b/iocore/net/I_UDPNet.h @@ -0,0 +1,132 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + I_UDPNet.h + This file provides UDP interface. To be included in I_Net.h + + + ****************************************************************************/ + +#ifndef __UDPNET_H_ +#define __UDPNET_H_ + +#include "I_Version.h" +#include "I_EventSystem.h" +/** + UDP service + + You can create UDPConnections for asynchronous send/receive or call + directly (inefficiently) into network layer. + */ +class UDPNetProcessor:public Processor +{ +public: + virtual int start(int n_upd_threads) = 0; + + //this function was interanal intially.. this is required for public and + //interface probably should change. + bool CreateUDPSocket(int *resfd, struct sockaddr_in *addr, + Action ** status, + int my_port, unsigned int my_ip = 0, int send_bufsize = 0, int recv_bufsize = 0); + + /** + create UDPConnection + + Why was this implemented as an asynchronous call? Just in case + Windows requires it... +

+ Callbacks:
+ cont->handleEvent( NET_EVENT_DATAGRAM_OPEN, UDPConnection *) is + called for new socket. + + @param c Continuation that is called back with newly created + socket. + @param my_port Local port to be bound (required) + @param my_ip Local IP to be bound (optional). Defaults to '0' (INADDR_ANY) + @param send_bufsize (optional) Socket buffer size for sending. + Limits how much outstanding data to OS before it is able to send + to the NIC. + @param recv_bufsize (optional) Socket buffer size for sending. + Limits how much can be queued by OS before we read it. + @return Action* Always returns ACTION_RESULT_DONE if socket was + created successfuly, or ACTION_IO_ERROR if not. + */ + inkcoreapi Action *UDPBind(Continuation * c, int my_port, int my_ip = 0, int send_bufsize = 0, int recv_bufsize = 0); + + // The mess again: the complier won't let me stick UDPConnection here. + void UDPClassifyConnection(Continuation * udpConn, int destIP); + + // create pairs of UDPConnections in which the first connection is + // on a even-#'ed port and the second connection is on the next + // odd-#'ed port. Create "nPairs" of such connections. + Action *UDPCreatePortPairs(Continuation *, int nPairs, + unsigned int myIP = 0, + unsigned int destIP = 0, int send_bufsize = 0, int recv_bufsize = 0); + + // Regarding sendto_re, sendmsg_re, recvfrom_re: + // * You may be called back on 'c' with completion or error status. + // * 'token' is an opaque which can be used by caller to match up the I/O + // with the completion event. + // * If IOBufferBlock * is passed in the interface, it is reference + // counted internally. + // * For recvfrom_re, data is written beginning at IOBufferBlock::end() and + // the IOBufferBlock is not fill()'ed until I/O actually occurs. This + // kind of implies that you can only have one outstanding I/O per + // IOBufferBlock + // Callback: + // * callback signature is: handleEvent(int event,CompletionEvent *cevent); + // where event is one of: + // NET_EVENT_DATAGRAM_WRITE_COMPLETE + // NET_EVENT_DATAGRAM_WRITE_ERROR + // * You can get the value of 'token' that you passed in by calling + // completionUtil::getHandle(cevent); + // * You can get other info about the completed operation through use + // of the completionUtil class. + Action *sendto_re(Continuation * c, void *token, int fd, + struct sockaddr *toaddr, int toaddrlen, IOBufferBlock * buf, int len); + // I/O buffers referenced by msg must be pinned by the caller until + // continuation is called back. + Action *sendmsg_re(Continuation * c, void *token, int fd, struct msghdr *msg); + + Action *recvfrom_re(Continuation * c, void *token, int fd, + struct sockaddr *fromaddr, socklen_t *fromaddrlen, + IOBufferBlock * buf, int len, bool useReadCont = true, int timeout = 0); + // Continuation is really a UDPConnection; due to the include mess, we stick in the + // base-class of UDPConnection. + bool AllocBandwidth(Continuation * udpConn, double desiredMbps); + bool ChangeBandwidth(Continuation * udpConn, double desiredMbps); + void FreeBandwidth(Continuation * udpConn); + double GetAvailableBandwidth(); + + virtual void UDPNetProcessor_is_abstract() = 0; + +}; + +inkcoreapi extern UDPNetProcessor & udpNet; + +#include "I_UDPPacket.h" +#include "I_UDPConnection.h" + +#endif //__UDPNET_H_ diff --git a/iocore/net/I_UDPPacket.h b/iocore/net/I_UDPPacket.h new file mode 100644 index 00000000..2ec81f15 --- /dev/null +++ b/iocore/net/I_UDPPacket.h @@ -0,0 +1,113 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + I_UDPPacket.h + UDPPacket interface + + + ****************************************************************************/ + +#ifndef __I_UDPPACKET_H_ +#define __I_UDPPACKET_H_ + +#include "I_UDPConnection.h" +/** @name UDPPacket + UDP packet functions used by UDPConnection + */ +//@{ +/** + UDP data with destination + */ +class UDPPacket +{ + +public: + + virtual ~ UDPPacket() + { + }; + virtual void free(); // fast deallocate + + void setContinuation(Continuation * c); + void setConnection(UDPConnection * c); + UDPConnection *getConnection(); + void setArrivalTime(ink_hrtime t); + IOBufferBlock *getIOBlockChain(); + void setReliabilityPkt(); + int64_t getPktLength(); + /** + Add IOBufferBlock (chain) to end of packet. + @param block block chain to add. + + */ + inkcoreapi void append_block(IOBufferBlock * block); + virtual void UDPPacket_is_abstract() = 0; + + struct sockaddr_in from; // what address came from + struct sockaddr_in to; // what address to send to + + int from_size; + + LINK(UDPPacket, link); +}; + +/** + Create a new packet to be sent over UDPConnection. This actually + copies data from a buffer. + + + @param to address of where to send packet + @param when ink_hrtime relative to ink_get_hrtime_internal() + @param buf if !NULL, then len bytes copied from buf and made into packet. + @param len # of bytes to copy from buf + */ +TS_INLINE UDPPacket *new_UDPPacket(struct sockaddr_in *to, ink_hrtime when = 0, char *buf = NULL, int len = 0); +/** + Create a new packet to be sent over UDPConnection. This clones and + makes a reference to an existing IOBufferBlock chain. + + + @param to address of where to send packet + @param when ink_hrtime relative to ink_get_hrtime_internal() + @param block if !NULL, then the IOBufferBlock chain of data to use + for packet + @param len # of bytes to reference from block + */ +TS_INLINE UDPPacket *new_UDPPacket(struct sockaddr_in *to, + ink_hrtime when = 0, IOBufferBlock * block = NULL, int len = 0); +/** + Create a new packet to be sent over UDPConnection. Packet has no + destination or data. +*/ +TS_INLINE UDPPacket *new_UDPPacket(); + +/** + Create a new packet to be delivered to application. + Internal function only +*/ +TS_INLINE UDPPacket *new_incoming_UDPPacket(struct sockaddr_in *from, char *buf, int len); + +//@} +#endif //__I_UDPPACKET_H_ diff --git a/iocore/net/Inline.cc b/iocore/net/Inline.cc new file mode 100644 index 00000000..ac73c944 --- /dev/null +++ b/iocore/net/Inline.cc @@ -0,0 +1,32 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Inline Functions as globals for users using the public interface + * + */ +#define TS_INLINE +#define INLINE_CC + +#include "P_Net.h" + diff --git a/iocore/net/Makefile.am b/iocore/net/Makefile.am new file mode 100644 index 00000000..05bd2970 --- /dev/null +++ b/iocore/net/Makefile.am @@ -0,0 +1,97 @@ +# Makefile.am for the traffic/iocore/net hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if STANDALONE_IOCORE +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records +else +AM_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/utils +endif + + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +noinst_LIBRARIES = libinknet.a + +libinknet_a_SOURCES = \ + Connection.cc \ + I_NetConfig.h \ + I_NetErrno.h \ + I_Net.h \ + I_NetProcessor.h \ + I_NetVConnection.h \ + I_Socks.h \ + I_UDPConnection.h \ + I_UDPNet.h \ + I_UDPPacket.h \ + Net.cc \ + NetConfig.cc \ + NetVConnection.cc \ + P_CompletionUtil.h \ + P_Connection.h \ + P_InkBulkIO.h \ + P_LibBulkIO.h \ + P_NetAccept.h \ + P_Net.h \ + P_NetVConnection.h \ + P_Socks.h \ + P_SSLCertLookup.h \ + P_SSLConfig.h \ + P_SSLNetAccept.h \ + P_SSLNetProcessor.h \ + P_SSLNetVConnection.h \ + P_UDPConnection.h \ + P_UDPIOEvent.h \ + P_UDPNet.h \ + P_UDPPacket.h \ + P_UnixCompletionUtil.h \ + P_UnixNet.h \ + P_UnixNetProcessor.h \ + P_UnixNetState.h \ + P_UnixNetVConnection.h \ + P_UnixPollDescriptor.h \ + P_UnixUDPConnection.h \ + Socks.cc \ + SSLCertLookup.cc \ + SSLConfig.cc \ + SSLNet.cc \ + SSLNetVConnection.cc \ + SSLUnixNet.cc \ + UDPIOEvent.cc \ + UnixConnection.cc \ + UnixNetAccept.cc \ + UnixNet.cc \ + UnixNetPages.cc \ + UnixNetProcessor.cc \ + UnixNetVConnection.cc \ + UnixUDPConnection.cc \ + UnixUDPNet.cc \ + Inline.cc + +if BUILD_TESTS + libinknet_a_SOURCES += NetVCTest.cc \ + P_NetVCTest.h +endif diff --git a/iocore/net/Makefile.in b/iocore/net/Makefile.in new file mode 100644 index 00000000..631b2ef2 --- /dev/null +++ b/iocore/net/Makefile.in @@ -0,0 +1,766 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/net hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@BUILD_TESTS_TRUE@am__append_1 = NetVCTest.cc \ +@BUILD_TESTS_TRUE@ P_NetVCTest.h + +subdir = iocore/net +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinknet_a_AR = $(AR) $(ARFLAGS) +libinknet_a_LIBADD = +am__libinknet_a_SOURCES_DIST = Connection.cc I_NetConfig.h \ + I_NetErrno.h I_Net.h I_NetProcessor.h I_NetVConnection.h \ + I_Socks.h I_UDPConnection.h I_UDPNet.h I_UDPPacket.h Net.cc \ + NetConfig.cc NetVConnection.cc P_CompletionUtil.h \ + P_Connection.h P_InkBulkIO.h P_LibBulkIO.h P_NetAccept.h \ + P_Net.h P_NetVConnection.h P_Socks.h P_SSLCertLookup.h \ + P_SSLConfig.h P_SSLNetAccept.h P_SSLNetProcessor.h \ + P_SSLNetVConnection.h P_UDPConnection.h P_UDPIOEvent.h \ + P_UDPNet.h P_UDPPacket.h P_UnixCompletionUtil.h P_UnixNet.h \ + P_UnixNetProcessor.h P_UnixNetState.h P_UnixNetVConnection.h \ + P_UnixPollDescriptor.h P_UnixUDPConnection.h Socks.cc \ + SSLCertLookup.cc SSLConfig.cc SSLNet.cc SSLNetVConnection.cc \ + SSLUnixNet.cc UDPIOEvent.cc UnixConnection.cc UnixNetAccept.cc \ + UnixNet.cc UnixNetPages.cc UnixNetProcessor.cc \ + UnixNetVConnection.cc UnixUDPConnection.cc UnixUDPNet.cc \ + Inline.cc NetVCTest.cc P_NetVCTest.h +@BUILD_TESTS_TRUE@am__objects_1 = NetVCTest.$(OBJEXT) +am_libinknet_a_OBJECTS = Connection.$(OBJEXT) Net.$(OBJEXT) \ + NetConfig.$(OBJEXT) NetVConnection.$(OBJEXT) Socks.$(OBJEXT) \ + SSLCertLookup.$(OBJEXT) SSLConfig.$(OBJEXT) SSLNet.$(OBJEXT) \ + SSLNetVConnection.$(OBJEXT) SSLUnixNet.$(OBJEXT) \ + UDPIOEvent.$(OBJEXT) UnixConnection.$(OBJEXT) \ + UnixNetAccept.$(OBJEXT) UnixNet.$(OBJEXT) \ + UnixNetPages.$(OBJEXT) UnixNetProcessor.$(OBJEXT) \ + UnixNetVConnection.$(OBJEXT) UnixUDPConnection.$(OBJEXT) \ + UnixUDPNet.$(OBJEXT) Inline.$(OBJEXT) $(am__objects_1) +libinknet_a_OBJECTS = $(am_libinknet_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinknet_a_SOURCES) +DIST_SOURCES = $(am__libinknet_a_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +@STANDALONE_IOCORE_FALSE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_FALSE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/lib/records \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/proxy/hdrs \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/preparse \ +@STANDALONE_IOCORE_FALSE@ -I$(top_srcdir)/mgmt/utils + +@STANDALONE_IOCORE_TRUE@AM_CPPFLAGS = \ +@STANDALONE_IOCORE_TRUE@ $(iocore_include_dirs) \ +@STANDALONE_IOCORE_TRUE@ -I$(top_srcdir)/lib/records + +noinst_LIBRARIES = libinknet.a +libinknet_a_SOURCES = Connection.cc I_NetConfig.h I_NetErrno.h I_Net.h \ + I_NetProcessor.h I_NetVConnection.h I_Socks.h \ + I_UDPConnection.h I_UDPNet.h I_UDPPacket.h Net.cc NetConfig.cc \ + NetVConnection.cc P_CompletionUtil.h P_Connection.h \ + P_InkBulkIO.h P_LibBulkIO.h P_NetAccept.h P_Net.h \ + P_NetVConnection.h P_Socks.h P_SSLCertLookup.h P_SSLConfig.h \ + P_SSLNetAccept.h P_SSLNetProcessor.h P_SSLNetVConnection.h \ + P_UDPConnection.h P_UDPIOEvent.h P_UDPNet.h P_UDPPacket.h \ + P_UnixCompletionUtil.h P_UnixNet.h P_UnixNetProcessor.h \ + P_UnixNetState.h P_UnixNetVConnection.h P_UnixPollDescriptor.h \ + P_UnixUDPConnection.h Socks.cc SSLCertLookup.cc SSLConfig.cc \ + SSLNet.cc SSLNetVConnection.cc SSLUnixNet.cc UDPIOEvent.cc \ + UnixConnection.cc UnixNetAccept.cc UnixNet.cc UnixNetPages.cc \ + UnixNetProcessor.cc UnixNetVConnection.cc UnixUDPConnection.cc \ + UnixUDPNet.cc Inline.cc $(am__append_1) +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/net/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/net/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinknet.a: $(libinknet_a_OBJECTS) $(libinknet_a_DEPENDENCIES) + -rm -f libinknet.a + $(libinknet_a_AR) libinknet.a $(libinknet_a_OBJECTS) $(libinknet_a_LIBADD) + $(RANLIB) libinknet.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Connection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Inline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Net.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetConfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetVCTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetVConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSLCertLookup.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSLConfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSLNet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSLNetVConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSLUnixNet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Socks.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UDPIOEvent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixNet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixNetAccept.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixNetPages.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixNetProcessor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixNetVConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixUDPConnection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnixUDPNet.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/net/Net.cc b/iocore/net/Net.cc new file mode 100644 index 00000000..f6a901f1 --- /dev/null +++ b/iocore/net/Net.cc @@ -0,0 +1,144 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/************************************************************************ + + Net.cc + + +************************************************************************/ + +#include "P_Net.h" + +RecRawStatBlock *net_rsb = NULL; + +static inline void +configure_net(void) +{ + IOCORE_RegisterConfigUpdateFunc("proxy.config.net.connections_throttle", change_net_connections_throttle, NULL); + IOCORE_ReadConfigInteger(fds_throttle, "proxy.config.net.connections_throttle"); + IOCORE_ReadConfigInteger(throttle_enabled,"proxy.config.net.throttle_enabled"); +} + + +static inline void +register_net_stats() +{ + + // + // Register statistics + // + RecRegisterRawStat(net_rsb, RECT_PROCESS, "proxy.process.net.net_handler_run", + RECD_INT, RECP_NULL, (int) net_handler_run_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_handler_run_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, "proxy.process.net.read_bytes", + RECD_INT, RECP_NULL, (int) net_read_bytes_stat, RecRawStatSyncSum); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, "proxy.process.net.write_bytes", + RECD_INT, RECP_NULL, (int) net_write_bytes_stat, RecRawStatSyncSum); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.connections_currently_open", + RECD_INT, RECP_NON_PERSISTENT, (int) net_connections_currently_open_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_connections_currently_open_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.accepts_currently_open", + RECD_INT, RECP_NON_PERSISTENT, (int) net_accepts_currently_open_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_accepts_currently_open_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_readfromnet", + RECD_INT, RECP_NULL, (int) net_calls_to_readfromnet_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_readfromnet_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_readfromnet_afterpoll", + RECD_INT, RECP_NULL, (int) net_calls_to_readfromnet_afterpoll_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_readfromnet_afterpoll_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_read", + RECD_INT, RECP_NULL, (int) net_calls_to_read_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_read_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_read_nodata", + RECD_INT, RECP_NULL, (int) net_calls_to_read_nodata_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_read_nodata_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_writetonet", + RECD_INT, RECP_NULL, (int) net_calls_to_writetonet_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_writetonet_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_writetonet_afterpoll", + RECD_INT, RECP_NULL, (int) net_calls_to_writetonet_afterpoll_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_writetonet_afterpoll_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_write", + RECD_INT, RECP_NULL, (int) net_calls_to_write_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_write_stat); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.net.calls_to_write_nodata", + RECD_INT, RECP_NULL, (int) net_calls_to_write_nodata_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(net_calls_to_write_nodata_stat); + +#ifndef INK_NO_SOCKS + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.socks.connections_successful", + RECD_INT, RECP_NULL, (int) socks_connections_successful_stat, RecRawStatSyncSum); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.socks.connections_unsuccessful", + RECD_INT, RECP_NULL, (int) socks_connections_unsuccessful_stat, RecRawStatSyncSum); + + RecRegisterRawStat(net_rsb, RECT_PROCESS, + "proxy.process.socks.connections_currently_open", + RECD_INT, RECP_NON_PERSISTENT, (int) socks_connections_currently_open_stat, RecRawStatSyncSum); + NET_CLEAR_DYN_STAT(socks_connections_currently_open_stat); +#endif + +} + +void +ink_net_init(ModuleVersion version) +{ + static int init_called = 0; + + ink_release_assert(!checkModuleVersion(version, NET_SYSTEM_MODULE_VERSION)); + if (!init_called) { + // do one time stuff + // create a stat block for NetStats + net_rsb = RecAllocateRawStatBlock((int) Net_Stat_Count); + configure_net(); + register_net_stats(); + } + + init_called = 1; +} diff --git a/iocore/net/NetConfig.cc b/iocore/net/NetConfig.cc new file mode 100644 index 00000000..4710f1f0 --- /dev/null +++ b/iocore/net/NetConfig.cc @@ -0,0 +1,105 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_NetConfig.h" + +#define NULL 0 + +int net_config_poll_timeout = DEFAULT_POLL_TIMEOUT; +int net_config_fds_throttle = 8000; +int net_config_listen_backlog = 1024; + + +// SSL config +// # proxy.config.ssl.enabled should be: +// # 0 - none +// # 1 - SSL enabled +int net_config_ssl_mode = 1; + +// # proxy.config.ssl.accelerator.type should be: +// # 0 - none (software algorithms) +// # 1 - NCipher Nfast accelerator card +// # 2 - Rainbow Crypto Swift accelerator card +// # 3 - Compaq Atalla accelerator card +int net_config_sslAccelerator = 0; + +// # the following accelerator library paths only need +// # to be changed if the default path was not used +// # while installing the accelerator card. +const char *net_config_atallaAccelLibPath = "/opt/atalla/lib"; +const char *net_config_ncipherAccelLibPath = "/opt/nfast/toolkits/hwcrhk"; +const char *net_config_cswiftAccelLibPath = "/usr/lib"; + + +int net_config_ssl_accept_port_number = 8443; + +// # Client certification level should be: +// # 0 no client certificates +// # 1 client certificates optional +// # 2 client certificates required +int net_config_clientCertLevel = 0; + +// # Server cert filename is the name of the cert file +// # for a single cert system and the default cert name +// # for a multiple cert system. +const char *net_config_serverCertFilename = "server.pem"; + +// # This is the path that will be used for both single and +// # multi cert systems. +const char *net_config_serverCertRelativePath = "etc/trafficserver"; + +// # Fill in private key file and path only if the server's +// # private key is not contained in the server certificate file. +// # For multiple cert systems, if any private key is not contained +// # in the cert file, you must fill in the private key path. +char *net_config_ssl_server_private_key_filename = NULL; +char *net_config_ssl_server_private_key_path = NULL; + +// # The CA file name and path are the +// # certificate authority certificate that +// # client certificates will be verified against. +char *net_config_CACertFilename = NULL; +char *net_config_CACertRelativePath = NULL; + + +// ################################ +// # client related configuration # +// ################################ + +int net_config_clientVerify = 0; +char *net_config_ssl_client_cert_filename = NULL; +const char *net_config_ssl_client_cert_path = "etc/trafficserver"; + +// # Fill in private key file and path only if the client's +// # private key is not contained in the client certificate file. +char *net_config_ssl_client_private_key_filename = NULL; +char *net_config_ssl_client_private_key_path = NULL; + +// # The CA file name and path are the +// # certificate authority certificate that +// # server certificates will be verified against. +char *net_config_clientCACertFilename = NULL; +char *net_config_clientCACertRelativePath = NULL; + + +const char *net_config_multicert_config_file = "ssl_multicert.config"; diff --git a/iocore/net/NetTest-http-server.c b/iocore/net/NetTest-http-server.c new file mode 100644 index 00000000..e8183143 --- /dev/null +++ b/iocore/net/NetTest-http-server.c @@ -0,0 +1,196 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +IOBufferBlock *resp_blk; +int doc_len; + +struct NetTesterSM:public Continuation +{ + VIO *read_vio; + IOBufferReader *reader, *resp_reader; + NetVConnection *vc; + MIOBuffer *req_buf, *resp_buf; + char request[2000]; + int req_len; + + + NetTesterSM(ProxyMutex * _mutex, NetVConnection * _vc):Continuation(_mutex) + { + MUTEX_TRY_LOCK(lock, mutex, _vc->thread); + ink_release_assert(lock); + vc = _vc; + Debug("net_test", "Accepted a connection"); + SET_HANDLER(&NetTesterSM::handle_read); + req_buf = new_MIOBuffer(1); + reader = req_buf->alloc_reader(); + read_vio = vc->do_io_read(this, INT64_MAX, req_buf); + //vc->set_inactivity_timeout(HRTIME_SECONDS(60)); + resp_buf = new_empty_MIOBuffer(6); + resp_buf->append_block(resp_blk->clone()); + req_len = 0; + resp_reader = resp_buf->alloc_reader(); + } + + + ~NetTesterSM() + { + req_buf->dealloc_all_readers(); + req_buf->clear(); + free_MIOBuffer(req_buf); + + resp_buf->dealloc_all_readers(); + resp_buf->clear(); + free_MIOBuffer(resp_buf); + } + + /* ********************* jtest sample request ********************** + GET http://npdev:8080/0.5216393021/6000 HTTP/1.0 + Proxy-Connection: Keep-Alive + */ + + int handle_read(int event, void *data) + { + int r; + char *str; + switch (event) { + case VC_EVENT_READ_READY: + r = reader->read_avail(); + reader->read(&request[req_len], r); + req_len += r; + request[req_len] = 0; + Debug("net_test", "%s\n", request); + fflush(stdout); + //vc->set_inactivity_timeout(HRTIME_SECONDS(30)); + if (strcmp(&request[req_len - 4], "\r\n\r\n") == 0) { + Debug("net_test", "The request header is :\n%s\n", request); + // parse and get the doc size + SET_HANDLER(&NetTesterSM::handle_write); + ink_debug_assert(doc_len == resp_reader->read_avail()); + vc->do_io_write(this, doc_len, resp_reader); + //vc->set_inactivity_timeout(HRTIME_SECONDS(10)); + } + break; + case VC_EVENT_READ_COMPLETE: + /* FALLSTHROUGH */ + case VC_EVENT_EOS: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + Debug("net_test", "%s", str); + fflush(stdout); + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + vc->do_io_close(); + // fixme + // handle timeout events + break; + default: + ink_release_assert(!"unknown event"); + + } + return EVENT_CONT; + } + + + int handle_write(int event, Event * e) + { + switch (event) { + case VC_EVENT_WRITE_READY: + break; + + case VC_EVENT_WRITE_COMPLETE: + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + vc->do_io_close(); + delete this; + return EVENT_DONE; + break; + default: + ink_release_assert(!"unknown event"); + } + return EVENT_CONT; + } + + + +}; + + +struct NetTesterAccept:public Continuation +{ + + NetTesterAccept(ProxyMutex * _mutex):Continuation(_mutex) + { + SET_HANDLER(&NetTesterAccept::handle_accept); + } + + int handle_accept(int event, void *data) + { + Debug("net_test", "Accepted a connection\n"); + fflush(stdout); + NetVConnection *vc = (NetVConnection *) data; + NEW(new NetTesterSM(new_ProxyMutex(), vc)); + return EVENT_CONT; + } + + +}; + + + +struct Stop:public Continuation +{ + Action *a; + Stop(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&Stop::stop); + } + + int stop(int event, Event * e) + { + a->cancel(); + return EVENT_DONE; + } +}; + + +int +test_main() +{ + const char *response_hdr = "HTTP/1.0 200 OK\n" "Content-Type: text/html\n" "Content-Length: 8000\r\n\r\n"; + + resp_blk = new_IOBufferBlock(); + resp_blk->alloc(6); + char *b = resp_blk->start(); + strcpy(b, response_hdr); + memset(b + strlen(response_hdr), 'x', 8000); + resp_blk->fill(doc_len = strlen(response_hdr) + 8000); + + Action *a = sslNetProcessor.accept(NEW(new NetTesterAccept(new_ProxyMutex())), + 8080, true); + + return 0; +} diff --git a/iocore/net/NetTest-simple-proxy.c b/iocore/net/NetTest-simple-proxy.c new file mode 100644 index 00000000..ce718258 --- /dev/null +++ b/iocore/net/NetTest-simple-proxy.c @@ -0,0 +1,312 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +static unsigned int +get_addr(char *host) +{ + unsigned int addr = inet_addr(host); + struct hostent *host_info = NULL; + + if (!addr || (-1 == (int) addr)) { + host_info = gethostbyname(host); + if (!host_info) { + perror("gethostbyname"); + return (unsigned int) -1; + } + addr = *((unsigned int *) host_info->h_addr); + } + return addr; +} + + + +char *origin_server = "trafficserver.apache.org"; +unsigned int origin_server_ip; +unsigned short origin_server_port = 8080; + +struct NetTesterSM:public Continuation +{ + VIO *client_read_vio; + VIO *client_resp_write_vio; + VIO *server_resp_read_vio; + int server_vc_closed, client_vc_closed; + + IOBufferReader *client_reader, *client_parse_reader; + + NetVConnection *client_vc, *server_vc; + MIOBuffer *request_buf; + MIOBuffer *response_buf; + char request[2000]; + int req_len; + + + NetTesterSM(ProxyMutex * _mutex, NetVConnection * _vc):Continuation(_mutex), + server_vc_closed(0), client_vc_closed(0) + { + MUTEX_TRY_LOCK(lock, mutex, _vc->thread); + ink_release_assert(lock); + client_vc = _vc; + server_vc = NULL; + SET_HANDLER(&NetTesterSM::handle_request_read_from_client); + // jtest headers are really short + request_buf = new_MIOBuffer(1); + response_buf = new_MIOBuffer(8); + client_reader = request_buf->alloc_reader(); + client_parse_reader = request_buf->alloc_reader(); + client_read_vio = client_vc->do_io_read(this, INT_MAX, request_buf); + //client_vc->set_inactivity_timeout(HRTIME_SECONDS(60)); + req_len = 0; + } + + + ~NetTesterSM() + { + request_buf->dealloc_all_readers(); + request_buf->clear(); + free_MIOBuffer(request_buf); + response_buf->dealloc_all_readers(); + response_buf->clear(); + free_MIOBuffer(response_buf); + //close_server_vc(); + //close_client_vc(); + } + + /* ********************* jtest sample request ********************** + GET http://npdev:8080/0.5216393021/6000 HTTP/1.0 + Proxy-Connection: Keep-Alive + */ + + int handle_request_read_from_client(int event, void *data) + { + int r; + char *str; + switch (event) { + case VC_EVENT_READ_READY: + r = client_parse_reader->read_avail(); + client_parse_reader->read(&request[req_len], r); + req_len += r; + request[req_len] = 0; + Debug("net_test", "%s\n", request); + fflush(stdout); + //client_vc->set_inactivity_timeout(HRTIME_SECONDS(30)); + if (strcmp(&request[req_len - 4], "\r\n\r\n") == 0) { + Debug("net_test", "The request header is :\n%s\n", request); + client_vc->cancel_inactivity_timeout(); + // connect to the origin server + SET_HANDLER(&NetTesterSM::handle_server_connect); + sslNetProcessor.connect_re(this, origin_server_ip, origin_server_port); + } + break; + case VC_EVENT_READ_COMPLETE: + /* FALLSTHROUGH */ + case VC_EVENT_EOS: + r = client_parse_reader->read_avail(); + str = NEW(new char[r + 10]); + client_parse_reader->read(str, r); + /* FALLSTHROUGH */ + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + close_client_vc(); + // fixme + // handle timeout events + break; + default: + ink_release_assert(!"unknown event"); + + } + return EVENT_CONT; + } + + int handle_server_connect(int event, Event * e) + { + switch (event) { + case NET_EVENT_OPEN: + server_vc = (NetVConnection *) e; + SET_HANDLER(&NetTesterSM::handle_write_request_to_server); + Debug("net_test", "connected to server\n"); + Debug("net_test", "writing %d to server\n", client_reader->read_avail()); + server_vc->do_io_write(this, client_reader->read_avail(), client_reader); + //vc->set_inactivity_timeout(HRTIME_SECONDS(10)); + break; + case NET_EVENT_OPEN_FAILED: + default: + close_client_vc(); + delete this; + } + return EVENT_CONT; + } + + int handle_write_request_to_server(int event, Event * e) + { + IOBufferReader *resp_reader; + switch (event) { + case VC_EVENT_WRITE_READY: + Debug("net_test", "wrote some bytes to server\n"); + break; + + case VC_EVENT_WRITE_COMPLETE: + Debug("net_test", "wrote request to server\n"); + SET_HANDLER(&NetTesterSM::handle_response_pump); + resp_reader = response_buf->alloc_reader(); + + response_buf->autopilot = 1; + server_resp_read_vio = server_vc->do_io_read(this, INT64_MAX, response_buf); + client_resp_write_vio = client_vc->do_io_write(this, INT64_MAX, resp_reader); + response_buf->assign_reader_vio(client_resp_write_vio, resp_reader); + response_buf->assign_writer_vio(server_resp_read_vio); + break; + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + close_server_vc(); + close_client_vc(); + delete this; + return EVENT_DONE; + break; + default: + ink_release_assert(!"unknown event"); + } + return EVENT_CONT; + } + + void close_server_vc() + { + if (!server_vc_closed) + server_vc->do_io_close(); + server_vc = NULL; + server_vc_closed = 1; + } + + void close_client_vc() + { + if (!client_vc_closed) + client_vc->do_io_close(); + client_vc = NULL; + client_vc_closed = 1; + } + + int handle_response_pump(int event, Event * e) + { + int doc_len; + switch (event) { + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + close_server_vc(); + close_client_vc(); + delete this; + return EVENT_DONE; + break; + + + case VC_EVENT_WRITE_READY: + case VC_EVENT_READ_READY: + ink_release_assert(!"unexpected READY event in handle_response_pump"); + break; + + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + doc_len = server_resp_read_vio->ndone; + Debug("net_test", "Got response %d bytes from server\n", doc_len); + close_server_vc(); + if (client_resp_write_vio->ndone != doc_len) { + client_resp_write_vio->set_nbytes(doc_len); + client_vc->reenable(client_resp_write_vio); + } else { + Debug("net_test", "Wrote response %d bytes to client\n", client_resp_write_vio->ndone); + close_client_vc(); + delete this; + return EVENT_DONE; + } + break; + case VC_EVENT_WRITE_COMPLETE: + Debug("net_test", "Wrote response %d bytes to client\n", client_resp_write_vio->ndone); + close_client_vc(); + delete this; + return EVENT_DONE; + + default: + ink_release_assert(!"unexpected event in handle_response_pump"); + } + return EVENT_CONT; + + } + + +}; + + +struct NetTesterAccept:public Continuation +{ + + NetTesterAccept(ProxyMutex * _mutex):Continuation(_mutex) + { + SET_HANDLER(&NetTesterAccept::handle_accept); + } + + int handle_accept(int event, void *data) + { + Debug("net_test", "Accepted a connection\n"); + NetVConnection *vc = (NetVConnection *) data; + NEW(new NetTesterSM(new_ProxyMutex(), vc)); + return EVENT_CONT; + } + + +}; + +//#define TEST_ACCEPT_CANCEL + +struct Stop:public Continuation +{ + Action *a; + Stop(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&Stop::stop); + } + + int stop(int event, Event * e) + { + printf("Cancelling accept\n"); + a->cancel(); + return EVENT_DONE; + } +}; + + +int +test_main() +{ + Action *a; + origin_server_ip = get_addr(origin_server); + + a = sslNetProcessor.accept(NEW(new NetTesterAccept(new_ProxyMutex())), 45080, true); + +#ifdef TEST_ACCEPT_CANCEL + Stop *s = NEW(new Stop(new_ProxyMutex())); + eventProcessor.schedule_in(s, HRTIME_SECONDS(10)); + s->a = a; +#endif + + return 0; +} diff --git a/iocore/net/NetVCTest.cc b/iocore/net/NetVCTest.cc new file mode 100644 index 00000000..8366990b --- /dev/null +++ b/iocore/net/NetVCTest.cc @@ -0,0 +1,425 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + NetVCTest.cc + + Description: + Unit test for infastructure for VConnections implementing the + NetVConnection interface + + + + + ****************************************************************************/ + +#include "P_Net.h" + +// Get rid of any previous MIN declaration, since we have our own +// funky MIN here. /leif +#if defined(MIN) +#undef MIN +#endif +#define MIN(x,y) (x <= y) ? x : y; + +// Each test requires two definition entries. One for the passive +// side of the connection and one for the active side +// +// test fields: +// +// name bytes_to_send nbytes_write bytes_to_read nbytes_read write_per timeout read_term write_term +// +NVC_test_def netvc_tests_def[] = { + + {"basic", 2000, 2000, 2000, 2000, 50, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + {"basic", 2000, 2000, 2000, 2000, 50, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + + {"basic2", 10001, 10001, 5001, 5001, 1024, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + {"basic2", 5001, 5001, 10001, 10001, 1024, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + + {"large", 1000000, 1000000, 500000, 500000, 8192, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + {"large", 500000, 500000, 1000000, 1000000, 8192, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + + // Test large block transfers + {"larget", 1000000, 1000000, 500000, 500000, 40000, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + {"larget", 500000, 500000, 1000000, 1000000, 40000, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + + {"eos", 4000, 4000, 10, 10, 8192, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + {"eos", 10, 10, 6000, 6000, 8192, 10, VC_EVENT_EOS, VC_EVENT_WRITE_COMPLETE} + , + + {"werr", 4000, 4000, 10, 10, 129, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_ERROR} + , + {"werr", 10, 10, 10, 10, 129, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + + {"itimeout", 6000, 8000, 10, 10, 512, 10, VC_EVENT_READ_COMPLETE, VC_EVENT_INACTIVITY_TIMEOUT} + , + {"itimeout", 10, 10, 6000, 8000, 512, 20, VC_EVENT_EOS, VC_EVENT_WRITE_COMPLETE} + , + + // Test the small transfer code one byts at a time + {"smallt", 400, 400, 500, 500, 1, 15, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + {"smallt", 500, 500, 400, 400, 1, 15, VC_EVENT_READ_COMPLETE, VC_EVENT_WRITE_COMPLETE} + , + + // The purpose of this test is show that stack can over flow if we move too + // small of blocks between the buffers. EVENT_NONE is wild card error event + // since which side gets the timeout is unpredictable + {"overflow", 1000000, 1000000, 50, 50, 1, 20, VC_EVENT_READ_COMPLETE, EVENT_NONE} + , + {"overflow", 50, 50, 0, 35000, 1024, 35, EVENT_NONE, VC_EVENT_WRITE_COMPLETE} + +}; +int num_netvc_tests = SIZE(netvc_tests_def); + + +NetVCTest::NetVCTest(): +Continuation(NULL), +test_cont_type(NET_VC_TEST_ACTIVE), +test_vc(NULL), regress(NULL), driver(NULL), read_vio(NULL), +write_vio(NULL), read_buffer(NULL), write_buffer(NULL), +reader_for_rbuf(NULL), reader_for_wbuf(NULL), write_bytes_to_add_per(0), +timeout(0), +actual_bytes_read(0), actual_bytes_sent(0), write_done(false), read_done(false), +read_seed(0), write_seed(0), bytes_to_send(0), bytes_to_read(0), +nbytes_read(0), nbytes_write(0), expected_read_term(0), +expected_write_term(0), test_name(NULL), module_name(NULL), debug_tag(NULL) +{ +} + +NetVCTest::~NetVCTest() +{ + mutex = NULL; + + if (read_buffer) { + Debug(debug_tag, "Freeing read MIOBuffer with %d blocks on %s", + read_buffer->max_block_count(), (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive"); + free_MIOBuffer(read_buffer); + read_buffer = NULL; + } + + if (write_buffer) { + Debug(debug_tag, "Freeing write MIOBuffer with %d blocks on %s", + write_buffer->max_block_count(), (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive"); + free_MIOBuffer(write_buffer); + write_buffer = NULL; + } +} + +void +NetVCTest::init_test(NetVcTestType_t c_type, NetTestDriver * driver_arg, + NetVConnection * nvc, RegressionTest * robj, + NVC_test_def * my_def, const char *module_name_arg, const char *debug_tag_arg) +{ + + test_cont_type = c_type; + driver = driver_arg; + test_vc = nvc; + regress = robj; + module_name = module_name_arg; + debug_tag = debug_tag_arg; + + bytes_to_send = my_def->bytes_to_send; + bytes_to_read = my_def->bytes_to_read; + + nbytes_read = my_def->nbytes_read; + nbytes_write = my_def->nbytes_write; + + write_bytes_to_add_per = my_def->write_bytes_per; + timeout = my_def->timeout; + expected_read_term = my_def->expected_read_term; + expected_write_term = my_def->expected_write_term; + test_name = my_def->test_name; + + mutex = new_ProxyMutex(); + SET_HANDLER(&NetVCTest::main_handler); + + if (c_type == NET_VC_TEST_ACTIVE) { + start_test(); + } +} + +void +NetVCTest::start_test() +{ + + test_vc->set_inactivity_timeout(HRTIME_SECONDS(timeout)); + test_vc->set_active_timeout(HRTIME_SECONDS(timeout + 5)); + + read_buffer = new_MIOBuffer(); + write_buffer = new_MIOBuffer(); + + reader_for_rbuf = read_buffer->alloc_reader(); + reader_for_wbuf = write_buffer->alloc_reader(); + + if (nbytes_read > 0) { + read_vio = test_vc->do_io_read(this, nbytes_read, read_buffer); + } else { + read_done = true; + } + + if (nbytes_write > 0) { + write_vio = test_vc->do_io_write(this, nbytes_write, reader_for_wbuf); + } else { + write_done = true; + } +} + + +int +NetVCTest::fill_buffer(MIOBuffer * buf, uint8_t * seed, int bytes) +{ + + char *space = (char *) xmalloc(bytes); + char *tmp = space; + int to_add = bytes; + + while (bytes > 0) { + *tmp = *seed; + (*seed)++; + bytes--; + tmp++; + } + + buf->write(space, to_add); + xfree(space); + + return to_add; +} + +int +NetVCTest::consume_and_check_bytes(IOBufferReader * r, uint8_t * seed) +{ + + uint8_t *tmp, *end; + int b_consumed = 0; + + if (actual_bytes_read >= bytes_to_read) { + return 1; + } + + while (r->read_avail() > 0) { + int64_t b_avail = r->block_read_avail(); + + tmp = (uint8_t *) r->start(); + end = tmp + b_avail; + b_consumed = 0; + + while (tmp < end && actual_bytes_read < bytes_to_read) { + actual_bytes_read++; + b_consumed++; + if (*tmp != *seed) { + r->consume(b_consumed); + return 0; + + } else { + tmp++; + (*seed)++; + } + } + + Debug(debug_tag, "consume_&_check: read %d, to_read %d", actual_bytes_read, bytes_to_read); + r->consume(b_consumed); + } + + return 1; +} + +void +NetVCTest::write_finished() +{ + if (nbytes_write != write_vio->ndone && expected_write_term == VC_EVENT_WRITE_COMPLETE) { + record_error("write: bad ndone value"); + return; + } + + write_done = true; + + if (read_done) { + test_vc->do_io_close(); + finished(); + } else { + test_vc->do_io_shutdown(IO_SHUTDOWN_WRITE); + } +} + +void +NetVCTest::read_finished() +{ + if (nbytes_read != read_vio->ndone && expected_read_term != VC_EVENT_EOS && expected_read_term != VC_EVENT_NONE) { + record_error("read: bad ndone value"); + return; + } + + read_done = true; + + if (write_done) { + test_vc->do_io_close(); + finished(); + } else { + test_vc->do_io_shutdown(IO_SHUTDOWN_READ); + } +} + +void +NetVCTest::record_error(const char *msg) +{ + + rprintf(regress, " %s test: %s failed : %s : on %s\n", + module_name, test_name, msg, (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive"); + ink_atomic_increment(&driver->errors, 1); + + test_vc->do_io_close(); + finished(); +} + +void +NetVCTest::finished() +{ + eventProcessor.schedule_imm(driver); + delete this; +} + +void +NetVCTest::write_handler(int event) +{ + + Debug(debug_tag, "write_handler received event %d on %s", + event, (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive"); + + switch (event) { + case VC_EVENT_WRITE_READY: + if (write_vio->ndone < bytes_to_send) { + int left_to_send = bytes_to_send - actual_bytes_sent; + ink_assert(left_to_send >= 0); + int to_fill = MIN(left_to_send, write_bytes_to_add_per); + actual_bytes_sent += fill_buffer(write_buffer, &write_seed, to_fill); + write_vio->reenable(); + } + break; + case VC_EVENT_WRITE_COMPLETE: + write_finished(); + break; + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + case VC_EVENT_ERROR: + if (expected_write_term != event && expected_write_term != VC_EVENT_NONE) { + record_error("write: Unexpected error or timeout"); + } else { + write_finished(); + } + break; + default: + record_error("write: Unknown event"); + break; + } +} + +void +NetVCTest::read_handler(int event) +{ + + Debug(debug_tag, "read_handler received event %d on %s", + event, (test_cont_type == NET_VC_TEST_ACTIVE) ? "Active" : "Passive"); + + switch (event) { + case VC_EVENT_READ_READY: + if (consume_and_check_bytes(reader_for_rbuf, &read_seed) == 0) { + record_error("Read content corrupt"); + return; + } else { + read_vio->reenable(); + } + break; + case VC_EVENT_READ_COMPLETE: + if (consume_and_check_bytes(reader_for_rbuf, &read_seed) == 0) { + record_error("Read content corrupt"); + return; + } else { + read_finished(); + } + break; + case VC_EVENT_EOS: + if (expected_read_term != VC_EVENT_EOS && expected_read_term != VC_EVENT_NONE) { + record_error("read: Unexpected EOS Event"); + } else { + read_finished(); + } + break; + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + case VC_EVENT_ERROR: + if (expected_read_term != event && expected_read_term != VC_EVENT_NONE) { + record_error("read: Unexpected error or timeout"); + } else { + read_finished(); + } + break; + default: + record_error("read: Unknown event"); + break; + } +} + +int +NetVCTest::main_handler(int event, void *data) +{ + + if (event == NET_EVENT_ACCEPT) { + test_vc = (NetVConnection *) data; + start_test(); + return 0; + } + + if (data == read_vio) { + read_handler(event); + } else if (data == write_vio) { + write_handler(event); + } else { + record_error("main: unknown event"); + } + + return 0; +} + + +NetTestDriver::NetTestDriver(): +Continuation(NULL), errors(0), r(NULL), pstatus(NULL) +{ +} + +NetTestDriver::~NetTestDriver() +{ +} diff --git a/iocore/net/NetVConnection.cc b/iocore/net/NetVConnection.cc new file mode 100644 index 00000000..1050a470 --- /dev/null +++ b/iocore/net/NetVConnection.cc @@ -0,0 +1,46 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + NetVConnection.cc + + This file implements an I/O Processor for network I/O. + + + ****************************************************************************/ + +#include "P_Net.h" + +Action * +NetVConnection::send_OOB(Continuation *, char *, int) +{ + return ACTION_RESULT_DONE; +} + +void +NetVConnection::cancel_OOB() +{ + return; +} + diff --git a/iocore/net/P_CompletionUtil.h b/iocore/net/P_CompletionUtil.h new file mode 100644 index 00000000..f177b002 --- /dev/null +++ b/iocore/net/P_CompletionUtil.h @@ -0,0 +1,49 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _COMPLETION_UTIL_H_ +#define _COMPLETION_UTIL_H_ +// interface +class completionUtil +{ +public: + static Event *create(); + static void destroy(Event * e); + static void setThread(Event * e, EThread * t); + static void setContinuation(Event * e, Continuation * c); + static void *getHandle(Event * e); + static void setHandle(Event * e, void *handle); + static void setInfo(Event * e, int fd, IOBufferBlock * buf, int actual, int errno_); + static void setInfo(Event * e, int fd, struct msghdr *msg, int actual, int errno_); + static int getBytesTransferred(Event * e); + static IOBufferBlock *getIOBufferBlock(Event * e); + static Continuation *getContinuation(Event * e); + static int getError(Event * e); + static void releaseReferences(Event * e); +}; + +#ifndef _IOCORE_WIN32_WINNT +#include "P_UnixCompletionUtil.h" +#endif + +#endif diff --git a/iocore/net/P_Connection.h b/iocore/net/P_Connection.h new file mode 100644 index 00000000..e48bf746 --- /dev/null +++ b/iocore/net/P_Connection.h @@ -0,0 +1,195 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + + Connection.h + Description: + struct Connection + struct Server + struct ConnectionManager + + struct ConnectionManager + ======================== + + struct ConnectionManager provides the interface for network or disk + connections. There is a global ConnectionManager in the system + (connectionManager). + + Connection * connect() + Connection * accept() + + The accept call is a blocking call while connect is non-blocking. They + returns a new Connection instance which is an handle to the newly created + connection. The connection `q instance can be used later for read/writes + using an intance of IOProcessor class. + + + **************************************************************************/ + +#ifndef __CONNECTION_H__ +#define __CONNECTION_H__ + +#include "libts.h" + +struct NetVCOptions; + +// +// Defines +// + +#define NON_BLOCKING_CONNECT true +#define BLOCKING_CONNECT false +#define CONNECT_WITH_TCP true +#define CONNECT_WITH_UDP false +#define NON_BLOCKING true +#define BLOCKING false +#define BIND_RANDOM_PORT true +#define BIND_ANY_PORT false +#define ENABLE_MC_LOOPBACK true +#define DISABLE_MC_LOOPBACK false +#define BC_NO_CONNECT true +#define BC_CONNECT false +#define BC_NO_BIND true +#define BC_BIND false + +/////////////////////////////////////////////////////////////////////// +// +// Connection +// +/////////////////////////////////////////////////////////////////////// +struct Connection +{ + SOCKET fd; ///< Socket for connection. + struct sockaddr_storage sa; ///< Remote address. + bool is_bound; ///< Flag for already bound to a local address. + bool is_connected; ///< Flag for already connected. + + /** Create and initialize the socket for this connection. + + A socket is created and the options specified by @a opt are + set. The socket is @b not connected. + + @note It is important to pass the same @a opt to this method and + @c connect. + + @return 0 on success, -ERRNO on failure. + @see connect + */ + int open( + NetVCOptions const& opt = DEFAULT_OPTIONS ///< Socket options. + ); + + /** Connect the socket. + + The socket is connected to the remote @a addr and @a port. The + @a opt structure is used to control blocking on the socket. All + other options are set via @c open. It is important to pass the + same @a opt to this method as was passed to @c open. + + @return 0 on success, -ERRNO on failure. + @see open + */ + int connect( + uint32_t addr, ///< Remote address. + uint16_t port, ///< Remote port. + NetVCOptions const& opt = DEFAULT_OPTIONS ///< Socket options + ); + + + /// Set the internal socket address struct. + /// @internal Used only by ICP. + void setRemote( + uint32_t addr, ///< Remote IP address. + uint16_t port ///< Remote port. + ) { + sockaddr_in* sa_in = reinterpret_cast(&sa); + sa.ss_family = AF_INET; + sa_in->sin_port = htons(port); + sa_in->sin_addr.s_addr = addr; + memset(&(sa_in->sin_zero), 0, 8); + } + + int setup_mc_send(unsigned int mc_ip, int mc_port, + unsigned int my_ip, int my_port, + bool non_blocking = NON_BLOCKING, + unsigned char mc_ttl = 1, bool mc_loopback = DISABLE_MC_LOOPBACK, Continuation * c = NULL); + + int setup_mc_receive(unsigned int mc_ip, int port, + bool non_blocking = NON_BLOCKING, Connection * sendchan = NULL, Continuation * c = NULL); + + int close(); // 0 on success, -errno on failure + + virtual ~ Connection(); + Connection(); + + /// Default options. + static NetVCOptions const DEFAULT_OPTIONS; + +protected: + void _cleanup(); +}; + +/////////////////////////////////////////////////////////////////////// +// +// Server +// +/////////////////////////////////////////////////////////////////////// +struct Server: public Connection +{ + // + // IP address in network byte order + // + unsigned int accept_ip; + char *accept_ip_str; + + /// If set, transparently connect to origin server for requests. + bool f_outbound_transparent; + /// If set, the related incoming connect was transparent. + bool f_inbound_transparent; + + // + // Use this call for the main proxy accept + // + int proxy_listen(bool non_blocking = false); + + int accept(Connection * c); + + // + // Listen on a socket. We assume the port is in host by orderr, but + // that the IP address (specified by accept_ip) has already been + // converted into network byte order + // + + int listen(int port, int domain = AF_INET, bool non_blocking = false, int recv_bufsize = 0, int send_bufsize = 0); + int setup_fd_for_listen(bool non_blocking = false, int recv_bufsize = 0, int send_bufsize = 0); + + Server() + : Connection() + , accept_ip(INADDR_ANY) + , accept_ip_str(NULL) + , f_outbound_transparent(false) + { } +}; + +#endif /*_Connection_h*/ diff --git a/iocore/net/P_InkBulkIO.h b/iocore/net/P_InkBulkIO.h new file mode 100644 index 00000000..96937f90 --- /dev/null +++ b/iocore/net/P_InkBulkIO.h @@ -0,0 +1,186 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef _INK_BULK_IO_H +#define _INK_BULK_IO_H + +#ifndef _KERNEL_ +#include +#include +#endif + +/* + * We are following the convention of the ioctl cmd constants: + * - the first 8 bits contain the character representing the device + * - bits 8-15 refer to the ioctl + */ +#define INKBIO_IOC ('x' << 8) /* 'x' to represent 'xx' */ + +#define INKBIO_SEND (INKBIO_IOC | 1) +#define INKBIO_BALLOC (INKBIO_IOC | 2) + +#define INKBIO_GET_STATS (INKBIO_IOC | 3) + +#define INKBIO_NOP (INKBIO_IOC | 7) +#define INKBIO_MEMCPY (INKBIO_IOC | 8) + +/* For ioctl's that are destined to the STREAMS module for getting at q ptrs */ +#define INKBIO_REGISTER 1024 + +#define INKBIO_MAX_BLOCKS 512 + +/* 1500 bytes of data; 100 bytes for header */ +#define INKBIO_MTU_SIZE 1500 +#define INKBIO_PKT_SIZE_WITH_UDPHDR (INKBIO_MTU_SIZE - (sizeof(struct ip) + sizeof(struct udphdr))) +#define INKBIO_PKT_SIZE_WO_UDPHDR (INKBIO_MTU_SIZE - sizeof(struct ip)) +/* 100 for ethernet and anything else; 20 for ip---every pkt got an ip header */ +#define INKBIO_PKT_HEADER_SIZE (100 + sizeof(struct ip)) +#define INKBIO_PKT_FOOTER_SIZE 0 +#define INKBIO_BLOCK_SIZE (INKBIO_MTU_SIZE + INKBIO_PKT_HEADER_SIZE + INKBIO_PKT_FOOTER_SIZE) + +#define INKBIO_MAX_UMEM_SIZE (INKBIO_BLOCK_SIZE * INKBIO_MAX_BLOCKS) +/* + * Describes a block of BulkIO memory + */ +struct InkBulkIOBlock +{ + void *ptr; /* where is it at */ + uint32_t id; +}; + +typedef struct +{ + uint32_t nextFreeIdx; + uint32_t numFreeBlocks; + uint32_t freeBlockId[INKBIO_MAX_BLOCKS]; +} InkBulkIOFreeBlockInfo_t; + + +/* + * Describes a packet to be sent. Found after a request header in a request block + */ +struct InkBulkIOPkt +{ + uint32_t blockID; + /* Set only in the first fragment of a chain. Contains the size of the packet */ + uint32_t pktsize; + /* If the thing is a chain, the size of the fragment */ + uint16_t fragsize; + uint16_t inChain:1; + uint16_t reserved:15; +}; + +struct InkBulkIOAddrInfo +{ + uint32_t ip; + uint16_t port; +}; + +/* + * Format of a sendto request: + * - sender, receiver: ip/port info. + * - list of InkBulkIOPkt terminated by a 0xffffffff + */ +struct InkBulkIOSendtoRequest +{ + /* declarations are done so that things in a req. block are usually 4-byte aligned */ + uint16_t pktCount; + struct InkBulkIOAddrInfo src; + struct InkBulkIOAddrInfo dest; +}; + +/* + * Format of a split request: + * - sender: ip/port info. and count of # of receivers; also a boolean that + * describes if there is a per-receiver specific header that has to be + * tacked on before each data-payload. + * - a list of InkBulkIOPkt that describes the payload being split; + * - a list of tuples + * terminate list by 0xffffffff + */ + +struct InkBulkIOSplitRequest +{ + /* declarations are done so that things in a req. block are usually 4-byte + * aligned */ + uint16_t recvCount; + struct InkBulkIOAddrInfo src; + uint16_t perDestHeader; /* boolean */ +}; + +/* + * Describes a request header, part of a request block + */ +struct InkBulkIORequest +{ + uint16_t reqType; /* one of sendto or split */ + union + { + struct InkBulkIOSendtoRequest sendto; + struct InkBulkIOSplitRequest split; + } request; +}; + +#define INKBIO_SENDTO_REQUEST 0x0a +#define INKBIO_SPLIT_REQUEST 0xf1 + +/* + * These 2 better be the same in user/kernel land + */ +#ifndef MAX +#define MAX(x, y) (x > y ? x : y) +#endif + +/* + * Purposely, under specify the size; we need to leave space for the "terminating" packet. + * Every block contains at least 1 request. + */ +#define INKBIO_MAX_PKTS_PER_REQ_BLOCK ((INKBIO_PKT_SIZE_WO_UDPHDR - \ + (sizeof(struct InkBulkIORequest) + sizeof(struct InkBulkIOPkt))) / \ + MAX((sizeof (struct InkBulkIORequest)), \ + (sizeof(struct InkBulkIOPkt)))) + +/* + * Requests are just block-ids---the block id points to the inkbio-block + * that describes the request. + */ +#define INKBIO_MAX_REQS_PER_REQ_BLOCK ((INKBIO_PKT_SIZE_WO_UDPHDR - sizeof(uint32_t)) / sizeof(uint32_t)) + +#define INKBIO_MAX_FRAGS_PER_REQ_BLOCK INKBIO_MAX_PKTS_PER_REQ_BLOCK + +/* + * There is always 1 req. block and 1 pkt. block. Next, + * Leave space for 1 "NULL" block for the Address information. + */ + +#define INKBIO_MAX_SPLIT_WO_HDR_PER_SPLIT_BLOCK ((INKBIO_PKT_SIZE_WO_UDPHDR - \ + (sizeof(struct InkBulkIORequest) + sizeof(struct InkBulkIOPkt) + sizeof(struct InkBulkIOAddrInfo))) / \ + (sizeof(struct InkBulkIOAddrInfo))) + +#define INKBIO_MAX_SPLIT_WITH_HDR_PER_SPLIT_BLOCK ((INKBIO_PKT_SIZE_WO_UDPHDR - \ + (sizeof(struct InkBulkIORequest) + sizeof(struct InkBulkIOPkt) + sizeof(struct InkBulkIOAddrInfo))) / \ + (sizeof(struct InkBulkIOPkt) + sizeof(struct InkBulkIOAddrInfo))) + + +#endif diff --git a/iocore/net/P_LibBulkIO.h b/iocore/net/P_LibBulkIO.h new file mode 100644 index 00000000..0d806714 --- /dev/null +++ b/iocore/net/P_LibBulkIO.h @@ -0,0 +1,178 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef _LIB_BULK_IO_H +#define _LIB_BULK_IO_H + +#if defined(solaris) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "P_InkBulkIO.h" + +struct InkBulkIOState +{ + int biofd; + void *sharedBuffer; + int sharedBufferSize; + InkBulkIOFreeBlockInfo_t freeList; + struct InkBulkIOBlock *blockInfo; + int numBlocks; +}; + +struct InkBulkIOSplit +{ + char *header; + int nbytes; + struct InkBulkIOAddrInfo dest; +}; + +struct InkBulkIOAggregator +{ + InkBulkIOAggregator() + { + metaReqCount = 0; + metablockInfo.ptr = NULL; + metablockInfo.id = 0xffffffff; + metablockReqPtr = NULL; + + lastReqFragCount = 0; + lastReq = NULL; + reqblockInfo.ptr = NULL; + reqblockInfo.id = 0xffffffff; + reqblockPktPtr = NULL; + + }; + struct InkBulkIOBlock metablockInfo; + // Location where the next req. block id should be stuffed in the meta block. + uint32_t *metablockReqPtr; + uint32_t metaReqCount; + struct InkBulkIOBlock reqblockInfo; + // Location where the next packet should be stuffed in the req. block + struct InkBulkIOPkt *reqblockPktPtr; + // # of fragments in the last request. + uint32_t lastReqFragCount; + struct InkBulkIORequest *lastReq; + void ResetLastRequestInfo() + { + lastReqFragCount = 0; + lastReq = NULL; + reqblockInfo.ptr = NULL; + reqblockInfo.id = 0xffffffff; + reqblockPktPtr = NULL; + }; + void ResetMetaBlockInfo() + { + metaReqCount = 0; + metablockInfo.ptr = NULL; + metablockInfo.id = 0xffffffff; + metablockReqPtr = NULL; + }; + bool AppendLastRequest() + { + if (metaReqCount >= INKBIO_MAX_REQS_PER_REQ_BLOCK) + return false; + + memcpy(metablockReqPtr, &(reqblockInfo.id), sizeof(uint32_t)); + metablockReqPtr++; + metaReqCount++; + return true; + }; + void TerminateMetaBlock() + { + *metablockReqPtr = 0xffffffff; + }; + void TerminateLastRequest() + { + reqblockPktPtr->blockID = 0xffffffff; + reqblockPktPtr->pktsize = 0xffff; + reqblockPktPtr->inChain = 0; + reqblockPktPtr->reserved = 0; + }; + void InitMetaBlock() + { + metablockReqPtr = (uint32_t *) metablockInfo.ptr; + metaReqCount = 0; + }; + void InitSendtoReqBlock() + { + reqblockPktPtr = (struct InkBulkIOPkt *) + ((caddr_t) reqblockInfo.ptr + sizeof(InkBulkIORequest)); + lastReq = (struct InkBulkIORequest *) reqblockInfo.ptr; + lastReq->reqType = INKBIO_SENDTO_REQUEST; + lastReq->request.sendto.pktCount = 0; + lastReqFragCount = 0; + }; + void InitSplitReqBlock() + { + reqblockPktPtr = (struct InkBulkIOPkt *) + ((caddr_t) reqblockInfo.ptr + sizeof(InkBulkIORequest)); + lastReq = (struct InkBulkIORequest *) reqblockInfo.ptr; + lastReq->reqType = INKBIO_SPLIT_REQUEST; + lastReq->request.split.recvCount = 0; + lastReq->request.split.perDestHeader = 0; + lastReqFragCount = 0; + }; + +}; + +/* + * Initialize the Bulk IO system and create a state cookie + */ +struct InkBulkIOState *BulkIOInit(int blockcount); +void BulkIOClose(struct InkBulkIOState *bioCookie); + +int BulkIOBlkAlloc(struct InkBulkIOState *bioCookie, int blkCount, struct InkBulkIOBlock *bioResult); + +int BulkIOAddPkt(struct InkBulkIOState *bioCookie, + struct InkBulkIOAggregator *bioAggregator, UDPPacketInternal * pkt, int sourcePort); + +int BulkIOSplitPkt(struct InkBulkIOState *bioCookie, + struct InkBulkIOAggregator *bioAggregator, UDPPacketInternal * pkt, int sourcePort); + +int BulkIOAppendToReqBlock(struct InkBulkIOState *bioCookie, + struct InkBulkIOAggregator *bioAggregator, Ptr pkt); + +int BulkIOSend(struct InkBulkIOState *bioCookie, uint32_t blkId); + +void BulkIORequestComplete(struct InkBulkIOState *bioCookie, struct InkBulkIOAggregator *bioAggregator); + +void BulkIOFlush(struct InkBulkIOState *bioCookie, struct InkBulkIOAggregator *bioAggregator); + +void CopyFromIOBufferBlock(char *dest, Ptr pktChain, uint32_t nbytes); +#endif + +#endif diff --git a/iocore/net/P_Net.h b/iocore/net/P_Net.h new file mode 100644 index 00000000..7be18c8b --- /dev/null +++ b/iocore/net/P_Net.h @@ -0,0 +1,138 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Net Subsystem + + +**************************************************************************/ +#ifndef __P_NET_H__ +#define __P_NET_H__ + +#ifndef INLINE_CC +#undef TS_INLINE +#define TS_INLINE inline +#endif + +// Net Stats + +enum Net_Stats +{ + net_handler_run_stat, + net_read_bytes_stat, + net_write_bytes_stat, + net_connections_currently_open_stat, + net_accepts_currently_open_stat, + net_calls_to_readfromnet_stat, + net_calls_to_readfromnet_afterpoll_stat, + net_calls_to_read_stat, + net_calls_to_read_nodata_stat, + net_calls_to_writetonet_stat, + net_calls_to_writetonet_afterpoll_stat, + net_calls_to_write_stat, + net_calls_to_write_nodata_stat, + socks_connections_successful_stat, + socks_connections_unsuccessful_stat, + socks_connections_currently_open_stat, + Net_Stat_Count +}; + +struct RecRawStatBlock; +extern RecRawStatBlock *net_rsb; +#define SSL_HANDSHAKE_WANT_READ 6 +#define SSL_HANDSHAKE_WANT_WRITE 7 +#define SSL_HANDSHAKE_WANT_ACCEPT 8 +#define SSL_HANDSHAKE_WANT_CONNECT 9 + +#define NET_DEBUG_COUNT_DYN_STAT(_x, _y) \ +RecIncrRawStatCount(net_rsb, mutex->thread_holding, (int)_x, _y) + +#define NET_INCREMENT_DYN_STAT(_x) \ +RecIncrRawStatSum(net_rsb, mutex->thread_holding, (int)_x, 1) + +#define NET_DECREMENT_DYN_STAT(_x) \ +RecIncrRawStatSum(net_rsb, mutex->thread_holding, (int)_x, -1) + +#define NET_SUM_DYN_STAT(_x, _r) \ +RecIncrRawStatSum(net_rsb, mutex->thread_holding, (int)_x, _r) + +#define NET_READ_DYN_SUM(_x, _sum) RecGetRawStatSum(net_rsb, (int)_x, &_sum) + +#define NET_READ_DYN_STAT(_x, _count, _sum) do {\ +RecGetRawStatSum(net_rsb, (int)_x, &_sum); \ +RecGetRawStatCount(net_rsb, (int)_x, &_count); \ +} while (0) + +#define NET_CLEAR_DYN_STAT(x) \ +do { \ + RecSetRawStatSum(net_rsb, x, 0); \ + RecSetRawStatCount(net_rsb, x, 0); \ +} while (0); + +// For global access +#define NET_SUM_GLOBAL_DYN_STAT(_x, _r) RecIncrGlobalRawStatSum(net_rsb, (_x), (_r)) +#define NET_READ_GLOBAL_DYN_SUM(_x, _sum) RecGetGlobalRawStatSum(net_rsb, _x, &_sum) + +#include "libts.h" +#include "P_EventSystem.h" +#include "I_Net.h" +#include "P_NetVConnection.h" +#include "P_UnixNet.h" +#include "P_UnixNetProcessor.h" +#include "P_NetAccept.h" +#include "P_UnixNetVConnection.h" +#include "P_UnixPollDescriptor.h" +#include "P_Socks.h" +#include "P_CompletionUtil.h" +#include "P_UDPNet.h" +#include "P_NetVCTest.h" +#include "P_LibBulkIO.h" + +#include "P_SSLConfig.h" +#include "P_SSLNetVConnection.h" +#include "P_SSLNetProcessor.h" +#include "P_SSLNetAccept.h" +#include "P_SSLCertLookup.h" + +#undef NET_SYSTEM_MODULE_VERSION +#define NET_SYSTEM_MODULE_VERSION makeModuleVersion( \ + NET_SYSTEM_MODULE_MAJOR_VERSION, \ + NET_SYSTEM_MODULE_MINOR_VERSION, \ + PRIVATE_MODULE_HEADER) +// libev backend flags +#if defined(solaris) +#define LIBEV_BACKEND_LIST (EVBACKEND_POLL | EVBACKEND_SELECT) // Level-Triggered +#else + #define LIBEV_BACKEND_LIST 0 /* auto */ +#endif + +// For very verbose iocore debugging. +#ifndef DEBUG +#define NetDebug if (0) dummy_debug +#else +#define NetDebug Debug +#endif + + +#endif diff --git a/iocore/net/P_NetAccept.h b/iocore/net/P_NetAccept.h new file mode 100644 index 00000000..848f49a0 --- /dev/null +++ b/iocore/net/P_NetAccept.h @@ -0,0 +1,131 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + NetAccept.h + + + NetAccept is a generalized facility which allows + Connections of different classes to be accepted either + from a blockable thread or by adaptive polling. + + It is used by the NetProcessor and the ClusterProcessor + and should be considered PRIVATE to processor implementations. + + + + ****************************************************************************/ +#ifndef __P_NETACCEPT_H__ +#define __P_NETACCEPT_H__ + +#include "libts.h" +#include "P_Connection.h" + + +struct NetAccept; +class Event; +// +// Default accept function +// Accepts as many connections as possible, returning the number accepted +// or -1 to stop accepting. +// +typedef int (AcceptFunction) (NetAccept * na, void *e, bool blockable); +typedef AcceptFunction *AcceptFunctionPtr; +AcceptFunction net_accept; + +class UnixNetVConnection; + +// TODO fix race between cancel accept and call back +struct NetAcceptAction:public Action, public RefCountObj +{ + Server *server; + + void cancel(Continuation * cont = NULL) { + Action::cancel(cont); + server->close(); + } + + Continuation *operator =(Continuation * acont) + { + return Action::operator=(acont); + } + + ~NetAcceptAction() { + Debug("net_accept", "NetAcceptAction dying\n"); + } +}; + + +// +// NetAccept +// Handles accepting connections. +// +struct NetAccept:public Continuation +{ + int port; + int domain; + ink_hrtime period; + Server server; + void *alloc_cache; + AcceptFunctionPtr accept_fn; + int ifd; + int ifd_seq_num; + bool callback_on_open; + Ptr action_; + int recv_bufsize; + int send_bufsize; + uint32_t sockopt_flags; + EventType etype; + UnixNetVConnection *epoll_vc; // only storage for epoll events + EventIO ep; + + // Functions all THREAD_FREE and THREAD_ALLOC to be performed + // for both SSL and regular NetVConnection transparent to + // accept functions. + virtual UnixNetVConnection *allocateThread(EThread *t); + virtual void freeThread(UnixNetVConnection *vc, EThread *t); + virtual UnixNetVConnection *allocateGlobal(); + virtual EventType getEtype(); + + void init_accept_loop(); + virtual void init_accept(EThread * t = NULL); + virtual void init_accept_per_thread(); + // 0 == success + int do_listen(bool non_blocking); + + int do_blocking_accept(NetAccept * master_na, EThread * t); + virtual int acceptEvent(int event, void *e); + virtual int acceptFastEvent(int event, void *e); + int acceptLoopEvent(int event, Event * e); + void cancel(); + + NetAccept(); + virtual ~ NetAccept() + { + action_ = NULL; + }; +}; + + +#endif diff --git a/iocore/net/P_NetVCTest.h b/iocore/net/P_NetVCTest.h new file mode 100644 index 00000000..a950f2d2 --- /dev/null +++ b/iocore/net/P_NetVCTest.h @@ -0,0 +1,152 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_NetVCTest.h + + Description: + Unit test for infastructure for VConnections implementing the + NetVConnection interface + + + + + ****************************************************************************/ + +#ifndef _P_NET_VC_TEST_H_ +#define _P_NET_VC_TEST_H_ + +#include "libts.h" + +class VIO; +class MIOBuffer; +class IOBufferReader; + + + +enum NetVcTestType_t +{ + NET_VC_TEST_ACTIVE, + NET_VC_TEST_PASSIVE +}; + +struct NVC_test_def +{ + const char *test_name; + + int bytes_to_send; + int nbytes_write; + + int bytes_to_read; + int nbytes_read; + + int write_bytes_per; + int timeout; + + int expected_read_term; + int expected_write_term; +}; + +extern NVC_test_def netvc_tests_def[]; +extern int num_netvc_tests; + +class NetTestDriver:public Continuation +{ +public: + NetTestDriver(); + ~NetTestDriver(); + + int errors; +protected: + + RegressionTest * r; + int *pstatus; +}; + + +class NetVCTest:public Continuation +{ +public: + NetVCTest(); + ~NetVCTest(); + NetVcTestType_t test_cont_type; + + int main_handler(int event, void *data); + void read_handler(int event); + void write_handler(int event); + void cleanup(); + + void init_test(NetVcTestType_t n_type, NetTestDriver * driver, + NetVConnection * nvc, RegressionTest * robj, + NVC_test_def * my_def, const char *module_name_arg, const char *debug_tag_arg); + void start_test(); + int fill_buffer(MIOBuffer * buf, uint8_t * seed, int bytes); + int consume_and_check_bytes(IOBufferReader * r, uint8_t * seed); + + void write_finished(); + void read_finished(); + void finished(); + void record_error(const char *msg); + + NetVConnection *test_vc; + RegressionTest *regress; + NetTestDriver *driver; + + VIO *read_vio; + VIO *write_vio; + + MIOBuffer *read_buffer; + MIOBuffer *write_buffer; + + IOBufferReader *reader_for_rbuf; + IOBufferReader *reader_for_wbuf; + + int write_bytes_to_add_per; + int timeout; + + int actual_bytes_read; + int actual_bytes_sent; + + bool write_done; + bool read_done; + + uint8_t read_seed; + uint8_t write_seed; + + int bytes_to_send; + int bytes_to_read; + + int nbytes_read; + int nbytes_write; + + int expected_read_term; + int expected_write_term; + + const char *test_name; + const char *module_name; + const char *debug_tag; +}; + + +#endif diff --git a/iocore/net/P_NetVConnection.h b/iocore/net/P_NetVConnection.h new file mode 100644 index 00000000..9ce69c8f --- /dev/null +++ b/iocore/net/P_NetVConnection.h @@ -0,0 +1,103 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_NetVConnection.h" + +TS_INLINE sockaddr_storage const* +NetVConnection::get_remote_addr() +{ + if (!got_remote_addr) { + set_remote_addr(); + got_remote_addr = 1; + } + return &remote_addr; +} + +TS_INLINE unsigned int +NetVConnection::get_remote_ip() +{ + switch (get_remote_addr()->ss_family) { + case AF_INET: + return (unsigned int)((struct sockaddr_in *)(get_remote_addr()))->sin_addr.s_addr; + default: + return 0; + } +} + + +TS_INLINE int +NetVConnection::get_remote_port() +{ + switch (get_remote_addr()->ss_family) { + case AF_INET: + return ntohs(((struct sockaddr_in *)(get_remote_addr()))->sin_port); + case AF_INET6: + return ntohs(((struct sockaddr_in6 *)(get_remote_addr()))->sin6_port); + default: + return 0; + } +} + +TS_INLINE sockaddr_storage const* +NetVConnection::get_local_addr() +{ + if (!got_local_addr) { + set_local_addr(); + switch (local_addr.ss_family) { + case AF_INET: + if (((struct sockaddr_in *)(&local_addr))->sin_addr.s_addr || ((struct sockaddr_in *)&(local_addr))->sin_port) { + got_local_addr = 1; + } + break; + case AF_INET6: + if (((struct sockaddr_in6 *)(&local_addr))->sin6_addr.s6_addr || ((struct sockaddr_in6 *)(&local_addr))->sin6_port) { + got_local_addr = 1; + } + } + } + return &local_addr; +} + +TS_INLINE unsigned int +NetVConnection::get_local_ip() +{ + switch (get_local_addr()->ss_family) { + case AF_INET: + return (unsigned int)((struct sockaddr_in *)(get_local_addr()))->sin_addr.s_addr; + default: + return 0; + } +} + +TS_INLINE int +NetVConnection::get_local_port() +{ + switch (get_local_addr()->ss_family) { + case AF_INET: + return ntohs(((struct sockaddr_in *)(get_local_addr()))->sin_port); + case AF_INET6: + return ntohs(((struct sockaddr_in6 *)(get_local_addr()))->sin6_port); + default: + return 0; + } +} diff --git a/iocore/net/P_SSLCertLookup.h b/iocore/net/P_SSLCertLookup.h new file mode 100644 index 00000000..5de14614 --- /dev/null +++ b/iocore/net/P_SSLCertLookup.h @@ -0,0 +1,51 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ssl_Cert_Lookup_h_ +#define _ssl_Cert_Lookup_h_ +#include "libts.h" +#include "P_SSLNetProcessor.h" + +#define PATH_NAME_MAX 511 + +class SSLCertLookup +{ + bool buildTable(); + const char *extractIPAndCert(matcher_line * line_info, char **addr, char **cert, char **ca, char **priKey); + int addInfoToHash(char *strAddr, char *cert, char *ca, char *serverPrivateKey); + + InkHashTable *SSLCertLookupHashTable; + char config_file_path[PATH_NAME_MAX]; + SslConfigParams *param; + +public: + bool multipleCerts; + void init(SslConfigParams * param); + SSL_CTX *findInfoInHash(char *strAddr); + SSLCertLookup(); + ~SSLCertLookup(); +}; + +extern SSLCertLookup sslCertLookup; + +#endif diff --git a/iocore/net/P_SSLConfig.h b/iocore/net/P_SSLConfig.h new file mode 100644 index 00000000..c18c1644 --- /dev/null +++ b/iocore/net/P_SSLConfig.h @@ -0,0 +1,198 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************** -*- Mod: C++ -*- ****************************** + P_SSLConfig.h + Created On : 07/20/2000 + + Description: + SSL Configurations + ****************************************************************************/ +#ifndef __P_SSLCONFIG_H__ +#define __P_SSLCONFIG_H__ + +#include "libts.h" + +#define SSL_NO_ACCEL 0 +#define SSL_NCIPHER_ACCEL 1 +#define SSL_CSWIFT_ACCEL 2 +#define SSL_ATALLA_ACCEL 3 +#define SSL_BROADCOM_ACCEL 4 + + + +// +// Dynamic updates of SSL settings are not implemented yet. +// +///////////////////////////////////////////////////////////// +// +// struct SslConfigParams +// +// configuration parameters as they apear in the global +// configuration file. +///////////////////////////////////////////////////////////// + + +struct SslConfigParams +#ifdef USE_CONFIG_PROCESSOR +: public ConfigInfo +#endif +{ +public: + enum SSL_TERMINATION_MODE + { + SSL_TERM_MODE_NONE = 0, + SSL_TERM_MODE_CLIENT = 1, + SSL_TERM_MODE_SERVER = 2, + SSL_TERM_MODE_BOTH = SSL_TERM_MODE_CLIENT | SSL_TERM_MODE_SERVER + }; + + enum SSL_ACCELERATOR_REQ + { + SSL_ACCELERATOR_REQ_NO = 0, + SSL_ACCELERATOR_REQ_YES = 1, + SSL_ACCELERATOR_REQ_MEAN = 2, + SSL_ACCELERATOR_REQ_BOTH = 3 + }; + + enum SSL_SESSION_CACHE_MODE + { + SSL_SESSION_CACHE_MODE_OFF = 0, + SSL_SESSION_CACHE_MODE_SERVER = 1 + }; + + SSL_TERMINATION_MODE getTerminationMode(void) const { return termMode; } + int getAcceptPort(void) const { return ssl_accept_port_number; } + char *getConfigFilePath(void) const { return configFilePath; } + char *getServerCertPathOnly(void) const { return serverCertPathOnly; } + char *getServerCACertPathOnly(void) const { return CACertPath; } + char *getServerKeyPathOnly(void) const { return serverKeyPathOnly; } + + SslConfigParams(); + virtual ~SslConfigParams(); + +private: + void initialize(); + void cleanup(); + + char *serverCertPath; + char *serverCertPathOnly; + char *serverCertChainPath; + char *serverKeyPath; + char *serverKeyPathOnly; + char *CACertFilename; + char *CACertPath; + char *configFilePath; + char *ncipherAccelLibPath; + char *cswiftAccelLibPath; + char *atallaAccelLibPath; + char *broadcomAccelLibPath; + char *cipherSuite; + int clientCertLevel; + int verify_depth; + int ssl_accept_port_number; + int sslAccelerator; + int ssl_session_cache; + int ssl_session_cache_size; + + char *clientCertPath; + char *clientKeyPath; + char *clientCACertFilename; + char *clientCACertPath; + int clientVerify; + int client_verify_depth; + + SSL_TERMINATION_MODE termMode; + int ssl_accelerator_required; + + long ssl_ctx_options; + + friend struct SSLNetProcessor; + friend class SslConfig; +}; + +///////////////////////////////////////////////////////////// +// +// class SslConfig +// +///////////////////////////////////////////////////////////// +class SslConfig +{ +public: + static void startup(); + static void reconfigure(); + static SslConfigParams *acquire(); + static void release(SslConfigParams * params); + + static bool serverTerminationEnabled(void) { return serverSSLTermination; } + +private: + static void clearTermEnabled() + { + serverSSLTermination = 0; + } + + static int id; + static bool serverSSLTermination; +#ifndef USE_CONFIG_PROCESSOR + static SslConfigParams *ssl_config_params; +#endif + friend struct SSLNetProcessor; +}; + +extern SslConfig sslTerminationConfig; + +#include "Diags.h" + +TS_INLINE void +DebugBufferPrint(const char *tag, char *buff, int blen, const char *message = NULL) +{ + (void) tag; + (void) buff; + (void) blen; + (void) message; +#if defined (_DEBUG) + if (is_debug_tag_set(tag)) { + if (message != NULL) +#if defined (_IOCORE_WIN32) + _RPT1(_CRT_WARN, "%s\n", message); +#else + fprintf(stdout, "%s\n", message); +#endif + for (int ii = 0; ii < blen; ii++) { +#if defined (_IOCORE_WIN32) + _RPT1(_CRT_WARN, "%c", buff[ii]); +#else + putc(buff[ii], stdout); +#endif + } +#if defined (_IOCORE_WIN32) + _RPT1(_CRT_WARN, "%c", '\n'); +#else + putc('\n', stdout); +#endif + } +#endif +} + +#endif diff --git a/iocore/net/P_SSLNetAccept.h b/iocore/net/P_SSLNetAccept.h new file mode 100644 index 00000000..86f7c835 --- /dev/null +++ b/iocore/net/P_SSLNetAccept.h @@ -0,0 +1,71 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_SSLNetAccept.h + + + NetAccept is a generalized facility which allows + Connections of different classes to be accepted either + from a blockable thread or by adaptive polling. + + It is used by the NetProcessor and the ClusterProcessor + and should be considered PRIVATE to processor implementations. + + + + ****************************************************************************/ +#if !defined (_SSLNetAccept_h_) +#define _SSLNetAccept_h_ + +#include "libts.h" +#include "P_Connection.h" +#include "P_NetAccept.h" + +class Event; +class UnixNetVConnection; + +// +// NetAccept +// Handles accepting connections. +// +struct SSLNetAccept: public NetAccept +{ + +#ifndef _IOCORE_WIN32_WINNT + virtual UnixNetVConnection *allocateThread(EThread * t); + virtual void freeThread(UnixNetVConnection * vc, EThread * t); + virtual UnixNetVConnection *allocateGlobal(); + virtual EventType getEtype(); +#endif + virtual void init_accept_per_thread(); + + SSLNetAccept() + { }; + + virtual ~SSLNetAccept() + { }; + +}; +#endif diff --git a/iocore/net/P_SSLNetProcessor.h b/iocore/net/P_SSLNetProcessor.h new file mode 100644 index 00000000..0817b5ac --- /dev/null +++ b/iocore/net/P_SSLNetProcessor.h @@ -0,0 +1,121 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Net.h + + This file implements an I/O Processor for network I/O. + + + ****************************************************************************/ +#ifndef __P_SSLNETPROCESSOR_H +#define __P_SSLNETPROCESSOR_H + +#include "libts.h" +#include "P_Net.h" +#include +#include +#include + + +#include "P_SSLConfig.h" + +class UnixNetVConnection; +struct NetAccept; + +////////////////////////////////////////////////////////////////// +// +// class SSLNetProcessor +// +////////////////////////////////////////////////////////////////// +struct SSLNetProcessor:public +#ifndef _IOCORE_WIN32_WINNT + UnixNetProcessor +#else + NTNetProcessor +#endif +{ +public: + + virtual int start(int no_of_ssl_threads); + + void cleanup(void); + int reconfigure(); + int initSSL(SslConfigParams * param); + int initSSLClient(SslConfigParams * param); + int initSSLServerCTX(SslConfigParams * param, + SSL_CTX * ctx, char *serverCertPtr, char *serverCaPtr, char *serverKeyPtr, bool defaultEnabled); + + SSL_CTX *getSSL_CTX(void) const {return ctx; } + SSL_CTX *getClientSSL_CTX(void) const { return client_ctx; } + int getAcceptPort() { return accept_port_number; } + + static void logSSLError(const char *errStr = "", int critical = 1); + + SSLNetProcessor() + : verify_depth(0), ctx(NULL), client_ctx(NULL), sslMutexArray(NULL), accept_port_number(-1) + { }; + virtual ~SSLNetProcessor(); + + int verify_depth; + SSL_CTX *ctx; + SSL_CTX *client_ctx; + ProxyMutex **sslMutexArray; + + // + // Private + // +#if !defined (_IOCORE_WIN32_WINNT) + + // Virtual function allows etype + // to be upgraded to ET_SSL for SSLNetProcessor. + virtual void upgradeEtype(EventType &etype); + + // Functions all THREAD_FREE and THREAD_ALLOC to be performed + // for both SSL and regular NetVConnection transparent to + // netProcessor connect functions. + virtual UnixNetVConnection *allocateThread(EThread * t); + virtual void freeThread(UnixNetVConnection * vc, EThread * t); +virtual NetAccept *createNetAccept(); +#else // #if defined (_IOCORE_WIN32) + +public: + virtual NTNetVConnection * newNetVConnection(void); + virtual NTNetVConnection *newClientNetVConnection(void); +#endif // #if defined (_IOCORE_WIN32) + +private: + void initSSLLocks(void); + SSLNetProcessor(const SSLNetProcessor &); + SSLNetProcessor & operator =(const SSLNetProcessor &); + + int accept_port_number; + static bool open_ssl_initialized; +}; + + +extern inkcoreapi SSLNetProcessor ssl_NetProcessor; + + +#endif diff --git a/iocore/net/P_SSLNetVConnection.h b/iocore/net/P_SSLNetVConnection.h new file mode 100644 index 00000000..dbf93724 --- /dev/null +++ b/iocore/net/P_SSLNetVConnection.h @@ -0,0 +1,175 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + SSLNetVConnection.h + + This file implements an I/O Processor for network I/O. + + + ****************************************************************************/ +#if !defined (_SSLNetVConnection_h_) +#define _SSLNetVConnection_h_ + +#include "libts.h" +#include "P_EventSystem.h" +#include "P_UnixNetVConnection.h" +#include "P_UnixNet.h" + +#include +#include + + +////////////////////////////////////////////////////////////////// +// +// class NetVConnection +// +// A VConnection for a network socket. +// +////////////////////////////////////////////////////////////////// +#ifdef _IOCORE_WIN32_WINNT +class SSLNetVConnection:public NTNetVConnection +#else +class SSLNetVConnection:public UnixNetVConnection +#endif +{ +public: + int connect_calls; + int connect_want_write; + int connect_want_read; + int connect_want_connect; + int connect_want_ssl; + int connect_want_syscal; + int connect_want_accept; + int connect_want_x509; + int connect_error_zero; + int accept_calls; + int read_calls; + int read_want_write; + int read_want_read; + int read_want_ssl; + int read_want_syscal; + int read_want_x509; + int read_error_zero; + int write_calls; + int write_want_write; + int write_want_read; + int write_want_ssl; + int write_want_syscal; + int write_want_x509; + int write_error_zero; + + virtual int sslStartHandShake(int event, int &err); + virtual void free(EThread * t); + virtual void enableRead() + { + read.enabled = 1; + write.enabled = 1; + }; + virtual bool getSSLHandShakeComplete() + { + return sslHandShakeComplete; + }; + void setSSLHandShakeComplete(bool state) + { + sslHandShakeComplete = state; + }; + virtual bool getSSLClientConnection() + { + return sslClientConnection; + }; + virtual void setSSLClientConnection(bool state) + { + sslClientConnection = state; + }; + int sslServerHandShakeEvent(int &err); + int sslClientHandShakeEvent(int &err); + virtual void net_read_io(NetHandler * nh, EThread * lthread); + virtual int64_t load_buffer_and_write(int64_t towrite, int64_t &wattempted, int64_t &total_wrote, MIOBufferAccessor & buf); + virtual ~ SSLNetVConnection() { } + //////////////////////////////////////////////////////////// + // instances of NetVConnection should be allocated // + // only from the free list using NetVConnection::alloc(). // + // The constructo is public just to avoid compile errors. // + //////////////////////////////////////////////////////////// + SSLNetVConnection(); + SSL *ssl; + X509 *client_cert; + X509 *server_cert; + +private: + bool sslHandShakeComplete; + bool sslClientConnection; + SSLNetVConnection(const SSLNetVConnection &); + SSLNetVConnection & operator =(const SSLNetVConnection &); +}; + +typedef int (SSLNetVConnection::*SSLNetVConnHandler) (int, void *); + +extern ClassAllocator sslNetVCAllocator; + +// +// Local functions +// + + +static inline SSLNetVConnection * +new_SSLNetVConnection(EThread * thread) +{ + NOWARN_UNUSED(thread); + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, 1); + SSLNetVConnection *vc = sslNetVCAllocator.alloc(); + vc->connect_calls = 0; + vc->write_calls = 0; + vc->read_calls = 0; + vc->accept_calls = 0; + vc->connect_want_write = 0; + vc->connect_want_read = 0; + vc->connect_want_connect = 0; + vc->connect_want_ssl = 0; + vc->connect_want_syscal = 0; + vc->connect_want_accept = 0; + vc->connect_want_x509 = 0; + vc->connect_error_zero = 0; + vc->read_want_write = 0; + vc->read_want_read = 0; + vc->read_want_ssl = 0; + vc->read_want_syscal = 0; + vc->read_want_x509 = 0; + vc->read_error_zero = 0; + vc->write_want_write = 0; + vc->write_want_read = 0; + vc->write_want_ssl = 0; + vc->write_want_syscal = 0; + vc->write_want_x509 = 0; + vc->write_error_zero = 0; + + vc->ssl = NULL; + vc->setSSLHandShakeComplete(0); + vc->id = net_next_connection_number(); + return vc; +} + + +#endif /* _SSLNetVConnection_h_ */ diff --git a/iocore/net/P_Socks.h b/iocore/net/P_Socks.h new file mode 100644 index 00000000..c9444b2c --- /dev/null +++ b/iocore/net/P_Socks.h @@ -0,0 +1,168 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __P_SOCKS_H__ +#define __P_SOCKS_H__ +#include "P_EventSystem.h" +#include "I_Socks.h" + +#ifdef SOCKS_WITH_TS +#include "ParentSelection.h" +#include "IPRange.h" +#endif + +enum +{ + + //types of events for Socks auth handlers + SOCKS_AUTH_OPEN, + SOCKS_AUTH_WRITE_COMPLETE, + SOCKS_AUTH_READ_COMPLETE, + SOCKS_AUTH_FILL_WRITE_BUF +}; + +struct socks_conf_struct +{ + int socks_needed; + int server_connect_timeout; + int socks_timeout; + unsigned char default_version; + char *user_name_n_passwd; + int user_name_n_passwd_len; + + int per_server_connection_attempts; + int connection_attempts; + + //the following ports are used by SocksProxy + int accept_enabled; + int accept_port; + unsigned short http_port; + +#ifdef SOCKS_WITH_TS + IPRange ip_range; +#endif + +#ifndef SOCKS_WITH_TS + unsigned int socks_server; + int socks_server_port; +#endif + + socks_conf_struct():socks_needed(0), server_connect_timeout(0), socks_timeout(100), default_version(5), + user_name_n_passwd(NULL), user_name_n_passwd_len(0), + per_server_connection_attempts(1), connection_attempts(0), accept_enabled(0), accept_port(0), http_port(1080) + { + } +}; + +extern struct socks_conf_struct *g_socks_conf_stuff; + +void start_SocksProxy(int port); + +int loadSocksAuthInfo(int fd, socks_conf_struct * socks_stuff); + +// umm.. the following typedef should take _its own_ type as one of the args +// not possible with C +// Right now just use a generic fn ptr and hide casting in an inline fn. +typedef int (*SocksAuthHandler) (int event, unsigned char *buf, void (**h_ptr) (void)); + +TS_INLINE int +invokeSocksAuthHandler(SocksAuthHandler & h, int arg1, unsigned char *arg2) +{ + return (h) (arg1, arg2, (void (**)(void)) (&h)); +} + +void loadSocksConfiguration(socks_conf_struct * socks_conf_stuff); +int socks5BasicAuthHandler(int event, unsigned char *p, void (**)(void)); +int socks5PasswdAuthHandler(int event, unsigned char *p, void (**)(void)); +int socks5ServerAuthHandler(int event, unsigned char *p, void (**)(void)); + +#if defined(_IOCORE_WIN32) +class NTNetVConnection; +typedef NTNetVConnection SocksNetVC; +#else +class UnixNetVConnection; +typedef UnixNetVConnection SocksNetVC; +#endif + +struct SocksEntry:public Continuation +{ + + + MIOBuffer *buf; + IOBufferReader *reader; + + SocksNetVC *netVConnection; + + unsigned int ip; // ip address in the original request + int port; // port number in the original request + + unsigned int server_ip; + int server_port; + int nattempts; + + Action action_; + int lerrno; + Event *timeout; + unsigned char version; + + bool write_done; + + SocksAuthHandler auth_handler; + unsigned char socks_cmd; + +#ifdef SOCKS_WITH_TS + //socks server selection: + ParentConfigParams *server_params; + HttpRequestData req_data; //We dont use any http specific fields. + ParentResult server_result; +#endif + + int startEvent(int event, void *data); + int mainEvent(int event, void *data); + void findServer(); + void init(ProxyMutex * m, SocksNetVC * netvc, unsigned char socks_support, unsigned char ver); + void free(); + + SocksEntry():Continuation(NULL), netVConnection(0), + ip(0), port(0), server_ip(0), server_port(0), nattempts(0), + lerrno(0), timeout(0), version(5), write_done(false), auth_handler(NULL), socks_cmd(NORMAL_SOCKS) + { + } +}; + +typedef int (SocksEntry::*SocksEntryHandler) (int, void *); + +extern ClassAllocator socksAllocator; + +TS_INLINE void +SocksAddrType::reset() +{ + if (type != SOCKS_ATYPE_IPV4 && addr.buf) { + xfree(addr.buf); + } + + addr.buf = 0; + type = SOCKS_ATYPE_NONE; +} + +#endif diff --git a/iocore/net/P_UDPConnection.h b/iocore/net/P_UDPConnection.h new file mode 100644 index 00000000..a34c5b03 --- /dev/null +++ b/iocore/net/P_UDPConnection.h @@ -0,0 +1,196 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_UDPConnection.h + Internal UDPConnection holds data members and defines member functions + + + ****************************************************************************/ +#ifndef __P_UDPCONNECTION_H_ +#define __P_UDPCONNECTION_H_ + +#include "I_UDPNet.h" + + +class UDPConnectionInternal:public UDPConnection +{ + +public: + UDPConnectionInternal(); + virtual ~ UDPConnectionInternal(); + + Continuation *continuation; + int recvActive; // interested in receiving + int refcount; // public for assertion + + SOCKET fd; + struct sockaddr_in binding; + int binding_valid; + int tobedestroyed; + int sendGenerationNum; + int64_t lastSentPktTSSeqNum; + + // this is for doing packet scheduling: we keep two values so that we can + // implement cancel. The first value tracks the startTime of the last + // packet that was sent on this connection; the second value tracks the + // startTime of the last packet when we are doing scheduling; whenever the + // associated continuation cancels a packet, we rest lastPktStartTime to be + // the same as the lastSentPktStartTime. + uint64_t lastSentPktStartTime; + uint64_t lastPktStartTime; + int32_t pipe_class; + uint32_t nBytesDone; + uint32_t nBytesTodo; + // flow rate in Bytes per sec. + double flowRateBps; + double avgPktSize; + int64_t allocedbps; + + //this class is abstract +}; + +TS_INLINE +UDPConnectionInternal::UDPConnectionInternal() + : continuation(NULL) + , recvActive(0) + , refcount(0) + , fd(-1) + , binding_valid(0) + , tobedestroyed(0) + , nBytesDone(0) + , nBytesTodo(0) +{ + sendGenerationNum = 0; + lastSentPktTSSeqNum = -1; + lastSentPktStartTime = 0; + lastPktStartTime = 0; + pipe_class = 0; + flowRateBps = 0.0; + avgPktSize = 0.0; + allocedbps = 0; + memset(&binding, 0, sizeof binding); + //SET_HANDLER(&BaseUDPConnection::callbackHandler); +} + +TS_INLINE +UDPConnectionInternal::~UDPConnectionInternal() +{ + udpNet.FreeBandwidth(this); + continuation = NULL; + mutex = NULL; +} + + +TS_INLINE SOCKET +UDPConnection::getFd() +{ + return ((UDPConnectionInternal *) this)->fd; +} + +TS_INLINE void +UDPConnection::setBinding(struct sockaddr_in *s) +{ + UDPConnectionInternal *p = (UDPConnectionInternal *) this; + memcpy(&p->binding, s, sizeof(p->binding)); + p->binding_valid = 1; +} + +TS_INLINE int +UDPConnection::getBinding(struct sockaddr_in *s) +{ + UDPConnectionInternal *p = (UDPConnectionInternal *) this; + memcpy(s, &p->binding, sizeof(*s)); + return p->binding_valid; +} + +// return the b/w allocated to this UDPConnection in Mbps +TS_INLINE double +UDPConnection::get_allocatedBandwidth() +{ + return (((UDPConnectionInternal *) this)->flowRateBps * 8.0) / (1024.0 * 1024.0); +} + +TS_INLINE void +UDPConnection::destroy() +{ + ((UDPConnectionInternal *) this)->tobedestroyed = 1; +} + +TS_INLINE int +UDPConnection::shouldDestroy() +{ + return ((UDPConnectionInternal *) this)->tobedestroyed; +} + +TS_INLINE void +UDPConnection::AddRef() +{ + ink_atomic_increment(&((UDPConnectionInternal *) this)->refcount, 1); +} + +TS_INLINE int +UDPConnection::GetRefCount() +{ + return ((UDPConnectionInternal *) this)->refcount; +} + +TS_INLINE int +UDPConnection::GetSendGenerationNumber() +{ + return ((UDPConnectionInternal *) this)->sendGenerationNum; +} + +TS_INLINE int +UDPConnection::getPortNum(void) +{ + return ((UDPConnectionInternal *) this)->binding.sin_port; +} + +TS_INLINE int64_t +UDPConnection::cancel(void) +{ + UDPConnectionInternal *p = (UDPConnectionInternal *) this; + + p->sendGenerationNum++; + p->lastPktStartTime = p->lastSentPktStartTime; + return p->lastSentPktTSSeqNum; +} + +TS_INLINE void +UDPConnection::SetLastSentPktTSSeqNum(int64_t sentSeqNum) +{ + ((UDPConnectionInternal *) this)->lastSentPktTSSeqNum = sentSeqNum; +} + +TS_INLINE void +UDPConnection::setContinuation(Continuation * c) +{ + // it is not safe to switch among continuations that don't share locks + ink_assert(mutex == NULL || c->mutex == mutex); + mutex = c->mutex; + ((UDPConnectionInternal *) this)->continuation = c; +} + +#endif //__P_UDPCONNECTION_H_ diff --git a/iocore/net/P_UDPIOEvent.h b/iocore/net/P_UDPIOEvent.h new file mode 100644 index 00000000..bc5511d3 --- /dev/null +++ b/iocore/net/P_UDPIOEvent.h @@ -0,0 +1,95 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _UDP_IO_EVENT_H_ +#define _UDP_IO_EVENT_H_ +// ugly -- just encapsulate the I/O result so that it can be passed +// back to the caller via continuation handler. + +class UDPIOEvent:public Event +{ +public: + UDPIOEvent():fd(-1), err(0), m(0), handle(0), b(0), bytesTransferred(0) + { + }; + ~UDPIOEvent() { + }; + void setInfo(int fd_, IOBufferBlock * b_, int bytesTransferred_, int errno_) + { + fd = fd_; + b = b_; + bytesTransferred = bytesTransferred_; + err = errno_; + }; + void setInfo(int fd_, struct msghdr *m_, int bytesTransferred_, int errno_) + { + fd = fd_; + m = m_; + bytesTransferred = bytesTransferred_; + err = errno_; + }; + void setHandle(void *v) + { + handle = v; + } + void *getHandle() + { + return handle; + } + void free(); + int getBytesTransferred() + { + return bytesTransferred; + } + IOBufferBlock *getIOBufferBlock() + { + return b; + } + int getError() + { + return err; + } + Continuation *getContinuation() + { + return continuation; + } + static void free(UDPIOEvent * e); +private: + void *operator new(size_t size); // undefined + int fd; + int err; // error code + struct msghdr *m; + void *handle; // some extra data for the client handler + Ptr b; // holds buffer that I/O will go to + int bytesTransferred; // actual bytes transferred +}; + +extern ClassAllocator UDPIOEventAllocator; +TS_INLINE void +UDPIOEvent::free(UDPIOEvent * e) +{ + e->b = NULL; + e->mutex = NULL; + UDPIOEventAllocator.free(e); +} +#endif diff --git a/iocore/net/P_UDPNet.h b/iocore/net/P_UDPNet.h new file mode 100644 index 00000000..7ad87821 --- /dev/null +++ b/iocore/net/P_UDPNet.h @@ -0,0 +1,465 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + P_UDPNet.h + Private header for UDPNetProcessor + + + ****************************************************************************/ + +#ifndef __P_UDPNET_H_ +#define __P_UDPNET_H_ + +extern EventType ET_UDP; + +#include "I_UDPNet.h" +#include "P_UDPPacket.h" + +//added by YTS Team, yamsat +static inline PollCont *get_UDPPollCont(EThread *); + +#include "P_UnixUDPConnection.h" +#include "P_UDPIOEvent.h" + +struct UDPNetHandler; + +struct UDPNetProcessorInternal : public UDPNetProcessor +{ + virtual int start(int n_udp_threads); +#if defined (_IOCORE_WIN32) + SOCKET create_dgram_socket_internal(); +#else + void udp_read_from_net(UDPNetHandler * nh, UDPConnection * uc, PollDescriptor * pd, EThread * thread); + int udp_callback(UDPNetHandler * nh, UDPConnection * uc, EThread * thread); +#endif + +#if defined (_IOCORE_WIN32) + EThread *ethread; + UDPNetHandler *udpNetHandler; +#else + off_t pollCont_offset; + off_t udpNetHandler_offset; +#endif + +public: + virtual void UDPNetProcessor_is_abstract() { } +}; + +extern UDPNetProcessorInternal udpNetInternal; + +class PacketQueue; + +class UDPQueue +{ +public: + + void service(UDPNetHandler *); + // these are internal APIs + // BulkIOSend uses the BulkIO kernel module for bulk data transfer + void BulkIOSend(); + // In the absence of bulk-io, we are down sending packet after packet + void SendPackets(); + void SendUDPPacket(UDPPacketInternal * p, int32_t pktLen); + + // Interface exported to the outside world + void send(UDPPacket * p); + + Queue reliabilityPktQueue; + InkAtomicList atomicQueue; + ink_hrtime last_report; + ink_hrtime last_service; + ink_hrtime last_byteperiod; + int bytesSent; + int packets; + int added; + + UDPQueue(); + ~UDPQueue(); +}; + +#ifdef PACKETQUEUE_IMPL_AS_RING + +// 20 ms slots; 2048 slots => 40 sec. into the future +#define SLOT_TIME_MSEC 20 +#define SLOT_TIME HRTIME_MSECONDS(SLOT_TIME_MSEC) +#define N_SLOTS 2048 + +extern uint64_t g_udp_bytesPending; + +class PacketQueue +{ +public: + PacketQueue() + :nPackets(0) + , now_slot(0) + { + lastPullLongTermQ = 0; + init(); + } + + virtual ~ PacketQueue() + { + } + int nPackets; + + ink_hrtime lastPullLongTermQ; + Queue longTermQ; + Queue bucket[N_SLOTS]; + ink_hrtime delivery_time[N_SLOTS]; + int now_slot; + + void init(void) + { + now_slot = 0; + ink_hrtime now = ink_get_hrtime_internal(); + int i = now_slot; + int j = 0; + while (j < N_SLOTS) { + delivery_time[i] = now + j * SLOT_TIME; + i = (i + 1) % N_SLOTS; + j++; + } + } + + void addPacket(UDPPacketInternal * e, ink_hrtime now = 0) { + int before = 0; + int slot; + + if (IsCancelledPacket(e)) { + g_udp_bytesPending -= e->getPktLength(); + e->free(); + return; + } + + nPackets++; + + ink_assert(delivery_time[now_slot]); + + if (e->delivery_time < now) + e->delivery_time = now; + + ink_hrtime s = e->delivery_time - delivery_time[now_slot]; + + if (s < 0) { + before = 1; + s = 0; + } + s = s / SLOT_TIME; + // if s >= N_SLOTS, either we are *REALLY* behind or someone is trying + // queue packets *WAY* too far into the future. + // need a thingy to hold packets in a "long-term" slot; then, pull packets + // from long-term slot whenever you advance. + if (s >= N_SLOTS - 1) { + longTermQ.enqueue(e); + e->in_heap = 0; + e->in_the_priority_queue = 1; + return; + } + slot = (s + now_slot) % N_SLOTS; + + // so that slot+1 is still "in future". + ink_assert((before || delivery_time[slot] <= e->delivery_time) && + (delivery_time[(slot + 1) % N_SLOTS] >= e->delivery_time)); + e->in_the_priority_queue = 1; + e->in_heap = slot; + bucket[slot].enqueue(e); + }; + UDPPacketInternal *firstPacket(ink_hrtime t) + { + if (t > delivery_time[now_slot]) { + return bucket[now_slot].head; + } else { + return NULL; + } + }; + UDPPacketInternal *getFirstPacket() + { + nPackets--; + return dequeue_ready(0); + }; + int size() + { + ink_assert(nPackets >= 0); + return nPackets; + }; + void invariant(); + bool IsCancelledPacket(UDPPacketInternal * p) + { + // discard packets that'll never get sent... + return ((p->conn->shouldDestroy()) || (p->conn->GetSendGenerationNumber() != p->reqGenerationNum)); + }; + + void FreeCancelledPackets(int numSlots) + { + UDPPacketInternal *p; + Queue tempQ; + int i, s; + + for (i = 0; i < numSlots; i++) { + s = (now_slot + i) % N_SLOTS; + while (NULL != (p = bucket[s].dequeue())) { + if (IsCancelledPacket(p)) { + g_udp_bytesPending -= p->getPktLength(); + p->free(); + continue; + } + tempQ.enqueue(p); + } + // remove and flip it over + while (NULL != (p = tempQ.dequeue())) { + bucket[s].enqueue(p); + } + } + }; + + void advanceNow(ink_hrtime t) + { + int s = now_slot; + int prev; + + if (ink_hrtime_to_msec(t - lastPullLongTermQ) >= SLOT_TIME_MSEC * ((N_SLOTS - 1) / 2)) { + Queue tempQ; + UDPPacketInternal *p; + // pull in all the stuff from long-term slot + lastPullLongTermQ = t; + // this is to handle wierdoness where someone is trying to queue a + // packet to be sent in SLOT_TIME_MSEC * N_SLOTS * (2+)---the packet + // will get back to longTermQ and we'll have an infinite loop. + while ((p = longTermQ.dequeue()) != NULL) + tempQ.enqueue(p); + while ((p = tempQ.dequeue()) != NULL) + addPacket(p); + } + + while (!bucket[s].head && (t > delivery_time[s] + SLOT_TIME)) { + prev = (s + N_SLOTS - 1) % N_SLOTS; + delivery_time[s] = delivery_time[prev] + SLOT_TIME; + s = (s + 1) % N_SLOTS; + prev = (s + N_SLOTS - 1) % N_SLOTS; + ink_assert(delivery_time[prev] > delivery_time[s]); + + if (s == now_slot) { + init(); + s = 0; + break; + } + } + + if (s != now_slot) + Debug("udpnet-service", "Advancing by (%d slots): behind by %" PRId64 " ms", + s - now_slot, ink_hrtime_to_msec(t - delivery_time[now_slot])); + now_slot = s; + }; +private: + void remove(UDPPacketInternal * e) + { + nPackets--; + ink_assert(e->in_the_priority_queue); + e->in_the_priority_queue = 0; + bucket[e->in_heap].remove(e); + } + +public: + UDPPacketInternal * dequeue_ready(ink_hrtime t) { + (void) t; + UDPPacketInternal *e = bucket[now_slot].dequeue(); + if (e) { + ink_assert(e->in_the_priority_queue); + e->in_the_priority_queue = 0; + } + advanceNow(t); + return e; + } + + void check_ready(ink_hrtime now) + { + (void) now; + } + + ink_hrtime earliest_timeout() + { + int s = now_slot; + for (int i = 0; i < N_SLOTS; i++) { + if (bucket[s].head) { + return delivery_time[s]; + } + s = (s + 1) % N_SLOTS; + } + return HRTIME_FOREVER; + } + +private: + void kill_cancelled_events() + { + } +}; +#endif + +#if !defined (_IOCORE_WIN32) + +void initialize_thread_for_udp_net(EThread * thread); + +struct UDPNetHandler: public Continuation +{ +public: + // to be polled for read + Que(UnixUDPConnection, polling_link) udp_polling; + // to be called back with data + Que(UnixUDPConnection, callback_link) udp_callbacks; + // outgoing packets + InkAtomicList udpAtomicQueue; + UDPQueue udpOutQueue; + // to hold the newly created descriptors before scheduling them on + // the servicing buckets. + // atomically added to by a thread creating a new connection with + // UDPBind + InkAtomicList udpNewConnections; + Event *trigger_event; + ink_hrtime nextCheck; + ink_hrtime lastCheck; + + int startNetEvent(int event, Event * data); + int mainNetEvent(int event, Event * data); + + UDPNetHandler(); +}; +#endif + +#if defined(_IOCORE_WIN32) +void initialize_thread_for_udp_net(EThread * thread); + +class UDPQueue; + +class UDPNetHandler:Continuation +{ +public: + // to be polled for read + Queue(UnixUDPConnection, polling_link) udp_polling; + // to be called back with data + Queue(UnixUDPConnection, callback_link) udp_callbacks; + // outgoing packets + InkAtomicList udpAtomicQueue; + UDPQueue udpOutQueue; + // to hold the newly created descriptors before scheduling them on + // the servicing buckets. + // atomically added to by a thread creating a new connection with + // UDPBind + InkAtomicList udpNewConnections; + Event *trigger_event; + ink_hrtime nextCheck; + ink_hrtime lastCheck; + + int startNetEvent(int event, Event * data); + int mainNetEvent(int event, Event * data); + + UDPNetHandler(); + virtual ~ UDPNetHandler(); +}; +#endif + +struct PollCont; +static inline PollCont * +get_UDPPollCont(EThread * t) +{ + return (PollCont *) ETHREAD_GET_PTR(t, udpNetInternal.pollCont_offset); +} + +static inline UDPNetHandler * +get_UDPNetHandler(EThread * t) +{ + return (UDPNetHandler *) + ETHREAD_GET_PTR(t, udpNetInternal.udpNetHandler_offset); +} + +// All of this stuff is for UDP egress b/w management +struct InkSinglePipeInfo +{ + InkSinglePipeInfo() + { + wt = 0.0; + bwLimit = 0; + destIP = 0; + count = 0; + bytesSent = pktsSent = 0; + bwAlloc = 0; + bwUsed = 0.0; + queue = NEW(new PacketQueue()); + }; + + ~InkSinglePipeInfo() { + delete queue; + } + + double wt; + // all are in bps (bits per sec.) so that we can do ink_atomic_increment + int64_t bwLimit; + int64_t bwAlloc; + // this is in Mbps + double bwUsed; + int32_t destIP; + uint32_t count; + uint64_t bytesSent; + uint64_t pktsSent; + PacketQueue *queue; +}; + +struct InkPipeInfo +{ + int numPipes; + double interfaceMbps; + double reliabilityMbps; + InkSinglePipeInfo *perPipeInfo; +}; + +extern InkPipeInfo G_inkPipeInfo; + +class UDPWorkContinuation:public Continuation +{ +public: + UDPWorkContinuation():cont(NULL), numPairs(0), myIP(0), destIP(0), + sendbufsize(0), recvbufsize(0), udpConns(NULL), resultCode(NET_EVENT_DATAGRAM_OPEN) + { + }; + ~UDPWorkContinuation() { + }; + void init(Continuation * c, int num_pairs, unsigned int my_ip, unsigned int dest_ip, int s_bufsize, int r_bufsize); + int StateCreatePortPairs(int event, void *data); + int StateDoCallback(int event, void *data); + + Action action; + +private: + Continuation * cont; + int numPairs; + unsigned int myIP, destIP; + int sendbufsize, recvbufsize; + UnixUDPConnection **udpConns; + int resultCode; +}; + +typedef int (UDPWorkContinuation::*UDPWorkContinuation_Handler) (int, void *); + +inkcoreapi extern ClassAllocator udpWorkContinuationAllocator; + +#endif //__P_UDPNET_H_ diff --git a/iocore/net/P_UDPPacket.h b/iocore/net/P_UDPPacket.h new file mode 100644 index 00000000..fe250a64 --- /dev/null +++ b/iocore/net/P_UDPPacket.h @@ -0,0 +1,307 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_UDPPacket.h + Implementation of UDPPacket + + + ****************************************************************************/ + + +#ifndef __P_UDPPPACKET_H_ +#define __P_UDPPPACKET_H_ + +#include "I_UDPNet.h" +#include "P_UDPConnection.h" + +//#define PACKETQUEUE_IMPL_AS_PQLIST +#define PACKETQUEUE_IMPL_AS_RING + +class UDPPacketInternal:public UDPPacket +{ + +public: + UDPPacketInternal(); + virtual ~ UDPPacketInternal(); + + void append_bytes(char *buf, int len); + void append_block_internal(IOBufferBlock * block); + + virtual void free(); + + SLINK(UDPPacketInternal, alink); // atomic link + // packet scheduling stuff: keep it a doubly linked list + uint64_t pktSendStartTime; + uint64_t pktSendFinishTime; + uint64_t pktLength; + + bool isReliabilityPkt; + + int reqGenerationNum; + ink_hrtime delivery_time; // when to deliver packet + ink_hrtime arrival_time; // when packet arrived + + Ptr chain; + Continuation *cont; // callback on error + UDPConnectionInternal *conn; // connection where packet should be sent to. + +#if defined(PACKETQUEUE_IMPL_AS_PQLIST) || defined(PACKETQUEUE_IMPL_AS_RING) + int in_the_priority_queue; + int in_heap; +#endif + + virtual void UDPPacket_is_abstract() { } +}; + +inkcoreapi extern ClassAllocator udpPacketAllocator; + +TS_INLINE +UDPPacketInternal::UDPPacketInternal() + : pktSendStartTime(0), pktSendFinishTime(0), pktLength(0), isReliabilityPkt(false), + reqGenerationNum(0), delivery_time(0), arrival_time(0), cont(NULL) , conn(NULL) +#if defined(PACKETQUEUE_IMPL_AS_PQLIST) || defined(PACKETQUEUE_IMPL_AS_RING) + ,in_the_priority_queue(0), in_heap(0) +#endif +{ + memset(&from, '\0', sizeof(from)); + memset(&to, '\0', sizeof(to)); +} + +TS_INLINE +UDPPacketInternal::~ +UDPPacketInternal() +{ + chain = NULL; +} + +TS_INLINE void +UDPPacketInternal::free() +{ + chain = NULL; + if (conn) + conn->Release(); + conn = NULL; + udpPacketAllocator.free(this); +} + +TS_INLINE void +UDPPacketInternal::append_bytes(char *buf, int len) +{ + IOBufferData *d = NULL; + if (buf) { + d = new_xmalloc_IOBufferData(buf, len); + append_block(new_IOBufferBlock(d, len)); + } +} + +TS_INLINE void +UDPPacket::setReliabilityPkt() +{ + UDPPacketInternal *p = (UDPPacketInternal *) this; + + p->isReliabilityPkt = true; +} + +TS_INLINE void +UDPPacket::append_block(IOBufferBlock * block) +{ + UDPPacketInternal *p = (UDPPacketInternal *) this; + + if (block) { + if (p->chain) { // append to end + IOBufferBlock *last = p->chain; + while (last->next != NULL) { + last = last->next; + } + last->next = block; + } else { + p->chain = block; + } + } +} + +TS_INLINE int64_t +UDPPacket::getPktLength() +{ + UDPPacketInternal *p = (UDPPacketInternal *) this; + IOBufferBlock *b; + + p->pktLength = 0; + b = p->chain; + while (b) { + p->pktLength += b->read_avail(); + b = b->next; + } + return p->pktLength; +} + +TS_INLINE void +UDPPacket::free() +{ + ((UDPPacketInternal *) this)->free(); +} + +TS_INLINE void +UDPPacket::setContinuation(Continuation * c) +{ + ((UDPPacketInternal *) this)->cont = c; +} + +TS_INLINE void +UDPPacket::setConnection(UDPConnection * c) +{ + /*Code reviewed by Case Larsen. Previously, we just had + ink_assert(!conn). This prevents tunneling of packets + correctly---that is, you get packets from a server on a udp + conn. and want to send it to a player on another connection, the + assert will prevent that. The "if" clause enables correct + handling of the connection ref. counts in such a scenario. */ + + UDPConnectionInternal *&conn = ((UDPPacketInternal *) this)->conn; + + if (conn) { + if (conn == c) + return; + conn->Release(); + conn = NULL; + } + conn = (UDPConnectionInternal *) c; + conn->AddRef(); +} + +TS_INLINE IOBufferBlock * +UDPPacket::getIOBlockChain(void) +{ + return ((UDPPacketInternal *) this)->chain; +} + +TS_INLINE UDPConnection * +UDPPacket::getConnection(void) +{ + return ((UDPPacketInternal *) this)->conn; +} + +TS_INLINE void +UDPPacket::setArrivalTime(ink_hrtime t) +{ + ((UDPPacketInternal *) this)->arrival_time = t; +} + +TS_INLINE UDPPacket * +new_UDPPacket(struct sockaddr_in *to, ink_hrtime when, char *buf, int len) +{ + UDPPacketInternal *p = udpPacketAllocator.alloc(); + +#if defined(PACKETQUEUE_IMPL_AS_PQLIST) || defined(PACKETQUEUE_IMPL_AS_RING) + p->in_the_priority_queue = 0; + p->in_heap = 0; +#endif + p->delivery_time = when; + memcpy(&p->to, to, sizeof(p->to)); + + if (buf) { + IOBufferBlock *body = new_IOBufferBlock(); + body->alloc(iobuffer_size_to_index(len)); + memcpy(body->end(), buf, len); + body->fill(len); + p->append_block(body); + } + + return p; +} + +TS_INLINE UDPPacket * +new_UDPPacket(struct sockaddr_in * to, ink_hrtime when, IOBufferBlock * buf, int len) +{ + (void) len; + UDPPacketInternal *p = udpPacketAllocator.alloc(); + IOBufferBlock *body; + +#if defined(PACKETQUEUE_IMPL_AS_PQLIST) || defined(PACKETQUEUE_IMPL_AS_RING) + p->in_the_priority_queue = 0; + p->in_heap = 0; +#endif + p->delivery_time = when; + memcpy(&p->to, to, sizeof(p->to)); + + while (buf) { + body = buf->clone(); + p->append_block(body); + buf = buf->next; + } + return p; +} + +TS_INLINE UDPPacket * +new_UDPPacket(struct sockaddr_in * to, ink_hrtime when, Ptr buf) +{ + UDPPacketInternal *p = udpPacketAllocator.alloc(); + +#if defined(PACKETQUEUE_IMPL_AS_PQLIST) || defined(PACKETQUEUE_IMPL_AS_RING) + p->in_the_priority_queue = 0; + p->in_heap = 0; +#endif + p->delivery_time = when; + if (to) + memcpy(&p->to, to, sizeof(p->to)); + p->chain = buf; + return p; +} + +TS_INLINE UDPPacket * +new_UDPPacket(ink_hrtime when, Ptr buf) +{ + return new_UDPPacket(NULL, when, buf); +} + +TS_INLINE UDPPacket * +new_incoming_UDPPacket(struct sockaddr_in * from, char *buf, int len) +{ + UDPPacketInternal *p = udpPacketAllocator.alloc(); + +#if defined(PACKETQUEUE_IMPL_AS_PQLIST) || defined(PACKETQUEUE_IMPL_AS_RING) + p->in_the_priority_queue = 0; + p->in_heap = 0; +#endif + p->delivery_time = 0; + memcpy(&p->from, from, sizeof(p->from)); + + IOBufferBlock *body = new_IOBufferBlock(); + body->alloc(iobuffer_size_to_index(len)); + memcpy(body->end(), buf, len); + body->fill(len); + p->append_block(body); + + return p; +} + +TS_INLINE UDPPacket * +new_UDPPacket() +{ + UDPPacketInternal *p = udpPacketAllocator.alloc(); + return p; +} + +#endif //__P_UDPPPACKET_H_ diff --git a/iocore/net/P_UnixCompletionUtil.h b/iocore/net/P_UnixCompletionUtil.h new file mode 100644 index 00000000..59bc6acc --- /dev/null +++ b/iocore/net/P_UnixCompletionUtil.h @@ -0,0 +1,108 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _UNIX_COMPLETION_UTIL_H_ +#define _UNIX_COMPLETION_UTIL_H_ + +#ifdef _IOCORE_WIN32_WINNT +#error "Some kind of problem with your include path" +#endif + +// platform specific wrappers for dealing with I/O completion events +// passed into and back from the I/O core. +#include "P_UDPIOEvent.h" + +TS_INLINE Event * +completionUtil::create() +{ + UDPIOEvent *u = UDPIOEventAllocator.alloc(); + return u; +} +TS_INLINE void +completionUtil::destroy(Event * e) +{ + ink_assert(e != NULL); + UDPIOEvent *u = (UDPIOEvent *) e; + UDPIOEvent::free(u); +} +TS_INLINE void +completionUtil::setThread(Event * e, EThread * t) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->ethread = t; +} +TS_INLINE void +completionUtil::setContinuation(Event * e, Continuation * c) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + *(Action *) u = c; +} +TS_INLINE void * +completionUtil::getHandle(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getHandle(); +} +TS_INLINE void +completionUtil::setHandle(Event * e, void *handle) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->setHandle(handle); +} +TS_INLINE void +completionUtil::setInfo(Event * e, int fd, IOBufferBlock * buf, int actual, int errno_) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->setInfo(fd, buf, actual, errno_); +} +TS_INLINE void +completionUtil::setInfo(Event * e, int fd, struct msghdr *msg, int actual, int errno_) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->setInfo(fd, msg, actual, errno_); +} +TS_INLINE int +completionUtil::getBytesTransferred(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getBytesTransferred(); +} +TS_INLINE IOBufferBlock * +completionUtil::getIOBufferBlock(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getIOBufferBlock(); +} +TS_INLINE Continuation * +completionUtil::getContinuation(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getContinuation(); +} +TS_INLINE int +completionUtil::getError(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getError(); +} +#endif diff --git a/iocore/net/P_UnixNet.h b/iocore/net/P_UnixNet.h new file mode 100644 index 00000000..ad5d607e --- /dev/null +++ b/iocore/net/P_UnixNet.h @@ -0,0 +1,720 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __P_UNIXNET_H__ +#define __P_UNIXNET_H__ + +#include "libts.h" + +#define USE_EDGE_TRIGGER_EPOLL 1 +#define USE_EDGE_TRIGGER_KQUEUE 1 +#define USE_EDGE_TRIGGER_PORT 1 + + +#define EVENTIO_NETACCEPT 1 +#define EVENTIO_READWRITE_VC 2 +#define EVENTIO_DNS_CONNECTION 3 +#define EVENTIO_UDP_CONNECTION 4 +#define EVENTIO_ASYNC_SIGNAL 5 + +#if TS_USE_LIBEV +#define EVENTIO_READ EV_READ +#define EVENTIO_WRITE EV_WRITE +#define EVENTIO_ERROR EV_ERROR +#endif + +#if TS_USE_EPOLL +#ifdef USE_EDGE_TRIGGER_EPOLL +#define USE_EDGE_TRIGGER 1 +#define EVENTIO_READ (EPOLLIN|EPOLLET) +#define EVENTIO_WRITE (EPOLLOUT|EPOLLET) +#else +#define EVENTIO_READ EPOLLIN +#define EVENTIO_WRITE EPOLLOUT +#endif +#define EVENTIO_ERROR (EPOLLERR|EPOLLPRI|EPOLLHUP) +#endif + +#if TS_USE_KQUEUE +#ifdef USE_EDGE_TRIGGER_KQUEUE +#define USE_EDGE_TRIGGER 1 +#define INK_EV_EDGE_TRIGGER EV_CLEAR +#else +#define INK_EV_EDGE_TRIGGER 0 +#endif +#define EVENTIO_READ INK_EVP_IN +#define EVENTIO_WRITE INK_EVP_OUT +#define EVENTIO_ERROR (0x010|0x002|0x020) // ERR PRI HUP +#endif +#if TS_USE_PORT +#ifdef USE_EDGE_TRIGGER_PORT +#define USE_EDGE_TRIGGER 1 +#endif +#define EVENTIO_READ POLLIN +#define EVENTIO_WRITE POLLOUT +#define EVENTIO_ERROR (POLLERR|POLLPRI|POLLHUP) +#endif + +#if TS_USE_LIBEV +#define EV_MINPRI 0 +#define EV_MAXPRI 0 +#include "ev.h" +typedef void (*eio_cb_t)(struct ev_loop*, struct ev_io*, int); +// expose libev internals +#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) +typedef void ANFD; +typedef struct { + ev_watcher *w; + int events; +} ANPENDING; +typedef void ANHE; +typedef ev_watcher *W; +struct ev_loop +{ + ev_tstamp ev_rt_now; +#define ev_rt_now ((loop)->ev_rt_now) +#define VAR(name,decl) decl; +#include "ev_vars.h" +#undef VAR +}; +extern "C" void fd_change(struct ev_loop *, int fd, int flags); +#endif /* USE_LIBEV */ + +struct PollDescriptor; +typedef PollDescriptor *EventLoop; + +class UnixNetVConnection; +class UnixUDPConnection; +struct DNSConnection; +struct NetAccept; +struct EventIO +{ +#if TS_USE_LIBEV + ev_io eio; +#define evio_get_port(e) ((e)->eio.fd) +#else + int fd; +#define evio_get_port(e) ((e)->fd) +#endif +#if TS_USE_KQUEUE || TS_USE_EPOLL && !defined(USE_EDGE_TRIGGER) || TS_USE_PORT + int events; +#endif + EventLoop event_loop; + int type; + union + { + Continuation *c; + UnixNetVConnection *vc; + DNSConnection *dnscon; + NetAccept *na; + UnixUDPConnection *uc; + } data; + int start(EventLoop l, DNSConnection *vc, int events); + int start(EventLoop l, NetAccept *vc, int events); + int start(EventLoop l, UnixNetVConnection *vc, int events); + int start(EventLoop l, UnixUDPConnection *vc, int events); + int start(EventLoop l, int fd, Continuation *c, int events); + // Change the existing events by adding modify(EVENTIO_READ) + // or removing modify(-EVENTIO_READ), for level triggered I/O + int modify(int events); + // Refresh the existing events (i.e. KQUEUE EV_CLEAR), for edge triggered I/O + int refresh(int events); + int stop(); + int close(); + EventIO() { +#if !TS_USE_LIBEV + fd = 0; +#endif + type = 0; + data.c = 0; + } +}; + +#include "P_UnixNetProcessor.h" +#include "P_UnixNetVConnection.h" +#include "P_NetAccept.h" +#include "P_DNSConnection.h" +#include "P_UnixUDPConnection.h" +#include "P_UnixPollDescriptor.h" + +#define EVENTFD 5 + +class UnixNetVConnection; +class NetHandler; +typedef int (NetHandler::*NetContHandler) (int, void *); +typedef unsigned int uint32; + +extern ink_hrtime last_throttle_warning; +extern ink_hrtime last_shedding_warning; +extern ink_hrtime emergency_throttle_time; +extern int net_connections_throttle; +extern int fds_throttle; +extern bool throttle_enabled; +extern int fds_limit; +extern ink_hrtime last_transient_accept_error; +extern int http_accept_port_number; + + +//#define INACTIVITY_TIMEOUT +// +// Configuration Parameter had to move here to share +// between UnixNet and UnixUDPNet or SSLNet modules. +// Design notes are in Memo.NetDesign +// + +#define THROTTLE_FD_HEADROOM (128 + 64) // CACHE_DB_FDS + 64 + +#define TRANSIENT_ACCEPT_ERROR_MESSAGE_EVERY HRTIME_HOURS(24) +#define ACCEPT_THREAD_POLL_TIMEOUT 100 // msecs +#define NET_PRIORITY_MSEC 4 +#define NET_PRIORITY_PERIOD HRTIME_MSECONDS(NET_PRIORITY_MSEC) +// p' = p + (p / NET_PRIORITY_LOWER) +#define NET_PRIORITY_LOWER 2 +// p' = p / NET_PRIORITY_HIGHER +#define NET_PRIORITY_HIGHER 2 +#define NET_RETRY_DELAY HRTIME_MSECONDS(10) +#define MAX_ACCEPT_PERIOD HRTIME_MSECONDS(100) + +// also the 'throttle connect headroom' +#define THROTTLE_AT_ONCE 5 +#define EMERGENCY_THROTTLE 16 +#define HYPER_EMERGENCY_THROTTLE 6 + +#define NET_THROTTLE_ACCEPT_HEADROOM 1.1 // 10% +#define NET_THROTTLE_CONNECT_HEADROOM 1.0 // 0% +#define NET_THROTTLE_MESSAGE_EVERY HRTIME_MINUTES(10) +#define NET_PERIOD -HRTIME_MSECONDS(5) +#define ACCEPT_PERIOD -HRTIME_MSECONDS(4) +#define NET_INITIAL_PRIORITY 0 +#define MAX_NET_BUCKETS 256 +#define MAX_EPOLL_ARRAY_SIZE (1024*16) +#define MAX_EPOLL_TIMEOUT 50 /* mseconds */ +/* NOTE: moved DEFAULT_POLL_TIMEOUT to I_NetConfig.h */ +#define NET_THROTTLE_DELAY 50 /* mseconds */ +#define INK_MIN_PRIORITY 0 + +#define PRINT_IP(x) ((uint8_t*)&(x))[0],((uint8_t*)&(x))[1], ((uint8_t*)&(x))[2],((uint8_t*)&(x))[3] + + +// function prototype needed for SSLUnixNetVConnection +unsigned int net_next_connection_number(); + +struct PollCont:public Continuation +{ + NetHandler *net_handler; + PollDescriptor *pollDescriptor; + PollDescriptor *nextPollDescriptor; + int poll_timeout; + + PollCont(ProxyMutex * m, int pt = net_config_poll_timeout); + PollCont(ProxyMutex * m, NetHandler * nh, int pt = net_config_poll_timeout); + ~PollCont(); + int pollEvent(int event, Event * e); +}; + + +// +// NetHandler +// +// A NetHandler handles the Network IO operations. It maintains +// lists of operations at multiples of it's periodicity. +// +class NetHandler:public Continuation +{ +public: + Event *trigger_event; + QueM(UnixNetVConnection, NetState, read, ready_link) read_ready_list; + QueM(UnixNetVConnection, NetState, write, ready_link) write_ready_list; + Que(UnixNetVConnection, link) open_list; + DList(UnixNetVConnection, cop_link) cop_list; + ASLLM(UnixNetVConnection, NetState, read, enable_link) read_enable_list; + ASLLM(UnixNetVConnection, NetState, write, enable_link) write_enable_list; + + time_t sec; + int cycles; + + int startNetEvent(int event, Event * data); + int mainNetEvent(int event, Event * data); + int mainNetEventExt(int event, Event * data); + void process_enabled_list(NetHandler *, EThread *); + + NetHandler(); +}; + +static inline NetHandler * +get_NetHandler(EThread * t) +{ + return (NetHandler *) ETHREAD_GET_PTR(t, unix_netProcessor.netHandler_offset); +} +static inline PollCont * +get_PollCont(EThread * t) +{ + return (PollCont *) ETHREAD_GET_PTR(t, unix_netProcessor.pollCont_offset); +} +static inline PollDescriptor * +get_PollDescriptor(EThread * t) +{ + PollCont *p = get_PollCont(t); + return p->pollDescriptor; +} + + +enum ThrottleType +{ ACCEPT, CONNECT }; + +TS_INLINE int +net_connections_to_throttle(ThrottleType t) +{ + + double headroom = t == ACCEPT ? NET_THROTTLE_ACCEPT_HEADROOM : NET_THROTTLE_CONNECT_HEADROOM; + int64_t sval = 0; + + NET_READ_GLOBAL_DYN_SUM(net_connections_currently_open_stat, sval); + int currently_open = (int) sval; + // deal with race if we got to multiple net threads + if (currently_open < 0) + currently_open = 0; + return (int) (currently_open * headroom); +} + +TS_INLINE void +check_shedding_warning() +{ + ink_hrtime t = ink_get_hrtime(); + if (t - last_shedding_warning > NET_THROTTLE_MESSAGE_EVERY) { + last_shedding_warning = t; + IOCORE_SignalWarning(REC_SIGNAL_SYSTEM_ERROR, "number of connections reaching shedding limit"); + } +} + +TS_INLINE int +emergency_throttle(ink_hrtime now) +{ + return emergency_throttle_time > now; +} + +TS_INLINE int +check_net_throttle(ThrottleType t, ink_hrtime now) +{ + if(throttle_enabled == false) { + // added by Vijay to disable throttle. This is done find out if + // there any other problem other than the stats problem -- bug 3040824 + return false; + } + int connections = net_connections_to_throttle(t); + if (connections >= net_connections_throttle) + return true; + + if (emergency_throttle(now)) + return true; + + return false; +} + +TS_INLINE void +check_throttle_warning() +{ + ink_hrtime t = ink_get_hrtime(); + if (t - last_throttle_warning > NET_THROTTLE_MESSAGE_EVERY) { + last_throttle_warning = t; + IOCORE_SignalWarning(REC_SIGNAL_SYSTEM_ERROR, "too many connections, throttling"); + + } +} + +// +// Emergency throttle when we are close to exhausting file descriptors. +// Block all accepts or connects for N seconds where N +// is the amount into the emergency fd stack squared +// (e.g. on the last file descriptor we have 14 * 14 = 196 seconds +// of emergency throttle). +// +// Hyper Emergency throttle when we are very close to exhausting file +// descriptors. Close the connection immediately, the upper levels +// will recover. +// +TS_INLINE int +check_emergency_throttle(Connection & con) +{ + int fd = con.fd; + int emergency = fds_limit - EMERGENCY_THROTTLE; + if (fd > emergency) { + int over = fd - emergency; + emergency_throttle_time = ink_get_hrtime() + (over * over) * HRTIME_SECOND; + IOCORE_SignalWarning(REC_SIGNAL_SYSTEM_ERROR, "too many open file descriptors, emergency throttling"); + int hyper_emergency = fds_limit - HYPER_EMERGENCY_THROTTLE; + if (fd > hyper_emergency) + con.close(); + return true; + } + return false; +} + + +TS_INLINE int +change_net_connections_throttle(const char *token, RecDataT data_type, RecData value, void *data) +{ + (void) token; + (void) data_type; + (void) value; + (void) data; + int throttle = fds_limit - THROTTLE_FD_HEADROOM; + if (fds_throttle < 0) + net_connections_throttle = throttle; + else { + net_connections_throttle = fds_throttle; + if (net_connections_throttle > throttle) + net_connections_throttle = throttle; + } + return 0; +} + + +// 1 - transient +// 0 - report as warning +// -1 - fatal +TS_INLINE int +accept_error_seriousness(int res) +{ + switch (res) { + case -EAGAIN: + case -ECONNABORTED: + case -ECONNRESET: // for Linux + case -EPIPE: // also for Linux + return 1; + case -EMFILE: + case -ENOMEM: +#if !defined(freebsd) + case -ENOSR: +#endif + ink_assert(!"throttling misconfigured: set too high"); +#ifdef ENOBUFS + case -ENOBUFS: +#endif +#ifdef ENFILE + case -ENFILE: +#endif + return 0; + case -EINTR: + ink_assert(!"should be handled at a lower level"); + return 0; +#if !defined(freebsd) + case -EPROTO: +#endif + case -EOPNOTSUPP: + case -ENOTSOCK: + case -ENODEV: + case -EBADF: + default: + return -1; + } +} + +TS_INLINE void +check_transient_accept_error(int res) +{ + ink_hrtime t = ink_get_hrtime(); + if (!last_transient_accept_error || t - last_transient_accept_error > TRANSIENT_ACCEPT_ERROR_MESSAGE_EVERY) { + last_transient_accept_error = t; + Warning("accept thread received transient error: errno = %d", -res); +#if defined(linux) + if (res == -ENOBUFS || res == -ENFILE) + Warning("errno : %d consider a memory upgrade", -res); +#endif + } +} + +// +// Disable a UnixNetVConnection +// +static inline void +read_disable(NetHandler * nh, UnixNetVConnection * vc) +{ +#ifdef INACTIVITY_TIMEOUT + if (vc->inactivity_timeout) { + if (!vc->write.enabled) { + vc->inactivity_timeout->cancel_action(); + vc->inactivity_timeout = NULL; + } + } +#else + if (!vc->write.enabled) + vc->next_inactivity_timeout_at = 0; +#endif + vc->read.enabled = 0; + nh->read_ready_list.remove(vc); + vc->ep.modify(-EVENTIO_READ); +} + +static inline void +write_disable(NetHandler * nh, UnixNetVConnection * vc) +{ +#ifdef INACTIVITY_TIMEOUT + if (vc->inactivity_timeout) { + if (!vc->read.enabled) { + vc->inactivity_timeout->cancel_action(); + vc->inactivity_timeout = NULL; + } + } +#else + if (!vc->read.enabled) + vc->next_inactivity_timeout_at = 0; +#endif + vc->write.enabled = 0; + nh->write_ready_list.remove(vc); + vc->ep.modify(-EVENTIO_WRITE); +} + +TS_INLINE int EventIO::start(EventLoop l, DNSConnection *vc, int events) { + type = EVENTIO_DNS_CONNECTION; + return start(l, vc->fd, (Continuation*)vc, events); +} +TS_INLINE int EventIO::start(EventLoop l, NetAccept *vc, int events) { + type = EVENTIO_NETACCEPT; + return start(l, vc->server.fd, (Continuation*)vc, events); +} +TS_INLINE int EventIO::start(EventLoop l, UnixNetVConnection *vc, int events) { + type = EVENTIO_READWRITE_VC; + return start(l, vc->con.fd, (Continuation*)vc, events); +} +TS_INLINE int EventIO::start(EventLoop l, UnixUDPConnection *vc, int events) { + type = EVENTIO_UDP_CONNECTION; + return start(l, vc->fd, (Continuation*)vc, events); +} +TS_INLINE int EventIO::close() { + stop(); + switch (type) { + default: ink_assert(!"case"); + case EVENTIO_DNS_CONNECTION: return data.dnscon->close(); break; + case EVENTIO_NETACCEPT: return data.na->server.close(); break; + case EVENTIO_READWRITE_VC: return data.vc->con.close(); break; + } + return -1; +} + +#if TS_USE_LIBEV + +TS_INLINE int EventIO::start(EventLoop l, int afd, Continuation *c, int e) { + event_loop = l; + data.c = c; + ev_init(&eio, (eio_cb_t)this); + ev_io_set(&eio, afd, e); + ev_io_start(l->eio, &eio); + return 0; +} + +TS_INLINE int EventIO::modify(int e) { + ink_assert(event_loop); + int ee = eio.events; + if (e < 0) + ee &= ~(-e); + else + ee |= e; + if (ee != eio.events) { + eio.events = ee; + fd_change(event_loop->eio, eio.fd, 0); + } + return 0; +} + +TS_INLINE int EventIO::refresh(int e) { + return 0; +} + +TS_INLINE int EventIO::stop() { + if (event_loop) { + ev_io_stop(event_loop->eio, &eio); + event_loop = 0; + } + return 0; +} + +#else /* !TS_USE_LIBEV */ + +TS_INLINE int EventIO::start(EventLoop l, int afd, Continuation *c, int e) { + data.c = c; + fd = afd; + event_loop = l; +#if TS_USE_EPOLL + struct epoll_event ev; + memset(&ev, 0, sizeof(ev)); + ev.events = e; + ev.data.ptr = this; +#ifndef USE_EDGE_TRIGGER + events = e; +#endif + return epoll_ctl(event_loop->epoll_fd, EPOLL_CTL_ADD, fd, &ev); +#endif +#if TS_USE_KQUEUE + events = e; + struct kevent ev[2]; + int n = 0; + if (e & EVENTIO_READ) + EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD|INK_EV_EDGE_TRIGGER, 0, 0, this); + if (e & EVENTIO_WRITE) + EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD|INK_EV_EDGE_TRIGGER, 0, 0, this); + return kevent(l->kqueue_fd, &ev[0], n, NULL, 0, NULL); +#endif +#if TS_USE_PORT + events = e; + int retval = port_associate(event_loop->port_fd, PORT_SOURCE_FD, fd, events, this); + Debug("iocore_eventio", "[EventIO::start] e(%d), events(%d), %d[%s]=port_associate(%d,%d,%d,%d,%p)", e, events, retval, retval<0? strerror(errno) : "ok", event_loop->port_fd, PORT_SOURCE_FD, fd, events, this); + return retval; +#endif +} + +TS_INLINE int EventIO::modify(int e) { +#if TS_USE_EPOLL && !defined(USE_EDGE_TRIGGER) + struct epoll_event ev; + memset(&ev, 0, sizeof(ev)); + int new_events = events, old_events = events; + if (e < 0) + new_events &= ~(-e); + else + new_events |= e; + events = new_events; + ev.events = new_events; + ev.data.ptr = this; + if (!new_events) + return epoll_ctl(event_loop->epoll_fd, EPOLL_CTL_DEL, fd, &ev); + else if (!old_events) + return epoll_ctl(event_loop->epoll_fd, EPOLL_CTL_ADD, fd, &ev); + else + return epoll_ctl(event_loop->epoll_fd, EPOLL_CTL_MOD, fd, &ev); +#endif +#if TS_USE_KQUEUE && !defined(USE_EDGE_TRIGGER) + int n = 0; + struct kevent ev[2]; + int ee = events; + if (e < 0) { + ee &= ~(-e); + if ((-e) & EVENTIO_READ) + EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, this); + if ((-e) & EVENTIO_WRITE) + EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, this); + } else { + ee |= e; + if (e & EVENTIO_READ) + EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD|INK_EV_EDGE_TRIGGER, 0, 0, this); + if (e & EVENTIO_WRITE) + EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD|INK_EV_EDGE_TRIGGER, 0, 0, this); + } + events = ee; + if (n) + return kevent(event_loop->kqueue_fd, &ev[0], n, NULL, 0, NULL); + else + return 0; +#endif +#if TS_USE_PORT + int n = 0; + int ne = e; + if (e < 0) { + if (((-e) & events)) { + ne = ~(-e) & events; + if ((-e) & EVENTIO_READ) + n++; + if ((-e) & EVENTIO_WRITE) + n++; + } + } else { + if (!(e & events)) { + ne = events | e; + if (e & EVENTIO_READ) + n++; + if (e & EVENTIO_WRITE) + n++; + } + } + if (n && ne && event_loop) { + events = ne; + int retval = port_associate(event_loop->port_fd, PORT_SOURCE_FD, fd, events, this); + Debug("iocore_eventio", "[EventIO::modify] e(%d), ne(%d), events(%d), %d[%s]=port_associate(%d,%d,%d,%d,%p)", e, ne, events, retval, retval<0? strerror(errno) : "ok", event_loop->port_fd, PORT_SOURCE_FD, fd, events, this); + return retval; + } + return 0; +#else + NOWARN_UNUSED(e); + return 0; +#endif +} + +TS_INLINE int EventIO::refresh(int e) { +#if TS_USE_KQUEUE && defined(USE_EDGE_TRIGGER) + e = e & events; + struct kevent ev[2]; + int n = 0; + if (e & EVENTIO_READ) + EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD|INK_EV_EDGE_TRIGGER, 0, 0, this); + if (e & EVENTIO_WRITE) + EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD|INK_EV_EDGE_TRIGGER, 0, 0, this); + if (n) + return kevent(event_loop->kqueue_fd, &ev[0], n, NULL, 0, NULL); + else + return 0; +#endif +#if TS_USE_PORT + int n = 0; + int ne = e; + if ((e & events)) { + ne = events | e; + if (e & EVENTIO_READ) + n++; + if (e & EVENTIO_WRITE) + n++; + if (n && ne && event_loop) { + events = ne; + int retval = port_associate(event_loop->port_fd, PORT_SOURCE_FD, fd, events, this); + Debug("iocore_eventio", "[EventIO::refresh] e(%d), ne(%d), events(%d), %d[%s]=port_associate(%d,%d,%d,%d,%p)", + e, ne, events, retval, retval<0? strerror(errno) : "ok", event_loop->port_fd, PORT_SOURCE_FD, fd, events, this); + return retval; + } + } + return 0; +#else + NOWARN_UNUSED(e); + return 0; +#endif +} + + +TS_INLINE int EventIO::stop() { + if (event_loop) { +#if TS_USE_EPOLL + struct epoll_event ev; + memset(&ev, 0, sizeof(struct epoll_event)); + ev.events = EPOLLIN | EPOLLOUT | EPOLLET; + return epoll_ctl(event_loop->epoll_fd, EPOLL_CTL_DEL, fd, &ev); +#endif +#if TS_USE_PORT + int retval = port_dissociate(event_loop->port_fd, PORT_SOURCE_FD, fd); + Debug("iocore_eventio", "[EventIO::stop] %d[%s]=port_dissociate(%d,%d,%d)", retval, retval<0? strerror(errno) : "ok", event_loop->port_fd, PORT_SOURCE_FD, fd); + return retval; +#endif + event_loop = 0; + } + return 0; +} + +#endif /* !TS_USE_LIBEV */ + +#endif diff --git a/iocore/net/P_UnixNetProcessor.h b/iocore/net/P_UnixNetProcessor.h new file mode 100644 index 00000000..43508644 --- /dev/null +++ b/iocore/net/P_UnixNetProcessor.h @@ -0,0 +1,100 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __UNIXNETPROCESSOR_H__ +#define __UNIXNETPROCESSOR_H__ +#include "I_Net.h" +#include "P_NetAccept.h" + +class UnixNetVConnection; + +////////////////////////////////////////////////////////////////// +// +// class UnixNetProcessor +// +////////////////////////////////////////////////////////////////// +struct UnixNetProcessor:public NetProcessor +{ +public: +virtual Action *accept_internal (Continuation * cont, + int fd, + sockaddr * bound_sockaddr = NULL, + int *bound_sockaddr_size = NULL, + bool frequent_accept = true, + AcceptFunctionPtr fn = net_accept, + unsigned int accept_ip = INADDR_ANY, + char *accept_ip_str = NULL, + AcceptOptions const &opt = DEFAULT_ACCEPT_OPTIONS); + + Action *connect_re_internal(Continuation * cont, unsigned int ip, int port, NetVCOptions * options = NULL); + Action *connect(Continuation * cont, UnixNetVConnection ** vc, unsigned int ip, int port, NetVCOptions * opt = NULL); + + // Virtual function allows etype to be upgraded to ET_SSL for SSLNetProcessor. Does + // nothing for NetProcessor + virtual void upgradeEtype(EventType & etype) { NOWARN_UNUSED(etype); }; + + // Functions all THREAD_FREE and THREAD_ALLOC to be performed + // for both SSL and regular NetVConnection transparent to + // netProcessor connect functions. + virtual UnixNetVConnection *allocateThread(EThread * t); + virtual void freeThread(UnixNetVConnection * vc, EThread * t); + virtual NetAccept *createNetAccept(); + + virtual int start(int number_of_net_threads = 0 /* uses event threads */ ); + + char *throttle_error_message; + Event *accept_thread_event; + + // offsets for per thread data structures + off_t netHandler_offset; + off_t pollCont_offset; + + // we probably wont need these members + int n_netthreads; + EThread **netthreads; + + char *incoming_ip_to_bind; + int incoming_ip_to_bind_saddr; +}; + + +TS_INLINE Action * +NetProcessor::connect_re(Continuation * cont, unsigned int ip, int port, NetVCOptions * opts) +{ + return static_cast(this)->connect_re_internal(cont, ip, port, opts); +} + + +extern UnixNetProcessor unix_netProcessor; + +// +// Set up a thread to receive events from the NetProcessor +// This function should be called for all threads created to +// accept such events by the EventProcesor. +// +extern void initialize_thread_for_net(EThread * thread, int thread_index); +#if defined(USE_OLD_EVENTFD) +extern void initialize_eventfd(EThread * thread); +#endif +//#include "UnixNet.h" +#endif diff --git a/iocore/net/P_UnixNetState.h b/iocore/net/P_UnixNetState.h new file mode 100644 index 00000000..5c1d4437 --- /dev/null +++ b/iocore/net/P_UnixNetState.h @@ -0,0 +1,61 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + UnixNetState.h + + + NetState + + State information for a particular channel of a NetVConnection + This information is private to the Net module. It is only here + because of the the C++ compiler needs it to define NetVConnection. + + Shared with Cluster.cc + + + + ****************************************************************************/ +#if !defined (_UnixNetState_h_) +#define _UnixNetState_h_ + +#include "List.h" +#include "I_VIO.h" + +class Event; +class UnixNetVConnection; + +struct NetState +{ + volatile int enabled; + VIO vio; + Link ready_link; + SLink enable_link; + int in_enabled_list; + int triggered; + + NetState() : enabled(0), vio(VIO::NONE), in_enabled_list(0), triggered(0) {} +}; + +#endif diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h new file mode 100644 index 00000000..6c924b60 --- /dev/null +++ b/iocore/net/P_UnixNetVConnection.h @@ -0,0 +1,354 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + + This file implements an I/O Processor for network I/O on Unix. + + + ****************************************************************************/ + +#ifndef __P_UNIXNETVCONNECTION_H__ +#define __P_UNIXNETVCONNECTION_H__ + +#include "ink_sock.h" +#include "I_NetVConnection.h" +#include "P_UnixNetState.h" +#include "P_Connection.h" + +class UnixNetVConnection; +class NetHandler; +struct PollDescriptor; + +TS_INLINE void +NetVCOptions::reset() +{ + ip_proto = USE_TCP; + local_port = 0; + port_binding = ANY_PORT; + local_addr = 0; + addr_binding = ANY_ADDR; + f_blocking = false; + f_blocking_connect = false; + socks_support = NORMAL_SOCKS; + socks_version = SOCKS_DEFAULT_VERSION; + socket_recv_bufsize = +#if defined(RECV_BUF_SIZE) + RECV_BUF_SIZE; +#else + 0; +#endif + socket_send_bufsize = 0; + sockopt_flags = 0; + etype = ET_NET; +} + +TS_INLINE void +NetVCOptions::set_sock_param(int _recv_bufsize, int _send_bufsize, unsigned long _opt_flags) +{ + socket_recv_bufsize = _recv_bufsize; + socket_send_bufsize = _send_bufsize; + sockopt_flags = _opt_flags; +} + +struct OOB_callback:public Continuation +{ + char *data; + int length; + Event *trigger; + UnixNetVConnection *server_vc; + Continuation *server_cont; + int retry_OOB_send(int, Event *); + + OOB_callback(ProxyMutex *m, NetVConnection *vc, Continuation *cont, + char *buf, int len):Continuation(m), data(buf), length(len), trigger(0) + { + server_vc = (UnixNetVConnection *) vc; + server_cont = cont; + SET_HANDLER(&OOB_callback::retry_OOB_send); + } +}; + +class UnixNetVConnection:public NetVConnection +{ +public: + + virtual VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf); + virtual VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false); + + virtual Action *send_OOB(Continuation *cont, char *buf, int len); + virtual void cancel_OOB(); + + virtual void setSSLHandshakeWantsRead(bool flag) { NOWARN_UNUSED(flag); return; } + virtual bool getSSLHandshakeWantsRead() { return false; } + virtual void setSSLHandshakeWantsWrite(bool flag) { NOWARN_UNUSED(flag); return; } + + virtual bool getSSLHandshakeWantsWrite() { return false; } + + virtual void do_io_close(int lerrno = -1); + virtual void do_io_shutdown(ShutdownHowTo_t howto); + + //////////////////////////////////////////////////////////// + // Set the timeouts associated with this connection. // + // active_timeout is for the total elasped time of // + // the connection. // + // inactivity_timeout is the elapsed time from the time // + // a read or a write was scheduled during which the // + // connection was unable to sink/provide data. // + // calling these functions repeatedly resets the timeout. // + // These functions are NOT THREAD-SAFE, and may only be // + // called when handing an event from this NetVConnection,// + // or the NetVConnection creation callback. // + //////////////////////////////////////////////////////////// + virtual void set_active_timeout(ink_hrtime timeout_in); + virtual void set_inactivity_timeout(ink_hrtime timeout_in); + virtual void cancel_active_timeout(); + virtual void cancel_inactivity_timeout(); + + // The public interface is VIO::reenable() + virtual void reenable(VIO *vio); + virtual void reenable_re(VIO *vio); + + virtual SOCKET get_socket(); + + virtual ~ UnixNetVConnection(); + + ///////////////////////////////////////////////////////////////// + // instances of UnixNetVConnection should be allocated // + // only from the free list using UnixNetVConnection::alloc(). // + // The constructor is public just to avoid compile errors. // + ///////////////////////////////////////////////////////////////// + UnixNetVConnection(); + +private: + UnixNetVConnection(const NetVConnection &); + UnixNetVConnection & operator =(const NetVConnection &); + +public: + + ///////////////////////// + // UNIX implementation // + ///////////////////////// + void set_enabled(VIO *vio); + + void get_local_sa(); + + // these are not part of the pure virtual interface. They were + // added to reduce the amount of duplicate code in classes inherited + // from NetVConnection (SSL). + virtual int sslStartHandShake(int event, int &err) { + (void) event; + (void) err; + return EVENT_ERROR; + } + virtual bool getSSLHandShakeComplete() { + return (true); + } + virtual bool getSSLClientConnection() + { + return (false); + } + virtual void setSSLClientConnection(bool state) + { + (void) state; + } + virtual void net_read_io(NetHandler *nh, EThread *lthread); + virtual int64_t load_buffer_and_write(int64_t towrite, int64_t &wattempted, int64_t &total_wrote, MIOBufferAccessor & buf); + void readDisable(NetHandler *nh); + void readSignalError(NetHandler *nh, int err); + int readSignalDone(int event, NetHandler *nh); + int readSignalAndUpdate(int event); + void readReschedule(NetHandler *nh); + void writeReschedule(NetHandler *nh); + void netActivity(EThread *lthread); + + Action action_; + volatile int closed; + NetState read; + NetState write; + + LINK(UnixNetVConnection, cop_link); + LINKM(UnixNetVConnection, read, ready_link) + SLINKM(UnixNetVConnection, read, enable_link) + LINKM(UnixNetVConnection, write, ready_link) + SLINKM(UnixNetVConnection, write, enable_link) + + ink_hrtime inactivity_timeout_in; + ink_hrtime active_timeout_in; +#ifdef INACTIVITY_TIMEOUT + Event *inactivity_timeout; +#else + ink_hrtime next_inactivity_timeout_at; +#endif + Event *active_timeout; + EventIO ep; + NetHandler *nh; + unsigned int id; + unsigned int ip; + // unsigned int _interface; // 'interface' conflicts with the C++ keyword + int accept_port; + int port; + + union + { + unsigned int flags; +#define NET_VC_SHUTDOWN_READ 1 +#define NET_VC_SHUTDOWN_WRITE 2 + struct + { + unsigned int got_local_sa:1; + unsigned int shutdown:2; + } f; + }; + struct sockaddr_in local_sa; + + Connection con; + int recursion; + ink_hrtime submit_time; + OOB_callback *oob_ptr; + bool from_accept_thread; + + int startEvent(int event, Event *e); + int acceptEvent(int event, Event *e); + int mainEvent(int event, Event *e); + virtual int connectUp(EThread *t); + virtual void free(EThread *t); + + virtual ink_hrtime get_inactivity_timeout(); + virtual ink_hrtime get_active_timeout(); + + virtual void set_local_addr(); + virtual void set_remote_addr(); +}; + +extern ClassAllocator netVCAllocator; + +typedef int (UnixNetVConnection::*NetVConnHandler) (int, void *); + + +TS_INLINE void +UnixNetVConnection::set_remote_addr() +{ + remote_addr = con.sa; +} + +TS_INLINE void +UnixNetVConnection::set_local_addr() +{ + int local_sa_size = sizeof(local_addr); + safe_getsockname(con.fd, (sockaddr *) & local_addr, &local_sa_size); +} + +TS_INLINE ink_hrtime +UnixNetVConnection::get_active_timeout() +{ + return active_timeout_in; +} + +TS_INLINE ink_hrtime +UnixNetVConnection::get_inactivity_timeout() +{ + return inactivity_timeout_in; +} + +TS_INLINE void +UnixNetVConnection::set_inactivity_timeout(ink_hrtime timeout) +{ + inactivity_timeout_in = timeout; +#ifndef INACTIVITY_TIMEOUT + next_inactivity_timeout_at = ink_get_hrtime() + timeout; +#else + if (inactivity_timeout) + inactivity_timeout->cancel_action(this); + if (inactivity_timeout_in) { + if (read.enabled) { + ink_debug_assert(read.vio.mutex->thread_holding == this_ethread()); + inactivity_timeout = read.vio.mutex->thread_holding->schedule_in_local(this, inactivity_timeout_in); + } else if (write.enabled) { + ink_debug_assert(write.vio.mutex->thread_holding == this_ethread()); + inactivity_timeout = write.vio.mutex->thread_holding->schedule_in_local(this, inactivity_timeout_in); + } else + inactivity_timeout = 0; + } else + inactivity_timeout = 0; +#endif +} + +TS_INLINE void +UnixNetVConnection::set_active_timeout(ink_hrtime timeout) +{ + active_timeout_in = timeout; + if (active_timeout) + active_timeout->cancel_action(this); + if (active_timeout_in) { + if (read.enabled) { + ink_debug_assert(read.vio.mutex->thread_holding == this_ethread()); + active_timeout = thread->schedule_in(this, active_timeout_in); + } else if (write.enabled) { + ink_debug_assert(write.vio.mutex->thread_holding == this_ethread()); + active_timeout = thread->schedule_in(this, active_timeout_in); + } else + active_timeout = 0; + } else + active_timeout = 0; +} + +TS_INLINE void +UnixNetVConnection::cancel_inactivity_timeout() +{ + inactivity_timeout_in = 0; +#ifdef INACTIVITY_TIMEOUT + if (inactivity_timeout) { + inactivity_timeout->cancel_action(this); + inactivity_timeout = NULL; + } +#else + next_inactivity_timeout_at = 0; +#endif +} + +TS_INLINE void +UnixNetVConnection::cancel_active_timeout() +{ + if (active_timeout) { + active_timeout->cancel_action(this); + active_timeout = NULL; + active_timeout_in = 0; + } +} + +TS_INLINE UnixNetVConnection::~UnixNetVConnection() { } + +TS_INLINE SOCKET +UnixNetVConnection::get_socket() { + return con.fd; +} + +// declarations for local use (within the net module) + +void close_UnixNetVConnection(UnixNetVConnection * vc, EThread * t); +void write_to_net(NetHandler * nh, UnixNetVConnection * vc, PollDescriptor * pd, EThread * thread); +void write_to_net_io(NetHandler * nh, UnixNetVConnection * vc, EThread * thread); + +#endif diff --git a/iocore/net/P_UnixPollDescriptor.h b/iocore/net/P_UnixPollDescriptor.h new file mode 100644 index 00000000..bdd1fe0f --- /dev/null +++ b/iocore/net/P_UnixPollDescriptor.h @@ -0,0 +1,158 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + UnixPollDescriptor.h + + +*****************************************************************************/ +#ifndef __P_UNIXPOLLDESCRIPTOR_H__ +#define __P_UNIXPOLLDESCRIPTOR_H__ + +#include "libts.h" + +#if TS_USE_LIBEV +#include "ev.h" +#endif +#if TS_USE_KQUEUE +#include +#define INK_EVP_IN 0x001 +#define INK_EVP_PRI 0x002 +#define INK_EVP_OUT 0x004 +#define INK_EVP_ERR 0x010 +#define INK_EVP_HUP 0x020 +#endif + +#define POLL_DESCRIPTOR_SIZE 32768 + +typedef struct pollfd Pollfd; + +struct PollDescriptor +{ + int result; // result of poll +#if TS_USE_LIBEV + struct ev_loop *eio; +#endif +#if TS_USE_EPOLL + int epoll_fd; + int nfds; // actual number + Pollfd pfd[POLL_DESCRIPTOR_SIZE]; + struct epoll_event ePoll_Triggered_Events[POLL_DESCRIPTOR_SIZE]; +#endif +#if TS_USE_KQUEUE + int kqueue_fd; +#endif +#if TS_USE_PORT + int port_fd; +#endif + +#if TS_USE_LIBEV +#define get_ev_port(a) ((a)->eio->backend_fd) +#define get_ev_events(a,x) (a->eio->pendings[0] + a->eio->pendingcnt[0] - 1)->events +#define get_ev_data(a,x) ((EventIO*)(a->eio->pendings[0] + a->eio->pendingcnt[0] - 1)->w->cb) +#define ev_next_event(a,x) do { \ + (a->eio->pendings[0] + a->eio->pendingcnt[0] - 1)->w->pending = 0; \ + a->eio->pendingcnt[0]--; \ + } while (0) +#endif + +#if TS_USE_EPOLL +#define get_ev_port(a) ((a)->epoll_fd) +#define get_ev_events(a,x) ((a)->ePoll_Triggered_Events[(x)].events) +#define get_ev_data(a,x) ((a)->ePoll_Triggered_Events[(x)].data.ptr) +#define ev_next_event(a,x) +#endif + +#if TS_USE_KQUEUE + struct kevent kq_Triggered_Events[POLL_DESCRIPTOR_SIZE]; + /* we define these here as numbers, because for kqueue mapping them to a combination of + * filters / flags is hard to do. */ +#define get_ev_port(a) ((a)->kqueue_fd) +#define get_ev_events(a,x) ((a)->kq_event_convert((a)->kq_Triggered_Events[(x)].filter, (a)->kq_Triggered_Events[(x)].flags)) +#define get_ev_data(a,x) ((a)->kq_Triggered_Events[(x)].udata) + int kq_event_convert(int16_t event, uint16_t flags) + { + int r = 0; + + if (event == EVFILT_READ) { + r |= INK_EVP_IN; + } + else if (event == EVFILT_WRITE) { + r |= INK_EVP_OUT; + } + + if (flags & EV_EOF) { + r |= INK_EVP_HUP; + } + return r; + } +#define ev_next_event(a,x) +#endif + +#if TS_USE_PORT + port_event_t Port_Triggered_Events[POLL_DESCRIPTOR_SIZE]; +#define get_ev_port(a) ((a)->port_fd) +#define get_ev_events(a,x) ((a)->Port_Triggered_Events[(x)].portev_events) +#define get_ev_data(a,x) ((a)->Port_Triggered_Events[(x)].portev_user) +#define get_ev_odata(a,x) ((a)->Port_Triggered_Events[(x)].portev_object) +#define ev_next_event(a,x) +#endif + + Pollfd *alloc() + { +#if TS_USE_EPOLL + return &pfd[nfds++]; +#else + return 0; +#endif + } + PollDescriptor *init() + { + result = 0; +#if TS_USE_LIBEV + eio = 0; + // eio = ev_loop_new(0); moved to initialize_thread_for_xx --- all this junk should go away +#endif +#if TS_USE_EPOLL + nfds = 0; + epoll_fd = epoll_create(POLL_DESCRIPTOR_SIZE); + memset(ePoll_Triggered_Events, 0, sizeof(ePoll_Triggered_Events)); + memset(pfd, 0, sizeof(pfd)); +#endif +#if TS_USE_KQUEUE + kqueue_fd = kqueue(); + memset(kq_Triggered_Events, 0, sizeof(kq_Triggered_Events)); +#endif +#if TS_USE_PORT + port_fd = port_create(); + memset(Port_Triggered_Events, 0, sizeof(Port_Triggered_Events)); +#endif + return this; + } + PollDescriptor() { + init(); + } +}; + +#endif diff --git a/iocore/net/P_UnixUDPConnection.h b/iocore/net/P_UnixUDPConnection.h new file mode 100644 index 00000000..0387b84d --- /dev/null +++ b/iocore/net/P_UnixUDPConnection.h @@ -0,0 +1,123 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + P_UnixUDPConnection.h + Unix UDPConnection implementation + + + ****************************************************************************/ +#ifndef __UNIXUDPCONNECTION_H_ +#define __UNIXUDPCONNECTION_H_ + +#ifndef _IOCORE_WIN32 + +#include "P_UDPConnection.h" +#include "P_UDPPacket.h" + +class UnixUDPConnection:public UDPConnectionInternal +{ +public: + void init(int the_fd); + void setEthread(EThread * e); + void errorAndDie(int e); + int callbackHandler(int event, void *data); + + LINK(UnixUDPConnection, polling_link); + LINK(UnixUDPConnection, callback_link); + SLINK(UnixUDPConnection, newconn_alink); + + InkAtomicList inQueue; + int onCallbackQueue; + Action *callbackAction; + EThread *ethread; + EventIO ep; + + UnixUDPConnection(int the_fd); + virtual ~ UnixUDPConnection(); +private: + int m_errno; + virtual void UDPConnection_is_abstract() {}; +}; + +TS_INLINE +UnixUDPConnection::UnixUDPConnection(int the_fd) + : onCallbackQueue(0) + , callbackAction(NULL) + , ethread(NULL) + , m_errno(0) +{ + fd = the_fd; + UDPPacketInternal p; + ink_atomiclist_init(&inQueue, "Incoming UDP Packet queue", (char *) &p.alink.next - (char *) &p); + SET_HANDLER(&UnixUDPConnection::callbackHandler); +} + +TS_INLINE void +UnixUDPConnection::init(int the_fd) +{ + fd = the_fd; + onCallbackQueue = 0; + callbackAction = NULL; + ethread = NULL; + m_errno = 0; + + UDPPacketInternal p; + ink_atomiclist_init(&inQueue, "Incoming UDP Packet queue", (char *) &p.alink.next - (char *) &p); + SET_HANDLER(&UnixUDPConnection::callbackHandler); +} + +TS_INLINE void +UnixUDPConnection::setEthread(EThread * e) +{ + ethread = e; +} + +TS_INLINE void +UnixUDPConnection::errorAndDie(int e) +{ + m_errno = e; +} + +TS_INLINE Action * +UDPConnection::recv(Continuation * c) +{ + UnixUDPConnection *p = (UnixUDPConnection *) this; + // register callback interest. + p->continuation = c; + ink_debug_assert(c != NULL); + mutex = c->mutex; + p->recvActive = 1; + return ACTION_RESULT_NONE; +} + + +TS_INLINE UDPConnection * +new_UDPConnection(int fd) +{ + return (fd >= 0) ? NEW(new UnixUDPConnection(fd)) : 0; +} + +#endif //_IOCORE_WIN32 +#endif //__UNIXUDPCONNECTION_H_ diff --git a/iocore/net/SSLCertLookup.cc b/iocore/net/SSLCertLookup.cc new file mode 100644 index 00000000..43f21ce0 --- /dev/null +++ b/iocore/net/SSLCertLookup.cc @@ -0,0 +1,247 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_config.h" + +#include "P_SSLCertLookup.h" +#include "P_UnixNet.h" + +SSLCertLookup sslCertLookup; + +#define SSL_IP_TAG "dest_ip" +#define SSL_CERT_TAG "ssl_cert_name" +#define SSL_PRIVATE_KEY_TAG "ssl_key_name" +#define SSL_CA_TAG "ssl_ca_name" +const char *moduleName = "SSLCertLookup"; + +const matcher_tags sslCertTags = { + NULL, NULL, SSL_IP_TAG, NULL, NULL, false +}; + +SSLCertLookup::SSLCertLookup(): +param(NULL), multipleCerts(false) +{ + SSLCertLookupHashTable = ink_hash_table_create(InkHashTableKeyType_String); + *config_file_path = '\0'; +} + +void +SSLCertLookup::init(SslConfigParams * p) +{ + param = p; + multipleCerts = buildTable(); +} + +bool +SSLCertLookup::buildTable() +{ + char *tok_state = NULL; + char *line = NULL; + const char *errPtr = NULL; + char errBuf[1024]; + char *file_buf = NULL; + int line_num = 0; + bool ret = 0; + char *addr = NULL; + char *sslCert = NULL; + char *sslCa = NULL; + char *priKey = NULL; + matcher_line line_info; + bool alarmAlready = false; + char *configFilePath = NULL; + + if (param != NULL) + configFilePath = param->getConfigFilePath(); + + // Table should be empty +// ink_assert(num_el == 0); + + Debug("ssl", "ssl_multicert.config: %s", configFilePath); + if (configFilePath) + file_buf = readIntoBuffer(configFilePath, moduleName, NULL); + + if (file_buf == NULL) { + Warning("%s Failed to read %s. Using default server cert for all connections", moduleName, configFilePath); + return ret; + } + + line = tokLine(file_buf, &tok_state); + while (line != NULL) { + + line_num++; + + // skip all blank spaces at beginning of line + while (*line && isspace(*line)) { + line++; + } + + if (*line != '\0' && *line != '#') { + + errPtr = parseConfigLine(line, &line_info, &sslCertTags); + + if (errPtr != NULL) { + snprintf(errBuf, 1024, "%s discarding %s entry at line %d : %s", + moduleName, configFilePath, line_num, errPtr); + IOCORE_SignalError(errBuf, alarmAlready); + } else { + ink_assert(line_info.type == MATCH_IP); + + errPtr = extractIPAndCert(&line_info, &addr, &sslCert, &sslCa, &priKey); + + if (errPtr != NULL) { + snprintf(errBuf, 1024, "%s discarding %s entry at line %d : %s", + moduleName, configFilePath, line_num, errPtr); + IOCORE_SignalError(errBuf, alarmAlready); + } else { + if (addr != NULL && sslCert != NULL) { + addInfoToHash(addr, sslCert, sslCa, priKey); + ret = 1; + } + xfree(sslCert); + xfree(sslCa); + xfree(priKey); + xfree(addr); + addr = NULL; + sslCert = NULL; + priKey = NULL; + } + } // else + } // if(*line != '\0' && *line != '#') + + line = tokLine(NULL, &tok_state); + } // while(line != NULL) + +/* if(num_el == 0) + { + Warning("%s No entries in %s. Using default server cert for all connections", + moduleName, configFilePath); + } + + if(is_debug_tag_set("ssl")) + { + Print(); + } +*/ + xfree(file_buf); + return ret; +} + +const char * +SSLCertLookup::extractIPAndCert(matcher_line * line_info, char **addr, char **cert, char **ca, char **priKey) +{ +// ip_addr_t testAddr; + char *label; + char *value; + + for (int i = 0; i < MATCHER_MAX_TOKENS; i++) { + + label = line_info->line[0][i]; + value = line_info->line[1][i]; + + if (label == NULL) { + continue; + } + + if (strcasecmp(label, SSL_IP_TAG) == 0) { + if (value != NULL) { + int buf_len = sizeof(char) * (strlen(value) + 1); + + *addr = (char *) xmalloc(buf_len); + ink_strncpy(*addr, (const char *) value, buf_len); +// testAddr = inet_addr (addr); + } + } + + if (strcasecmp(label, SSL_CERT_TAG) == 0) { + if (value != NULL) { + int buf_len = sizeof(char) * (strlen(value) + 1); + + *cert = (char *) xmalloc(buf_len); + ink_strncpy(*cert, (const char *) value, buf_len); + } + } + + if (strcasecmp(label, SSL_CA_TAG) == 0) { + if (value != NULL) { + int buf_len = sizeof(char) * (strlen(value) + 1); + + *ca = (char *)xmalloc(buf_len); + ink_strlcpy(*ca, (const char *) value, buf_len); + } + } + + if (strcasecmp(label, SSL_PRIVATE_KEY_TAG) == 0) { + if (value != NULL) { + int buf_len = sizeof(char) * (strlen(value) + 1); + + *priKey = (char *) xmalloc(buf_len); + ink_strncpy(*priKey, (const char *) value, buf_len); + } + } + } + + if ( /*testAddr == INADDR_NONE || */ addr != NULL && cert == NULL) + return "Bad address or certificate."; + else + return NULL; +} + +int +SSLCertLookup::addInfoToHash(char *strAddr, char *cert, char *caCert, char *serverPrivateKey) +{ + +#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) // openssl returns a const SSL_METHOD now + const SSL_METHOD *meth = NULL; +#else + SSL_METHOD *meth = NULL; +#endif + meth = SSLv23_server_method(); + SSL_CTX *ctx = SSL_CTX_new(meth); + if (!ctx) { + ssl_NetProcessor.logSSLError("Cannot create new server contex."); + return (false); + } +// if (serverPrivateKey == NULL) +// serverPrivateKey = cert; + + ssl_NetProcessor.initSSLServerCTX(param, ctx, cert, caCert, serverPrivateKey, false); + ink_hash_table_insert(SSLCertLookupHashTable, strAddr, (void *) ctx); + return (true); +} + +SSL_CTX * +SSLCertLookup::findInfoInHash(char *strAddr) +{ + + InkHashTableValue hash_value; + if (ink_hash_table_lookup(SSLCertLookupHashTable, strAddr, &hash_value) == 0) { + return NULL; + } else { + return (SSL_CTX *) hash_value; + } +} + +SSLCertLookup::~SSLCertLookup() +{ + ink_hash_table_destroy_and_xfree_values(SSLCertLookupHashTable); +} diff --git a/iocore/net/SSLConfig.cc b/iocore/net/SSLConfig.cc new file mode 100644 index 00000000..847c0bc1 --- /dev/null +++ b/iocore/net/SSLConfig.cc @@ -0,0 +1,404 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************** -*- Mod: C++ -*- ****************************** + SslConfig.cc + Created On : 07/20/2000 + + Description: + SSL Configurations + ****************************************************************************/ + +#include "libts.h" +#include "I_Layout.h" + +#include +#include "P_Net.h" +#include + +int SslConfig::id = 0; +bool SslConfig::serverSSLTermination = 0; + +SslConfig sslTerminationConfig; + +#ifndef USE_CONFIG_PROCESSOR +SslConfigParams *SslConfig::ssl_config_params; +#endif + +SslConfigParams::SslConfigParams() +{ + serverCertPath = serverCertPathOnly = + serverCertChainPath = + serverKeyPath = configFilePath = + CACertFilename = CACertPath = + clientCertPath = clientKeyPath = + clientCACertFilename = clientCACertPath = + cipherSuite = + serverKeyPathOnly = ncipherAccelLibPath = cswiftAccelLibPath = atallaAccelLibPath = broadcomAccelLibPath = NULL; + + clientCertLevel = client_verify_depth = verify_depth = clientVerify = sslAccelerator = 0; + + ssl_accept_port_number = -1; + termMode = SSL_TERM_MODE_NONE; + ssl_ctx_options = 0; + ssl_accelerator_required = SSL_ACCELERATOR_REQ_NO; + ssl_session_cache = SSL_SESSION_CACHE_MODE_SERVER; + ssl_session_cache_size = 1024*20; +} + +SslConfigParams::~SslConfigParams() +{ + cleanup(); +} + +void +SslConfigParams::cleanup() +{ + if (serverCertPath) { + xfree(serverCertPath); + serverCertPath = NULL; + } + if (serverCertChainPath) { + xfree(serverCertChainPath); + serverCertChainPath = NULL; + } + if (serverKeyPath) { + xfree(serverKeyPath); + serverKeyPath = NULL; + } + if (CACertFilename) { + xfree(CACertFilename); + CACertFilename = NULL; + } + if (CACertPath) { + xfree(CACertPath); + CACertPath = NULL; + } + if (clientCertPath) { + xfree(clientCertPath); + clientCertPath = NULL; + } + if (clientKeyPath) { + xfree(clientKeyPath); + clientKeyPath = NULL; + } + if (clientCACertFilename) { + xfree(clientCACertFilename); + clientCACertFilename = NULL; + } + if (clientCACertPath) { + xfree(clientCACertPath); + clientCACertPath = NULL; + } + if (configFilePath) { + xfree(configFilePath); + configFilePath = NULL; + } + if (serverCertPathOnly) { + xfree(serverCertPathOnly); + serverCertPathOnly = NULL; + } + if (serverKeyPathOnly) { + xfree(serverKeyPathOnly); + serverKeyPathOnly = NULL; + } + if (ncipherAccelLibPath) { + xfree(ncipherAccelLibPath); + ncipherAccelLibPath = NULL; + } + if (cswiftAccelLibPath) { + xfree(cswiftAccelLibPath); + cswiftAccelLibPath = NULL; + } + if (atallaAccelLibPath) { + xfree(atallaAccelLibPath); + atallaAccelLibPath = NULL; + } + if (broadcomAccelLibPath) { + xfree(broadcomAccelLibPath); + broadcomAccelLibPath = NULL; + } + if (cipherSuite) { + xfree(cipherSuite); + cipherSuite = NULL; + } + + clientCertLevel = client_verify_depth = verify_depth = clientVerify = sslAccelerator = 0; + ssl_accept_port_number = -1; + termMode = SSL_TERM_MODE_NONE; +} + +/** set_paths_helper + + If path is *not* absolute, consider it relative to PREFIX + if it's empty, just take SYSCONFDIR, otherwise we can take it as-is + if final_path is NULL, it will not be updated. + + XXX: Add handling for Windows? + */ +static void +set_paths_helper(const char *path, const char *filename, char **final_path, char **final_filename) +{ + if (final_path != NULL) { + if (path && path[0] != '/') { + *final_path = Layout::get()->relative_to(Layout::get()->prefix, path); + } else if (!path || path[0] == '\0'){ + *final_path = xstrdup(Layout::get()->sysconfdir); + } else { + *final_path = xstrdup(path); + } + } + if (filename) { + *final_filename = xstrdup(Layout::get()->relative_to(path, filename)); + } else { + *final_filename = NULL; + } + +#ifdef _WIN32 + i = 0; + while (final_path[i] != 0) { + if (final_path[i] == '/') + final_path[i] = '\\'; + i++; + } + + i = 0; + while (final_filename[i] != 0) { + if (final_filename[i] == '/') + final_filename[i] = '\\'; + i++; + } +#endif +} +void +SslConfigParams::initialize() +{ + char serverCertFilename[PATH_NAME_MAX] = ""; + char serverCertRelativePath[PATH_NAME_MAX] = ""; + char *ssl_server_private_key_filename = NULL; + char *ssl_server_private_key_path = NULL; + char *CACertRelativePath = NULL; + char *ssl_client_cert_filename = NULL; + char *ssl_client_cert_path = NULL; + char *ssl_client_private_key_filename = NULL; + char *ssl_client_private_key_path = NULL; + char *clientCACertRelativePath = NULL; + char *multicert_config_file = NULL; + + int ssl_mode = SSL_TERM_MODE_NONE; + int ret_val; + + cleanup(); + + //+++++++++++++++++++++++++ Server part +++++++++++++++++++++++++++++++++ + verify_depth = 7; + + IOCORE_ReadConfigInteger(ssl_accelerator_required, "proxy.config.ssl.accelerator_required"); + ssl_accelerator_required &= SSL_ACCELERATOR_REQ_BOTH; + + IOCORE_ReadConfigInteger(ssl_mode, "proxy.config.ssl.enabled"); + ssl_mode &= SSL_TERM_MODE_BOTH; + termMode = (SSL_TERMINATION_MODE) ssl_mode; + + IOCORE_ReadConfigStringAlloc(cipherSuite, "proxy.config.ssl.server.cipher_suite"); + + /* if ssl is enabled and we require an accelerator */ + /* XXX: This code does not work */ + if ((termMode & SSL_TERM_MODE_BOTH) && (ssl_accelerator_required & SSL_ACCELERATOR_REQ_BOTH)) { + if (system(NULL)) { + ret_val = system("bin/openssl_accelerated >/dev/null 2>&1"); + Debug("ssl_accelerator_required", "bin/openssl_accelerated returned %d|%d|(%d)", ret_val, + WIFEXITED(ret_val), WEXITSTATUS(ret_val)); + if (WEXITSTATUS(ret_val) != 1) { + if (ssl_accelerator_required & SSL_ACCELERATOR_REQ_MEAN) { + Error + ("You asked to have ssl acceleration only if you have an accelerator card present (and wanted to exit if you didn't), but you don't appear to have one"); + exit(-1); + } else { + Error + ("You asked to have ssl acceleration only if you have an accelerator card present, but you don't appear to have one [what does bin/openssl_accelerated return?]"); + ssl_mode = 0; + termMode = (SSL_TERMINATION_MODE) ssl_mode; + } + } + } else { + Error + ("You asked to have ssl acceleration only if you have an accelerator card present, but I can't determine either way. Disabling for now"); + ssl_mode = 0; + termMode = (SSL_TERMINATION_MODE) ssl_mode; + } + } + + IOCORE_ReadConfigInteger(sslAccelerator, "proxy.config.ssl.accelerator.type"); + + IOCORE_ReadConfigInt32(ssl_accept_port_number, "proxy.config.ssl.server_port"); + IOCORE_ReadConfigInt32(clientCertLevel, "proxy.config.ssl.client.certification_level"); + + IOCORE_ReadConfigStringAlloc(atallaAccelLibPath, "proxy.config.ssl.atalla.lib.path"); +#ifdef _WIN32 + i = 0; + while (atallaAccelLibPath[i] != 0) { + if (atallaAccelLibPath[i] == '/') + atallaAccelLibPath[i] = '\\'; + i++; + } +#endif + + IOCORE_ReadConfigStringAlloc(ncipherAccelLibPath, "proxy.config.ssl.ncipher.lib.path"); +#ifdef _WIN32 + i = 0; + while (ncipherAccelLibPath[i] != 0) { + if (ncipherAccelLibPath[i] == '/') + ncipherAccelLibPath[i] = '\\'; + i++; + } +#endif + + IOCORE_ReadConfigStringAlloc(cswiftAccelLibPath, "proxy.config.ssl.cswift.lib.path"); +#ifdef _WIN32 + i = 0; + while (cswiftAccelLibPath[i] != 0) { + if (cswiftAccelLibPath[i] == '/') + cswiftAccelLibPath[i] = '\\'; + i++; + } +#endif + IOCORE_ReadConfigStringAlloc(broadcomAccelLibPath, "proxy.config.ssl.broadcom.lib.path"); +#ifdef _WIN32 + i = 0; + while (broadcomAccelLibPath[i] != 0) { + if (broadcomAccelLibPath[i] == '/') + broadcomAccelLibPath[i] = '\\'; + i++; + } +#endif + int options; + IOCORE_ReadConfigInteger(options, "proxy.config.ssl.SSLv2"); + if (!options) + ssl_ctx_options |= SSL_OP_NO_SSLv2; + IOCORE_ReadConfigInteger(options, "proxy.config.ssl.SSLv3"); + if (!options) + ssl_ctx_options |= SSL_OP_NO_SSLv3; + IOCORE_ReadConfigInteger(options, "proxy.config.ssl.TLSv1"); + if (!options) + ssl_ctx_options |= SSL_OP_NO_TLSv1; +#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE + IOCORE_ReadConfigInteger(options, "proxy.config.ssl.server.honor_cipher_order"); + if (!options) + ssl_ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE; +#endif + + IOCORE_ReadConfigString(serverCertFilename, "proxy.config.ssl.server.cert.filename", PATH_NAME_MAX); + IOCORE_ReadConfigString(serverCertRelativePath, "proxy.config.ssl.server.cert.path", PATH_NAME_MAX); + set_paths_helper(serverCertRelativePath, serverCertFilename, &serverCertPathOnly, &serverCertPath); + + char *cert_chain = NULL; + IOCORE_ReadConfigStringAlloc(cert_chain, "proxy.config.ssl.server.cert_chain.filename"); + set_paths_helper(serverCertRelativePath, cert_chain, &serverCertPathOnly, &serverCertChainPath); + xfree(cert_chain); + + IOCORE_ReadConfigStringAlloc(multicert_config_file, "proxy.config.ssl.server.multicert.filename"); + set_paths_helper(Layout::get()->sysconfdir, multicert_config_file, NULL, &configFilePath); + xfree(multicert_config_file); + + IOCORE_ReadConfigStringAlloc(ssl_server_private_key_filename, "proxy.config.ssl.server.private_key.filename"); + IOCORE_ReadConfigStringAlloc(ssl_server_private_key_path, "proxy.config.ssl.server.private_key.path"); + set_paths_helper(ssl_server_private_key_path, ssl_server_private_key_filename, &serverKeyPathOnly, &serverKeyPath); + xfree(ssl_server_private_key_filename); + xfree(ssl_server_private_key_path); + + + IOCORE_ReadConfigStringAlloc(CACertFilename, "proxy.config.ssl.CA.cert.filename"); + IOCORE_ReadConfigStringAlloc(CACertRelativePath, "proxy.config.ssl.CA.cert.path"); + set_paths_helper(CACertRelativePath, CACertFilename, &CACertPath, &CACertFilename); + xfree(CACertRelativePath); + + // SSL session cache configurations + IOCORE_ReadConfigInteger(ssl_session_cache, "proxy.config.ssl.session_cache"); + IOCORE_ReadConfigInteger(ssl_session_cache_size, "proxy.config.ssl.session_cache.size"); + + // ++++++++++++++++++++++++ Client part ++++++++++++++++++++ + client_verify_depth = 7; + IOCORE_ReadConfigInt32(clientVerify, "proxy.config.ssl.client.verify.server"); + + ssl_client_cert_filename = NULL; + ssl_client_cert_path = NULL; + IOCORE_ReadConfigStringAlloc(ssl_client_cert_filename, "proxy.config.ssl.client.cert.filename"); + IOCORE_ReadConfigStringAlloc(ssl_client_cert_path, "proxy.config.ssl.client.cert.path"); + set_paths_helper(ssl_client_cert_path, ssl_client_cert_filename, NULL, &clientCertPath); + xfree_null(ssl_client_cert_filename); + xfree_null(ssl_client_cert_path); + + IOCORE_ReadConfigStringAlloc(ssl_client_private_key_filename, "proxy.config.ssl.client.private_key.filename"); + IOCORE_ReadConfigStringAlloc(ssl_client_private_key_path, "proxy.config.ssl.client.private_key.path"); + set_paths_helper(ssl_client_private_key_path, ssl_client_private_key_filename, NULL, &clientKeyPath); + xfree_null(ssl_client_private_key_filename); + xfree_null(ssl_client_private_key_path); + + + IOCORE_ReadConfigStringAlloc(clientCACertFilename, "proxy.config.ssl.client.CA.cert.filename"); + IOCORE_ReadConfigStringAlloc(clientCACertRelativePath, "proxy.config.ssl.client.CA.cert.path"); + set_paths_helper(clientCACertRelativePath, clientCACertFilename, &clientCACertPath, &clientCACertFilename); + xfree(clientCACertRelativePath); +} + + +void +SslConfig::startup() +{ + reconfigure(); +} + + +void +SslConfig::reconfigure() +{ + SslConfigParams *params; + params = NEW(new SslConfigParams); + params->initialize(); // re-read configuration +#ifdef USE_CONFIG_PROCESSOR + id = configProcessor.set(id, params); +#else + ssl_config_params = params; +#endif + serverSSLTermination = (params->termMode & SslConfigParams::SSL_TERM_MODE_SERVER) != 0; +} + +SslConfigParams * +SslConfig::acquire() +{ +#ifndef USE_CONFIG_PROCESSOR + return ssl_config_params; +#else + return ((SslConfigParams *) configProcessor.get(id)); +#endif +} + +void +SslConfig::release(SslConfigParams * params) +{ + (void) params; +#ifdef USE_CONFIG_PROCESSOR + configProcessor.release(id, params); +#endif +} diff --git a/iocore/net/SSLNet.cc b/iocore/net/SSLNet.cc new file mode 100644 index 00000000..6f351111 --- /dev/null +++ b/iocore/net/SSLNet.cc @@ -0,0 +1,521 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + SSLNet.cc -- + + Description: Common SSL initialization/cleanup fuctions from SSLNet.h + ****************************************************************************/ + +#include "ink_config.h" + +#include "P_Net.h" +#include "I_Layout.h" +#if !defined (_IOCORE_WIN32) // remove when NT openssl lib is upgraded to eng-0.9.6 +#include "openssl/engine.h" +#include "openssl/dso.h" +#endif + +void sslLockingCallback(int mode, int type, const char *file, int line); +unsigned long SSL_pthreads_thread_id(); + +bool SSLNetProcessor::open_ssl_initialized = false; + + +int +SSL_CTX_add_extra_chain_cert_file(SSL_CTX * ctx, const char *file) +{ + BIO *in; + int ret = 0; + X509 *x = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + goto end; + } + + // j = ERR_R_PEM_LIB; + while ((x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata)) != NULL) { + ret = SSL_CTX_add_extra_chain_cert(ctx, x); + if (!ret) { + X509_free(x); + BIO_free(in); + return -1; + } + } +/* x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata); + if (x == NULL) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, j); + goto end; + } + + ret = SSL_CTX_add_extra_chain_cert(ctx, x);*/ +end: + // if (x != NULL) X509_free(x); + if (in != NULL) + BIO_free(in); + return (ret); +} + + +void +SSLNetProcessor::cleanup(void) +{ + if (sslMutexArray) { + CRYPTO_set_locking_callback(NULL); + CRYPTO_set_id_callback(NULL); + for (int i = 0; i < CRYPTO_num_locks(); i++) { + sslMutexArray[i]->free(); + } +#if !defined (_IOCORE_WIN32) + OPENSSL_free(sslMutexArray); +#else + Free(sslMutexArray); +#endif + sslMutexArray = NULL; + } + + if (ctx) + SSL_CTX_free(ctx); + ctx = NULL; + if (client_ctx) + SSL_CTX_free(client_ctx); + client_ctx = NULL; +} + +void +SSLNetProcessor::initSSLLocks(void) +{ + +#if !defined (_IOCORE_WIN32) + sslMutexArray = (ProxyMutex **) OPENSSL_malloc(CRYPTO_num_locks() * sizeof(ProxyMutex *)); +#else + sslMutexArray = (ProxyMutex **) Malloc(CRYPTO_num_locks() * sizeof(ProxyMutex *)); +#endif + + for (int i = 0; i < CRYPTO_num_locks(); i++) { + sslMutexArray[i] = new_ProxyMutex(); + } + CRYPTO_set_locking_callback((void (*)(int, int, const char *, int)) sslLockingCallback); + CRYPTO_set_id_callback(SSL_pthreads_thread_id); +} + +int +SSLNetProcessor::reconfigure(void) +{ + int ssl_mode = SslConfigParams::SSL_TERM_MODE_NONE, err = 0; + int sslServerEnabled = 0; + + cleanup(); + + if (!open_ssl_initialized) { + open_ssl_initialized = true; + SSL_load_error_strings(); + SSLeay_add_ssl_algorithms(); + initSSLLocks(); + } + + SslConfigParams *param = sslTerminationConfig.acquire(); + ink_assert(param); + + ssl_mode = param->getTerminationMode(); + sslServerEnabled = ssl_mode & SslConfigParams::SSL_TERM_MODE_CLIENT; + + if (sslServerEnabled) { + // Only init server stuff if SSL is enabled in the config file + err = initSSL(param); + if (err == 0) { + sslCertLookup.init(param); + } else { + logSSLError("Can't initialize the SSL library, disabling SSL termination!"); + sslTerminationConfig.clearTermEnabled(); + } + } + // Enable client regardless of config file setttings as remap file + // can cause HTTP layer to connect using SSL. But only if SSL + // initialization hasn't failed already. + if (err == 0) { + err = initSSLClient(param); + if (err != 0) + logSSLError("Can't initialize the SSL client, HTTPS in remap rules will not function"); + } + + sslTerminationConfig.release(param); + return (err); +} + +void +sslLockingCallback(int mode, int type, const char *file, int line) +{ + NOWARN_UNUSED(file); + (void) line; + if (mode & CRYPTO_LOCK) { + MUTEX_TAKE_LOCK(ssl_NetProcessor.sslMutexArray[type], this_ethread()); + } else if (mode & CRYPTO_UNLOCK) + MUTEX_UNTAKE_LOCK(ssl_NetProcessor.sslMutexArray[type], this_ethread()); + else + ink_debug_assert(0); +} + +unsigned long +SSL_pthreads_thread_id() +{ + EThread *eth = this_ethread(); + return (unsigned long) (eth->id); +} + + + + +void +SSLNetProcessor::logSSLError(const char *errStr, int critical) +{ + unsigned long l; + char buf[256]; + const char *file, *data; + int line, flags; + unsigned long es; + + if (!critical) { + if (errStr) { + Debug("ssl_error", "SSL ERROR: %s.", errStr); + } else { + Debug("ssl_error", "SSL ERROR."); + } + } else { + if (errStr) { + Error("SSL ERROR: %s.", errStr); + } else { + Error("SSL ERROR."); + } + } + + es = CRYPTO_thread_id(); + while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { + if (!critical) { + Debug("ssl_error", "SSL::%lu:%s:%s:%d:%s", es, + ERR_error_string(l, buf), file, line, (flags & ERR_TXT_STRING) ? data : ""); + } else { + Error("SSL::%lu:%s:%s:%d:%s", es, ERR_error_string(l, buf), file, line, (flags & ERR_TXT_STRING) ? data : ""); + } + } +} + +int +SSLNetProcessor::initSSL(SslConfigParams * param) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) // openssl returns a const SSL_METHOD now + const SSL_METHOD *meth = NULL; +#else + SSL_METHOD *meth = NULL; +#endif + // Note that we do not call RAND_seed() explicitly here, we depend on OpenSSL + // to do the seeding of the PRNG for us. This is the case for all platforms that + // has /dev/urandom for example. + + accept_port_number = param->ssl_accept_port_number; + if ((unsigned int) accept_port_number >= 0xFFFF) { + Error("\ncannot listen on port %d.\naccept port cannot be larger that 65535.\n" + "please check your Traffic Server configurations", accept_port_number); + return (1); + } + // these are not operating system specific calls and + // this ifdef needs to be removed when the openssl-engine + // library is built for NT. +#if !defined (_IOCORE_WIN32) + +#ifdef USE_OPENSSL_ENGINES + int engineType; + char *accelLibPath; + + ENGINE *accleratorEng; + + ENGINE_load_builtin_engines(); + engineType = param->sslAccelerator; + + if (engineType == SSL_NCIPHER_ACCEL) { + accelLibPath = param->ncipherAccelLibPath; + accleratorEng = ENGINE_by_id("chil"); + } else if (engineType == SSL_CSWIFT_ACCEL) { + accelLibPath = param->cswiftAccelLibPath; + accleratorEng = ENGINE_by_id("cswift"); + } else if (engineType == SSL_ATALLA_ACCEL) { + accelLibPath = param->cswiftAccelLibPath; + accleratorEng = ENGINE_by_id("atalla"); + } else if (engineType == SSL_BROADCOM_ACCEL) { + accelLibPath = param->broadcomAccelLibPath; + accleratorEng = ENGINE_by_id("ubsec"); + } else { + accelLibPath = NULL; + accleratorEng = ENGINE_by_id("dynamic"); + } + + if (accleratorEng == NULL) { + logSSLError("Cannot find SSL hardware accelerator library, SSL will operate without accelerator."); + return (-5); + } + + if (accelLibPath != NULL) { + // Removed, not sure what it does, or how... it's nowhere to be found in OpenSSL /leif. + // DSO_set_dl_path (accelLibPath); + } + + if (!ENGINE_set_default(accleratorEng, ENGINE_METHOD_ALL)) { + logSSLError("Cannot set SSL hardware accelerator card as default, SSL will operate without accelerator."); + logSSLError + ("Check records.config variable for SSL accelerator hardware library path in the SSL Termination section. "); + + // set software engine as default + ENGINE_set_default(ENGINE_by_id("openssl"), ENGINE_METHOD_ALL); + } + + ENGINE_free(accleratorEng); + +#endif // ! USE_OPENSSL_ENGINES + +#endif // !_IOCORE_WIN32 + + meth = SSLv23_server_method(); + ctx = SSL_CTX_new(meth); + if (!ctx) { + logSSLError("Cannot create new server contex."); + return (-1); + } + + return (initSSLServerCTX(param, ctx, param->serverCertPath, param->serverCertChainPath, param->serverKeyPath, true)); +} + +int +SSLNetProcessor::initSSLServerCTX(SslConfigParams * param, SSL_CTX * lCtx, + char *serverCertPtr, char *serverCaCertPtr, char *serverKeyPtr, bool defaultEnabled) +{ + int session_id_context; + int server_verify_client; + char *completeServerCertPath; + + // disable selected protocols + SSL_CTX_set_options(lCtx, param->ssl_ctx_options); + + switch (param->ssl_session_cache) { + case SslConfigParams::SSL_SESSION_CACHE_MODE_OFF: + SSL_CTX_set_session_cache_mode(lCtx, SSL_SESS_CACHE_OFF|SSL_SESS_CACHE_NO_INTERNAL); + break; + case SslConfigParams::SSL_SESSION_CACHE_MODE_SERVER: + SSL_CTX_set_session_cache_mode(lCtx, SSL_SESS_CACHE_SERVER); + SSL_CTX_sess_set_cache_size(lCtx, param->ssl_session_cache_size); + break; + } + + //might want to make configurable at some point. + verify_depth = param->verify_depth; + SSL_CTX_set_quiet_shutdown(lCtx, 1); + + if (defaultEnabled) { + if (SSL_CTX_use_certificate_file(lCtx, param->serverCertPath, SSL_FILETYPE_PEM) <= 0) { + Error ("SSL ERROR: Cannot use server certificate file: %s", param->serverCertPath); + return -2; + } + if (param->serverKeyPath != NULL) { + if (SSL_CTX_use_PrivateKey_file(lCtx, param->serverKeyPath, SSL_FILETYPE_PEM) <= 0) { + Error("SSL ERROR: Cannot use server private key file: %s", param->serverKeyPath); + return -3; + } + } else // assume key is contained in the cert file. + { + if (SSL_CTX_use_PrivateKey_file(lCtx, param->serverCertPath, SSL_FILETYPE_PEM) <= 0) { + Error("SSL ERROR: Cannot use server private key file: %s", param->serverKeyPath); + return -3; + } + } + + if (param->serverCertChainPath) { + char *completeServerCaCertPath = Layout::relative_to (param->getServerCACertPathOnly(), param->serverCertChainPath); + if (SSL_CTX_add_extra_chain_cert_file(lCtx, param->serverCertChainPath) <= 0) { + Error ("SSL ERROR: Cannot use server certificate chain file: %s", completeServerCaCertPath); + xfree(completeServerCaCertPath); + return -2; + } + xfree(completeServerCaCertPath); + } + } else { + completeServerCertPath = Layout::relative_to (param->getServerCertPathOnly(), serverCertPtr); + + if (SSL_CTX_use_certificate_file(lCtx, completeServerCertPath, SSL_FILETYPE_PEM) <= 0) { + Error ("SSL ERROR: Cannot use server certificate file: %s", completeServerCertPath); + xfree(completeServerCertPath); + return -2; + } + if (serverCaCertPtr) { + char *completeServerCaCertPath = Layout::relative_to (param->getServerCACertPathOnly(), serverCaCertPtr); + if (SSL_CTX_add_extra_chain_cert_file(lCtx, completeServerCaCertPath) <= 0) { + Error ("SSL ERROR: Cannot use server certificate chain file: %s", completeServerCaCertPath); + xfree(completeServerCaCertPath); + return -2; + } + xfree(completeServerCaCertPath); + } + + if (serverKeyPtr == NULL) // assume private key is contained in cert obtained from multicert file. + { + if (SSL_CTX_use_PrivateKey_file(lCtx, completeServerCertPath, SSL_FILETYPE_PEM) <= 0) { + Error("SSL ERROR: Cannot use server private key file: %s", completeServerCertPath); + xfree(completeServerCertPath); + return -3; + } + } else { + if (param->getServerKeyPathOnly() != NULL) { + char *completeServerKeyPath = Layout::get()->relative_to(param->getServerKeyPathOnly(), serverKeyPtr); + if (SSL_CTX_use_PrivateKey_file(lCtx, completeServerKeyPath, SSL_FILETYPE_PEM) <= 0) { + Error("SSL ERROR: Cannot use server private key file: %s", completeServerKeyPath); + xfree(completeServerKeyPath); + return -3; + } + xfree(completeServerKeyPath); + } else { + logSSLError("Empty ssl private key path in records.config."); + } + + } + xfree(completeServerCertPath); + + + } + + if (!SSL_CTX_check_private_key(lCtx)) { + logSSLError("Server private key does not match the certificate public key"); + return -4; + } + + + if (param->clientCertLevel != 0) { + + if (param->CACertFilename != NULL && param->CACertPath != NULL) { + if ((!SSL_CTX_load_verify_locations(lCtx, param->CACertFilename, param->CACertPath)) || + (!SSL_CTX_set_default_verify_paths(lCtx))) { + logSSLError("CA Certificate file or CA Certificate path invalid"); + return -5; + } + } + + if (param->clientCertLevel == 2) + server_verify_client = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE; + else if (param->clientCertLevel == 1) + server_verify_client = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; + else // disable client cert support + { + server_verify_client = SSL_VERIFY_NONE; + Error("Illegal Client Certification Level in records.config\n"); + } + + session_id_context = 1; + + SSL_CTX_set_verify(lCtx, server_verify_client, NULL); + SSL_CTX_set_verify_depth(lCtx, verify_depth); + SSL_CTX_set_session_id_context(lCtx, (const unsigned char *) &session_id_context, sizeof session_id_context); + + SSL_CTX_set_client_CA_list(lCtx, SSL_load_client_CA_file(param->CACertFilename)); + } + + + if (param->cipherSuite != NULL) { + if (!SSL_CTX_set_cipher_list(lCtx, param->cipherSuite)) { + logSSLError("Invalid Cipher Suite in records.config"); + return -6; + } + } + return 0; + +} + +int +SSLNetProcessor::initSSLClient(SslConfigParams * param) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) // openssl returns a const SSL_METHOD now + const SSL_METHOD *meth = NULL; +#else + SSL_METHOD *meth = NULL; +#endif + int client_verify_server; + char *clientKeyPtr = NULL; + + // Note that we do not call RAND_seed() explicitly here, we depend on OpenSSL + // to do the seeding of the PRNG for us. This is the case for all platforms that + // has /dev/urandom for example. + + client_verify_server = param->clientVerify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE; + meth = SSLv23_client_method(); + client_ctx = SSL_CTX_new(meth); + + // disable selected protocols + SSL_CTX_set_options(client_ctx, param->ssl_ctx_options); + verify_depth = param->client_verify_depth; + if (!client_ctx) { + logSSLError("Cannot create new client contex."); + return (-1); + } + // if no path is given for the client private key, + // assume it is contained in the client certificate file. + clientKeyPtr = param->clientKeyPath; + if (clientKeyPtr == NULL) + clientKeyPtr = param->clientCertPath; + + if (param->clientCertPath != 0) { + if (SSL_CTX_use_certificate_file(client_ctx, param->clientCertPath, SSL_FILETYPE_PEM) <= 0) { + logSSLError("Cannot use client certificate file"); + return (-2); + } + + if (SSL_CTX_use_PrivateKey_file(client_ctx, clientKeyPtr, SSL_FILETYPE_PEM) <= 0) { + logSSLError("Cannot use client private key file"); + return (-3); + } + + if (!SSL_CTX_check_private_key(client_ctx)) { + logSSLError("Client private key does not match the certificate public key"); + return (-4); + } + } + + if (param->clientVerify) { + SSL_CTX_set_verify(client_ctx, client_verify_server, NULL); + /*???*/ SSL_CTX_set_verify_depth(client_ctx, verify_depth); + // ??? + + if (param->clientCACertFilename != NULL && param->clientCACertPath != NULL) { + if ((!SSL_CTX_load_verify_locations(client_ctx, param->clientCACertFilename, + param->clientCACertPath)) || + (!SSL_CTX_set_default_verify_paths(client_ctx))) { + logSSLError("Client CA Certificate file or CA Certificate path invalid"); + return (-5); + } + } + } + return (0); +} diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc new file mode 100644 index 00000000..7630c60a --- /dev/null +++ b/iocore/net/SSLNetVConnection.cc @@ -0,0 +1,646 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +#include "ink_config.h" +#include "P_Net.h" + +#define SSL_READ_ERROR_NONE 0 +#define SSL_READ_ERROR 1 +#define SSL_READ_READY 2 +#define SSL_READ_COMPLETE 3 +#define SSL_READ_WOULD_BLOCK 4 +#define SSL_READ_EOS 5 +#define SSL_HANDSHAKE_WANT_READ 6 +#define SSL_HANDSHAKE_WANT_WRITE 7 +#define SSL_HANDSHAKE_WANT_ACCEPT 8 +#define SSL_HANDSHAKE_WANT_CONNECT 9 +#define SSL_WRITE_WOULD_BLOCK 10 +ClassAllocator sslNetVCAllocator("sslNetVCAllocator"); + + +// +// Private +// + +static inline int +do_SSL_write(SSL * ssl, void *buf, int size) +{ + int r = 0; + do { + // need to check into SSL error handling + // to see if this is good enough. + r = SSL_write(ssl, (const char *) buf, size); + if (r >= 0) + return r; + else + r = -errno; + } while (r == -EINTR || r == -ENOBUFS || r == -ENOMEM); + + return r; +} + + +static int +ssl_read_from_net(NetHandler * nh, UnixNetVConnection * vc, EThread * lthread, int64_t &ret) +{ + NOWARN_UNUSED(nh); + NetState *s = &vc->read; + SSLNetVConnection *sslvc = (SSLNetVConnection *) vc; + MIOBufferAccessor & buf = s->vio.buffer; + IOBufferBlock *b = buf.mbuf->_writer; + int event = SSL_READ_ERROR_NONE; + int64_t bytes_read; + int64_t block_write_avail; + int sslErr = SSL_ERROR_NONE; + + for (bytes_read = 0; (b != 0) && (sslErr == SSL_ERROR_NONE); b = b->next) { + block_write_avail = b->write_avail(); + + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] b->write_avail()=%d", block_write_avail); + + int64_t offset = 0; + // while can be replaced with if - need to test what works faster with openssl + while (block_write_avail > 0) { + sslvc->read_calls++; + int rres = SSL_read(sslvc->ssl, b->end() + offset, (int)block_write_avail); + + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] rres=%d", rres); + + sslErr = SSL_get_error(sslvc->ssl, rres); + switch (sslErr) { + case SSL_ERROR_NONE: + + DebugBufferPrint("ssl_buff", b->end() + offset, rres, "SSL Read"); + ink_debug_assert(rres); + + bytes_read += rres; + offset += rres; + block_write_avail -= rres; + ink_debug_assert(block_write_avail >= 0); + + continue; + + case SSL_ERROR_WANT_WRITE: + event = SSL_WRITE_WOULD_BLOCK; + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_WOULD_BLOCK(write)"); + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + event = SSL_READ_WOULD_BLOCK; + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_WOULD_BLOCK(read)"); + break; + case SSL_ERROR_SYSCALL: + if (rres != 0) { + // not EOF + event = SSL_READ_ERROR; + ret = errno; + Error("[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_SYSCALL, underlying IO error: %s", strerror(errno)); + } else { + // then EOF observed, treat it as EOS + event = SSL_READ_EOS; + //Error("[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_SYSCALL, EOF observed violating SSL protocol"); + } + break; + case SSL_ERROR_ZERO_RETURN: + event = SSL_READ_EOS; + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_ZERO_RETURN"); + break; + case SSL_ERROR_SSL: + default: { + char err_string[4096]; + ERR_error_string(ERR_get_error(), err_string); + event = SSL_READ_ERROR; + ret = errno; + Error("[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_SSL %s", err_string); + break; + } + } // switch + break; + } // while( block_write_avail > 0 ) + } // for ( bytes_read = 0; (b != 0); b = b->next) + + if (bytes_read > 0) { + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] bytes_read=%d", bytes_read); + buf.writer()->fill(bytes_read); + s->vio.ndone += bytes_read; + vc->netActivity(lthread); + + ret = bytes_read; + + if (s->vio.ntodo() <= 0) { + event = SSL_READ_COMPLETE; + } else { + event = SSL_READ_READY; + } + } else // if( bytes_read > 0 ) + { +#if defined (_DEBUG) + if (bytes_read == 0) { + Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] bytes_read == 0"); + } +#endif + } + return (event); + +} + + +//changed by YTS Team, yamsat +void +SSLNetVConnection::net_read_io(NetHandler * nh, EThread * lthread) +{ + int ret; + int64_t r = 0; + int64_t bytes = 0; + NetState *s = &this->read; + MIOBufferAccessor & buf = s->vio.buffer; + MUTEX_TRY_LOCK_FOR(lock, s->vio.mutex, lthread, s->vio._cont); + if (!lock) { + readReschedule(nh); + return; + } + // If it is not enabled, lower its priority. This allows + // a fast connection to speed match a slower connection by + // shifting down in priority even if it could read. + if (!s->enabled || s->vio.op != VIO::READ) { + read_disable(nh, this); + return; + } + + ink_debug_assert(buf.writer()); + + // This function will always return true unless + // vc is an SSLNetVConnection. + if (!getSSLHandShakeComplete()) { + int err; + + if (getSSLClientConnection()) { + ret = sslStartHandShake(SSL_EVENT_CLIENT, err); + } else { + ret = sslStartHandShake(SSL_EVENT_SERVER, err); + } + + if (ret == EVENT_ERROR) { + this->read.triggered = 0; + readSignalError(nh, err); + } else if (ret == SSL_HANDSHAKE_WANT_READ || ret == SSL_HANDSHAKE_WANT_ACCEPT) { + read.triggered = 0; + nh->read_ready_list.remove(this); + readReschedule(nh); + } else if (ret == SSL_HANDSHAKE_WANT_CONNECT || ret == SSL_HANDSHAKE_WANT_WRITE) { + write.triggered = 0; + nh->write_ready_list.remove(this); + writeReschedule(nh); + } else if (ret == EVENT_DONE) { + read.triggered = 1; + if (read.enabled) + nh->read_ready_list.in_or_enqueue(this); + } else + readReschedule(nh); + return; + } + // If there is nothing to do, disable connection + int64_t ntodo = s->vio.ntodo(); + if (ntodo <= 0) { + read_disable(nh, this); + return; + } + + do { + if (!buf.writer()->write_avail()) { + buf.writer()->add_block(); + } + ret = ssl_read_from_net(nh, this, lthread, r); + if (ret == SSL_READ_READY || ret == SSL_READ_ERROR_NONE) { + bytes += r; + } + + } while (ret == SSL_READ_READY || ret == SSL_READ_ERROR_NONE); + + if (bytes > 0) { + if (ret == SSL_READ_WOULD_BLOCK) { + if (readSignalAndUpdate(VC_EVENT_READ_READY) != EVENT_CONT) { + Debug("ssl", "ssl_read_from_net, readSignal !=EVENT_CONT"); + return; + } + } + } + + switch (ret) { + case SSL_READ_ERROR_NONE: + case SSL_READ_READY: + // how did we exit the while loop above? should never happen. + ink_debug_assert(false); + break; + case SSL_WRITE_WOULD_BLOCK: + case SSL_READ_WOULD_BLOCK: + if (lock.m.m_ptr != s->vio.mutex.m_ptr) { + Debug("ssl", "ssl_read_from_net, mutex switched"); + if(ret == SSL_READ_WOULD_BLOCK) readReschedule(nh); + else writeReschedule(nh); + return; + } + // reset the tigger and remove from the ready queue + // we will need to be retriggered to read from this socket again + read.triggered = 0; + nh->read_ready_list.remove(this); + Debug("ssl", "read_from_net, read finished - would block"); +#ifdef TS_USE_PORT + if(ret == SSL_READ_WOULD_BLOCK) readReschedule(nh); + else writeReschedule(nh); +#endif + break; + + case SSL_READ_EOS: + // close the connection if we have SSL_READ_EOS, this is the return value from ssl_read_from_net() if we get an SSL_ERROR_ZERO_RETURN from SSL_get_error() + // SSL_ERROR_ZERO_RETURN means that the origin server closed the SSL connection + read.triggered = 0; + readSignalDone(VC_EVENT_EOS, nh); + + if (bytes > 0) { + Debug("ssl", "read_from_net, read finished - EOS"); + } else { + Debug("ssl", "read_from_net, read finished - 0 useful bytes read, bytes used by SSL layer"); + } + break; + case SSL_READ_COMPLETE: + readSignalDone(VC_EVENT_READ_COMPLETE, nh); + Debug("ssl", "read_from_net, read finished - signal done"); + break; + case SSL_READ_ERROR: + this->read.triggered = 0; + readSignalError(nh, (int)r); + Debug("ssl", "read_from_net, read finished - read error"); + break; + } + +} + + +int64_t +SSLNetVConnection::load_buffer_and_write(int64_t towrite, int64_t &wattempted, int64_t &total_wrote, MIOBufferAccessor & buf) { + ProxyMutex *mutex = this_ethread()->mutex; + int64_t r = 0; + int64_t l = 0; + int64_t offset = buf.entry->start_offset; + IOBufferBlock *b = buf.entry->block; + + do { + // check if we have done this block + l = b->read_avail(); + l -= offset; + if (l <= 0) { + offset = -l; + b = b->next; + continue; + } + // check if to amount to write exceeds that in this buffer + int64_t wavail = towrite - total_wrote; + + if (l > wavail) + l = wavail; + if (!l) + break; + wattempted = l; + total_wrote += l; + Debug("ssl", "SSLNetVConnection::loadBufferAndCallWrite, before do_SSL_write, l = %d, towrite = %d, b = %x", l, + towrite, b); + write_calls++; + r = do_SSL_write(ssl, b->start() + offset, (int)l); + if (r == l) { + wattempted = total_wrote; + } + // on to the next block + offset = 0; + b = b->next; + Debug("ssl", "SSLNetVConnection::loadBufferAndCallWrite,Number of bytes written =%d , total =%d", r, total_wrote); + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_write_stat, 1); + } while (r == l && total_wrote < towrite && b); + if (r > 0) { + if (total_wrote != wattempted) { + Debug("ssl", "SSLNetVConnection::loadBufferAndCallWrite, wrote some bytes, but not all requested."); + return (r); + } else { + Debug("ssl", "SSLNetVConnection::loadBufferAndCallWrite, write successful."); + return (total_wrote); + } + } else { + int err = SSL_get_error(ssl, (int)r); + + switch (err) { + case SSL_ERROR_NONE: + Debug("ssl", "SSL_write-SSL_ERROR_NONE"); + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + r = -EAGAIN; + Debug("ssl", "SSL_write-SSL_ERROR_WANT_WRITE"); + break; + case SSL_ERROR_SYSCALL: + r = -errno; + Debug("ssl", "SSL_write-SSL_ERROR_SYSCALL"); + break; + // end of stream + case SSL_ERROR_ZERO_RETURN: + r = -errno; + Debug("ssl", "SSL_write-SSL_ERROR_ZERO_RETURN"); + break; + case SSL_ERROR_SSL: + default: + r = -errno; + Debug("ssl", "SSL_write-SSL_ERROR_SSL"); + SSLNetProcessor::logSSLError("SSL_write"); + break; + } + return (r); + } +} + +SSLNetVConnection::SSLNetVConnection(): + connect_calls(0), + connect_want_write(0), + connect_want_read(0), + connect_want_connect(0), + connect_want_ssl(0), + connect_want_syscal(0), + connect_want_accept(0), + connect_want_x509(0), + connect_error_zero(0), + accept_calls(0), + read_calls(0), + read_want_write(0), + read_want_read(0), + read_want_ssl(0), + read_want_syscal(0), + read_want_x509(0), + read_error_zero(0), + write_calls(0), + write_want_write(0), + write_want_read(0), + write_want_ssl(0), + write_want_syscal(0), write_want_x509(0), write_error_zero(0), sslHandShakeComplete(false), sslClientConnection(false) +{ + ssl = NULL; +} + +void +SSLNetVConnection::free(EThread * t) { + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, -1); + got_remote_addr = 0; + got_local_addr = 0; + read.vio.mutex.clear(); + write.vio.mutex.clear(); + action_.mutex.clear(); + this->mutex.clear(); + flags = 0; + SET_CONTINUATION_HANDLER(this, (SSLNetVConnHandler) & SSLNetVConnection::startEvent); + nh = NULL; + read.triggered = 0; + write.triggered = 0; + options.reset(); + closed = 0; + ink_assert(con.fd == NO_FD); + read_calls = 0; + write_calls = 0; + connect_calls = 0; + accept_calls = 0; + connect_want_write = 0; + connect_want_read = 0; + connect_want_connect = 0; + connect_want_ssl = 0; + connect_want_syscal = 0; + connect_want_accept = 0; + connect_want_x509 = 0; + connect_error_zero = 0; + read_want_write = 0; + read_want_read = 0; + read_want_ssl = 0; + read_want_syscal = 0; + read_want_x509 = 0; + read_error_zero = 0; + write_want_write = 0; + write_want_read = 0; + write_want_ssl = 0; + write_want_syscal = 0; + write_want_x509 = 0; + write_error_zero = 0; + if (ssl != NULL) { + /*if (sslHandShakeComplete) + SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); */ + SSL_free(ssl); + ssl = NULL; + } + sslHandShakeComplete = 0; + sslClientConnection = 0; + + if (from_accept_thread) { + sslNetVCAllocator.free(this); + } else { + THREAD_FREE(this, sslNetVCAllocator, t); + } +} + +int +SSLNetVConnection::sslStartHandShake(int event, int &err) +{ + SSL_CTX *ctx = NULL; + struct sockaddr_in sa; + struct in_addr ia; + int namelen = sizeof(sa); + char *strAddr; + + if (event == SSL_EVENT_SERVER) { + if (ssl == NULL) { + if (sslCertLookup.multipleCerts) { + safe_getsockname(get_socket(), (struct sockaddr *) &sa, &namelen); + ia.s_addr = sa.sin_addr.s_addr; + strAddr = inet_ntoa(ia); + ctx = sslCertLookup.findInfoInHash(strAddr); + if (ctx == NULL) + ctx = ssl_NetProcessor.ctx; + } else { + ctx = ssl_NetProcessor.ctx; + } + ssl = SSL_new(ctx); + if (ssl != NULL) { + SSL_set_fd(ssl, get_socket()); + } else { + Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, ssl create failed"); + } + + } + return (sslServerHandShakeEvent(err)); + } else { + if (ssl == NULL) { + ssl = SSL_new(ssl_NetProcessor.client_ctx); + SSL_set_fd(ssl, get_socket()); + } + ink_assert(event == SSL_EVENT_CLIENT); + return (sslClientHandShakeEvent(err)); + } + +} + +int +SSLNetVConnection::sslServerHandShakeEvent(int &err) +{ + int ret; + + accept_calls++; + //printf("calling SSL_accept for fd %d\n",con.fd); + ret = SSL_accept(ssl); + + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_NONE: + Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, handshake completed successfully"); + client_cert = SSL_get_peer_certificate(ssl); + if (client_cert != NULL) { +/* str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0); + Free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0); + Free (str); + + // Add any extra client cert verification stuff here. SSL + // is set up in SSLNetProcessor::start to automatically verify + // the client cert's CA, if required. +*/ + X509_free(client_cert); + } + sslHandShakeComplete = 1; + + return EVENT_DONE; + + case SSL_ERROR_WANT_ACCEPT: + break; + + case SSL_ERROR_WANT_CONNECT: + return SSL_HANDSHAKE_WANT_CONNECT; + + case SSL_ERROR_WANT_WRITE: + return SSL_HANDSHAKE_WANT_WRITE; + + case SSL_ERROR_WANT_READ: + return SSL_HANDSHAKE_WANT_READ; + case SSL_ERROR_WANT_X509_LOOKUP: + Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, would block on read or write"); + break; + + case SSL_ERROR_ZERO_RETURN: + Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, EOS"); + return EVENT_ERROR; + break; + + case SSL_ERROR_SYSCALL: + err = errno; + Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, syscall"); + return EVENT_ERROR; + break; + + case SSL_ERROR_SSL: + default: + err = errno; + Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, error"); + SSLNetProcessor::logSSLError("SSL_ServerHandShake"); + return EVENT_ERROR; + break; + } + return EVENT_CONT; +} + + +int +SSLNetVConnection::sslClientHandShakeEvent(int &err) +{ + int ret; + + connect_calls++; + //printf("calling connect for fd %d\n",con.fd); + ret = SSL_connect(ssl); + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_NONE: + Debug("ssl", "SSLNetVConnection::sslClientHandShakeEvent, handshake completed successfully"); + server_cert = SSL_get_peer_certificate(ssl); + +/* str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0); + Free (str); + + str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0); + Free (str); +*/ + +/* Add certificate verification stuff here before + deallocating the certificate. +*/ + + X509_free(server_cert); + sslHandShakeComplete = 1; + + return EVENT_DONE; + + case SSL_ERROR_WANT_WRITE: + connect_want_write++; + return SSL_HANDSHAKE_WANT_WRITE; + + case SSL_ERROR_WANT_READ: + connect_want_read++; + return SSL_HANDSHAKE_WANT_READ; + + case SSL_ERROR_WANT_X509_LOOKUP: + connect_want_x509++; + Debug("ssl", "SSLNetVConnection::sslClientHandShakeEvent, would block on read or write"); + break; + + case SSL_ERROR_WANT_ACCEPT: + connect_want_accept++; + return SSL_HANDSHAKE_WANT_ACCEPT; + + case SSL_ERROR_WANT_CONNECT: + connect_want_connect++; + break; + + case SSL_ERROR_ZERO_RETURN: + connect_error_zero++; + Debug("ssl", "SSLNetVConnection::sslClientHandShakeEvent, EOS"); + return EVENT_ERROR; + + case SSL_ERROR_SYSCALL: + connect_want_syscal++; + err = errno; + Debug("ssl", "SSLNetVConnection::sslClientHandShakeEvent, syscall"); + return EVENT_ERROR; + break; + + + case SSL_ERROR_SSL: + default: + connect_want_ssl++; + err = errno; + SSLNetProcessor::logSSLError("sslClientHandShakeEvent"); + return EVENT_ERROR; + break; + + } + return EVENT_CONT; + +} diff --git a/iocore/net/SSLUnixNet.cc b/iocore/net/SSLUnixNet.cc new file mode 100644 index 00000000..45617342 --- /dev/null +++ b/iocore/net/SSLUnixNet.cc @@ -0,0 +1,166 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + /**************************************************************************** + + SSLUnixNet.h + + This file implements an I/O Processor for network I/O for Unix. + Contains additions for handling port pairs for RTSP/RTP. + + + ****************************************************************************/ +#include "ink_config.h" + +#include "P_Net.h" +// +// Global Data +// + +SSLNetProcessor ssl_NetProcessor; +NetProcessor & sslNetProcessor = ssl_NetProcessor; + +EventType ET_SSL; + +typedef int (SSLNetAccept::*SSLNetAcceptHandler) (int, void *); + + +int +SSLNetProcessor::start(int number_of_ssl_threads) +{ + sslTerminationConfig.startup(); + int err = reconfigure(); + + if (err != 0) { + return -1; + } + + if (number_of_ssl_threads < 1) + return -1; + + ET_SSL = eventProcessor.spawn_event_threads(number_of_ssl_threads, "ET_SSL"); + if (err == 0) + err = UnixNetProcessor::start(); + return err; +} + + +NetAccept * +SSLNetProcessor::createNetAccept() +{ + return ((NetAccept *) NEW(new SSLNetAccept)); +} + +// Virtual function allows etype to be upgraded to ET_SSL for SSLNetProcessor. Does +// nothing for NetProcessor +void +SSLNetProcessor::upgradeEtype(EventType & etype) +{ + if (etype == ET_NET) { + etype = ET_SSL; + } +} + +// Virtual function allows the correct +// etype to be used in NetAccept functions (ET_SSL +// or ET_NET). +EventType +SSLNetAccept::getEtype() +{ + return ET_SSL; +} + +// Functions all THREAD_FREE and THREAD_ALLOC to be performed +// for both SSL and regular NetVConnection transparent to +// accept functions. +UnixNetVConnection * +SSLNetAccept::allocateThread(EThread *t) +{ + return ((UnixNetVConnection *) THREAD_ALLOC(sslNetVCAllocator, t)); +} + +void +SSLNetAccept::freeThread(UnixNetVConnection *vc, EThread *t) +{ + ink_assert(!vc->from_accept_thread); + THREAD_FREE((SSLNetVConnection *) vc, sslNetVCAllocator, t); +} + +// This allocates directly on the class allocator, used for accept threads. +UnixNetVConnection * +SSLNetAccept::allocateGlobal() +{ + return (UnixNetVConnection *)sslNetVCAllocator.alloc(); +} + +// Functions all THREAD_FREE and THREAD_ALLOC to be performed +// for both SSL and regular NetVConnection transparent to +// netProcessor connect functions. Yes it looks goofy to +// have them in both places, but it saves a bunch of +// connect code from being duplicated. +UnixNetVConnection * +SSLNetProcessor::allocateThread(EThread *t) +{ + return ((UnixNetVConnection *) THREAD_ALLOC(sslNetVCAllocator, t)); +} + +void +SSLNetProcessor::freeThread(UnixNetVConnection *vc, EThread *t) +{ + ink_assert(!vc->from_accept_thread); + THREAD_FREE((SSLNetVConnection *) vc, sslNetVCAllocator, t); +} + +void +SSLNetAccept::init_accept_per_thread() +{ + int i, n; + if (do_listen(NON_BLOCKING)) + return; + if (accept_fn == net_accept) + SET_HANDLER((SSLNetAcceptHandler) & SSLNetAccept::acceptFastEvent); + else + SET_HANDLER((SSLNetAcceptHandler) & SSLNetAccept::acceptEvent); + period = ACCEPT_PERIOD; + NetAccept *a = this; + n = eventProcessor.n_threads_for_type[ET_SSL]; + for (i = 0; i < n; i++) { + if (i < n - 1) { + a = NEW(new SSLNetAccept); + *a = *this; + } else + a = this; + EThread *t = eventProcessor.eventthread[ET_SSL][i]; + + PollDescriptor *pd = get_PollDescriptor(t); + if (ep.start(pd, this, EVENTIO_READ) < 0) + Debug("iocore_net", "error starting EventIO"); + a->mutex = get_NetHandler(t)->mutex; + t->schedule_every(a, period, etype); + } +} + +SSLNetProcessor::~SSLNetProcessor() +{ + cleanup(); +} diff --git a/iocore/net/Socks.cc b/iocore/net/Socks.cc new file mode 100644 index 00000000..cd029c3a --- /dev/null +++ b/iocore/net/Socks.cc @@ -0,0 +1,699 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + Socks.cc + + + + This file contains the Socks client functionality. Previously this code was + duplicated in UnixNet.cc and NTNetProcessor.cc +*/ + +#include "P_Net.h" +#include "I_Layout.h" + +socks_conf_struct *g_socks_conf_stuff = 0; + +ClassAllocator socksAllocator("socksAllocator"); + +void +SocksEntry::init(ProxyMutex * m, SocksNetVC * vc, unsigned char socks_support, unsigned char ver) +{ + mutex = m; + buf = new_MIOBuffer(); + reader = buf->alloc_reader(); + + socks_cmd = socks_support; + + if (ver == SOCKS_DEFAULT_VERSION) + version = netProcessor.socks_conf_stuff->default_version; + else + version = ver; + + SET_HANDLER(&SocksEntry::startEvent); + + ip = vc->ip; + port = vc->port; + +#ifdef SOCKS_WITH_TS + req_data.hdr = 0; + req_data.hostname_str = 0; + req_data.api_info = 0; + req_data.xact_start = time(0); + req_data.dest_ip = ip; + + //we dont have information about the source. set to destination's + req_data.src_ip = ip; + req_data.incoming_port = port; + + server_params = SocksServerConfig::acquire(); +#endif + + nattempts = 0; + findServer(); + + timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->server_connect_timeout)); + write_done = false; +} + +void +SocksEntry::findServer() +{ + nattempts++; + +#ifdef SOCKS_WITH_TS + if (nattempts == 1) { + ink_debug_assert(server_result.r == PARENT_UNDEFINED); + server_params->findParent(&req_data, &server_result); + } else { + + socks_conf_struct *conf = netProcessor.socks_conf_stuff; + if ((nattempts - 1) % conf->per_server_connection_attempts) + return; //attempt again + + server_params->markParentDown(&server_result); + + if (nattempts > conf->connection_attempts) + server_result.r = PARENT_FAIL; + else + server_params->nextParent(&req_data, &server_result); + } + + switch (server_result.r) { + case PARENT_SPECIFIED: + server_ip = inet_addr(server_result.hostname); + server_port = server_result.port; + break; + + default: + ink_debug_assert(!"Unexpected event"); + case PARENT_DIRECT: + case PARENT_FAIL: + server_ip = (unsigned int) -1; + } +#else + server_ip = (nattempts > netProcessor.socks_conf_stuff->connection_attempts) + ? (unsigned int) -1 : g_socks_conf_stuff->socks_server; + server_port = g_socks_conf_stuff->socks_server_port; +#endif // SOCKS_WITH_TS + + Debug("SocksParents", "findServer result: %u.%u.%u.%u:%d", PRINT_IP(server_ip), server_port); +} + +void +SocksEntry::free() +{ + MUTEX_TRY_LOCK(lock, action_.mutex, this_ethread()); + if (!lock) { + // Socks continuation share the user's lock + // so acquiring a lock shouldn't fail + ink_debug_assert(0); + return; + } + + if (timeout) + timeout->cancel(this); + +#ifdef SOCKS_WITH_TS + if (!lerrno && netVConnection && server_result.retry) + server_params->recordRetrySuccess(&server_result); +#endif + + if ((action_.cancelled || lerrno) && netVConnection) + netVConnection->do_io_close(); + + if (!action_.cancelled) { + if (lerrno) { + Debug("Socks", "retryevent: Sent errno %d to HTTP", lerrno); + NET_INCREMENT_DYN_STAT(socks_connections_unsuccessful_stat); + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *)(intptr_t)(-lerrno)); + } else { + netVConnection->do_io_read(this, 0, 0); + netVConnection->do_io_write(this, 0, 0); + netVConnection->action_ = action_; //assign the original continuation + netVConnection->ip = ip; + netVConnection->port = port; // we already have the lock for the continuation + Debug("Socks", "Sent success to HTTP"); + NET_INCREMENT_DYN_STAT(socks_connections_successful_stat); + action_.continuation->handleEvent(NET_EVENT_OPEN, netVConnection); + } + } +#ifdef SOCKS_WITH_TS + SocksServerConfig::release(server_params); +#endif + + free_MIOBuffer(buf); + action_ = NULL; + mutex = NULL; + socksAllocator.free(this); +} + +int +SocksEntry::startEvent(int event, void *data) +{ + if (event == NET_EVENT_OPEN) { + netVConnection = (SocksNetVC *) data; + + if (version == SOCKS5_VERSION) + auth_handler = &socks5BasicAuthHandler; + + SET_HANDLER((SocksEntryHandler) & SocksEntry::mainEvent); + mainEvent(NET_EVENT_OPEN, data); + } else { + if (timeout) { + timeout->cancel(this); + timeout = NULL; + } + + Debug("Socks", "Failed to connect to %u.%u.%u.%u:%d", PRINT_IP(server_ip), server_port); + + findServer(); + + if (server_ip == (uint32_t) - 1) { + Debug("Socks", "Unable to open connection to the SOCKS server"); + lerrno = ESOCK_NO_SOCK_SERVER_CONN; + free(); + return EVENT_CONT; + } + + if (timeout) { + timeout->cancel(this); + timeout = 0; + } + + if (netVConnection) { + netVConnection->do_io_close(); + netVConnection = 0; + } + + timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->server_connect_timeout)); + + write_done = false; + + NetVCOptions options; + options.socks_support = NO_SOCKS; + netProcessor.connect_re(this, server_ip, server_port, &options); + } + + return EVENT_CONT; +} + +int +SocksEntry::mainEvent(int event, void *data) +{ + int ret = EVENT_DONE; + int n_bytes = 0; + unsigned char *p; + + switch (event) { + + case NET_EVENT_OPEN: + buf->reset(); + unsigned short ts; + p = (unsigned char *) buf->start(); + ink_debug_assert(netVConnection); + + if (auth_handler) { + n_bytes = invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_OPEN, p); + } else { + + //Debug("Socks", " Got NET_EVENT_OPEN to SOCKS server\n"); + + p[n_bytes++] = version; + p[n_bytes++] = (socks_cmd == NORMAL_SOCKS) ? SOCKS_CONNECT : socks_cmd; + ts = (unsigned short) htons(port); + + if (version == SOCKS5_VERSION) { + p[n_bytes++] = 0; //Reserved + p[n_bytes++] = 1; //IPv4 addr + p[n_bytes++] = ((unsigned char *) &ip)[0]; + p[n_bytes++] = ((unsigned char *) &ip)[1]; + p[n_bytes++] = ((unsigned char *) &ip)[2]; + p[n_bytes++] = ((unsigned char *) &ip)[3]; + } + + p[n_bytes++] = ((unsigned char *) &ts)[0]; + p[n_bytes++] = ((unsigned char *) &ts)[1]; + + if (version == SOCKS4_VERSION) { + //for socks4, ip addr is after the port + p[n_bytes++] = ((unsigned char *) &ip)[0]; + p[n_bytes++] = ((unsigned char *) &ip)[1]; + p[n_bytes++] = ((unsigned char *) &ip)[2]; + p[n_bytes++] = ((unsigned char *) &ip)[3]; + + p[n_bytes++] = 0; // NULL + } + + } + + buf->fill(n_bytes); + + if (!timeout) { + /* timeout would be already set when we come here from StartEvent() */ + timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout)); + } + + netVConnection->do_io_write(this, n_bytes, reader, 0); + //Debug("Socks", "Sent the request to the SOCKS server\n"); + + ret = EVENT_CONT; + break; + + case VC_EVENT_WRITE_READY: + + ret = EVENT_CONT; + break; + + case VC_EVENT_WRITE_COMPLETE: + if (timeout) { + timeout->cancel(this); + timeout = NULL; + write_done = true; + } + + buf->reset(); // Use the same buffer for a read now + + if (auth_handler) + n_bytes = invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_WRITE_COMPLETE, NULL); + else if (socks_cmd == NORMAL_SOCKS) + n_bytes = (version == SOCKS5_VERSION) + ? SOCKS5_REP_LEN : SOCKS4_REP_LEN; + else { + Debug("Socks", "Tunnelling the connection"); + //let the client handle the response + free(); + break; + } + + timeout = this_ethread()->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout)); + + netVConnection->do_io_read(this, n_bytes, buf); + + ret = EVENT_DONE; + break; + + case VC_EVENT_READ_READY: + ret = EVENT_CONT; + + if (version == SOCKS5_VERSION && auth_handler == NULL) { + VIO *vio = (VIO *) data; + p = (unsigned char *) buf->start(); + + if (vio->ndone >= 5) { + int reply_len; + + switch (p[3]) { + case SOCKS_ATYPE_IPV4: + reply_len = 10; + break; + case SOCKS_ATYPE_FQHN: + reply_len = 7 + p[4]; + break; + case SOCKS_ATYPE_IPV6: + Debug("Socks", "Who is using IPv6 Addr?"); + reply_len = 22; + break; + default: + reply_len = INT_MAX; + Debug("Socks", "Illegal address type(%d) in Socks server", (int) p[3]); + } + + if (vio->ndone >= reply_len) { + vio->nbytes = vio->ndone; + ret = EVENT_DONE; + } + } + } + + if (ret == EVENT_CONT) + break; + // Fall Through + case VC_EVENT_READ_COMPLETE: + if (timeout) { + timeout->cancel(this); + timeout = NULL; + } + //Debug("Socks", "Successfully read the reply from the SOCKS server\n"); + p = (unsigned char *) buf->start(); + + if (auth_handler) { + SocksAuthHandler temp = auth_handler; + + if (invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_READ_COMPLETE, p) < 0) { + lerrno = ESOCK_DENIED; + free(); + } else if (auth_handler != temp) { + // here either authorization is done or there is another + // stage left. + mainEvent(NET_EVENT_OPEN, NULL); + } + + } else { + + bool success; + if (version == SOCKS5_VERSION) { + success = (p[0] == SOCKS5_VERSION && p[1] == SOCKS5_REQ_GRANTED); + Debug("Socks", "received reply of length %d addr type %d", ((VIO *) data)->ndone, (int) p[3]); + } else + success = (p[0] == 0 && p[1] == SOCKS4_REQ_GRANTED); + + //ink_debug_assert(*(p) == 0); + if (!success) { // SOCKS request failed + Debug("Socks", "Socks request denied %d", (int) *(p + 1)); + lerrno = ESOCK_DENIED; + } else { + Debug("Socks", "Socks request successful %d", (int) *(p + 1)); + lerrno = 0; + } + free(); + } + + break; + + case EVENT_INTERVAL: + timeout = NULL; + if (write_done) { + lerrno = ESOCK_TIMEOUT; + free(); + break; + } + /* else + This is server_connect_timeout. So we treat this as server being + down. + Should cancel any pending connect() action. Important on windows + + fall through + */ + case VC_EVENT_ERROR: + /*This is mostly ECONNREFUSED on Unix */ + SET_HANDLER(&SocksEntry::startEvent); + startEvent(NET_EVENT_OPEN_FAILED, NULL); + break; + + case VC_EVENT_EOS: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + Debug("Socks", "VC_EVENT error: %s", get_vc_event_name(event)); + lerrno = ESOCK_NO_SOCK_SERVER_CONN; + free(); + break; + default: + // BUGBUG:: could be active/inactivity timeout ... + ink_debug_assert(!"bad case value"); + Debug("Socks", "Bad Case/Net Error Event"); + lerrno = ESOCK_NO_SOCK_SERVER_CONN; + free(); + break; + } + + return ret; +} + +void +loadSocksConfiguration(socks_conf_struct * socks_conf_stuff) +{ + int socks_config_fd = -1; + char config_pathname[PATH_NAME_MAX + 1]; + char *socks_config_file = NULL; +#ifdef SOCKS_WITH_TS + char *tmp; +#endif + + socks_conf_stuff->accept_enabled = 0; //initialize it INKqa08593 + socks_conf_stuff->socks_needed = IOCORE_ConfigReadInteger("proxy.config.socks.socks_needed"); + if (!socks_conf_stuff->socks_needed) { + Debug("Socks", "Socks Turned Off"); + return; + } + + socks_conf_stuff->default_version = IOCORE_ConfigReadInteger("proxy.config.socks.socks_version"); + Debug("Socks", "Socks Version %d", socks_conf_stuff->default_version); + + if (socks_conf_stuff->default_version != 4 && socks_conf_stuff->default_version != 5) { + Error("SOCKS Config: Unsupported Version: %d. SOCKS Turned off", socks_conf_stuff->default_version); + goto error; + } + + socks_conf_stuff->server_connect_timeout = IOCORE_ConfigReadInteger("proxy.config.socks.server_connect_timeout"); + socks_conf_stuff->socks_timeout = IOCORE_ConfigReadInteger("proxy.config.socks.socks_timeout"); + Debug("Socks", "server connect timeout: %d socks respnonse timeout %d", + socks_conf_stuff->server_connect_timeout, socks_conf_stuff->socks_timeout); + + socks_conf_stuff->per_server_connection_attempts = + IOCORE_ConfigReadInteger("proxy.config.socks.per_server_connection_attempts"); + socks_conf_stuff->connection_attempts = IOCORE_ConfigReadInteger("proxy.config.socks.connection_attempts"); + + socks_conf_stuff->accept_enabled = IOCORE_ConfigReadInteger("proxy.config.socks.accept_enabled"); + socks_conf_stuff->accept_port = IOCORE_ConfigReadInteger("proxy.config.socks.accept_port"); + socks_conf_stuff->http_port = IOCORE_ConfigReadInteger("proxy.config.socks.http_port"); + Debug("SocksProxy", "Read SocksProxy info: accept_enabled = %d " + "accept_port = %d http_port = %d", socks_conf_stuff->accept_enabled, + socks_conf_stuff->accept_port, socks_conf_stuff->http_port); + +#ifdef SOCKS_WITH_TS + SocksServerConfig::startup(); +#endif + + socks_config_file = IOCORE_ConfigReadString("proxy.config.socks.socks_config_file"); + + if (!socks_config_file) { + Error("SOCKS Config: could not read config file name. SOCKS Turned off"); + goto error; + } + + Layout::relative_to(config_pathname, sizeof(config_pathname), + Layout::get()->sysconfdir, socks_config_file); + xfree(socks_config_file); + Debug("Socks", "Socks Config File: %s", config_pathname); + + socks_config_fd =::open(config_pathname, O_RDONLY); + + if (socks_config_fd < 0) { + Error("SOCKS Config: could not open config file '%s'. SOCKS Turned off", config_pathname); + goto error; + } +#ifdef SOCKS_WITH_TS + tmp = socks_conf_stuff->ip_range.read_table_from_file(socks_config_fd, "no_socks"); + + if (tmp) { + Error("SOCKS Config: Error while reading ip_range: %s.", tmp); + xfree(tmp); + goto error; + } +#endif + + if (loadSocksAuthInfo(socks_config_fd, socks_conf_stuff) != 0) { + Error("SOCKS Config: Error while reading Socks auth info"); + goto error; + } + Debug("Socks", "Socks Turned on"); + ::close(socks_config_fd); + + return; +error: + + socks_conf_stuff->socks_needed = 0; + socks_conf_stuff->accept_enabled = 0; + if (socks_config_fd >= 0) + ::close(socks_config_fd); + +} + +int +loadSocksAuthInfo(int fd, socks_conf_struct * socks_stuff) +{ + char c = '\0'; + char line[256] = { 0 }; // initialize all chars to nil + char user_name[256] = { 0 }; + char passwd[256] = { 0 }; + + if (lseek(fd, 0, SEEK_SET) < 0) { + Warning("Can not seek on Socks configuration file\n"); + return -1; + } + + bool end_of_file = false; + do { + int n = 0, rc; + while (((rc = read(fd, &c, 1)) == 1) && (c != '\n') && (n < 254)) + line[n++] = c; + if (rc <= 0) + end_of_file = true; + line[n] = '\0'; + + // coverity[secure_coding] + rc = sscanf(line, " auth u %255s %255s ", user_name, passwd); + if (rc >= 2) { + int len1 = strlen(user_name); + int len2 = strlen(passwd); + + Debug("Socks", "Read user_name(%s) and passwd(%s) from config file", user_name, passwd); + + socks_stuff->user_name_n_passwd_len = len1 + len2 + 2; + + char *ptr = (char *) xmalloc(socks_stuff->user_name_n_passwd_len); + ptr[0] = len1; + memcpy(&ptr[1], user_name, len1); + ptr[len1 + 1] = len2; + memcpy(&ptr[len1 + 2], passwd, len2); + + socks_stuff->user_name_n_passwd = ptr; + + return 0; + } + } while (!end_of_file); + + return 0; +} + +int +socks5BasicAuthHandler(int event, unsigned char *p, void (**h_ptr) (void)) +{ + //for more info on Socks5 see RFC 1928 + int ret = 0; + char *pass_phrase = netProcessor.socks_conf_stuff->user_name_n_passwd; + + switch (event) { + + case SOCKS_AUTH_OPEN: + p[ret++] = SOCKS5_VERSION; //version + p[ret++] = (pass_phrase) ? 2 : 1; //#Methods + p[ret++] = 0; //no authentication + if (pass_phrase) + p[ret++] = 2; + + break; + + case SOCKS_AUTH_WRITE_COMPLETE: + //return number of bytes to read + ret = 2; + break; + + case SOCKS_AUTH_READ_COMPLETE: + + if (p[0] == SOCKS5_VERSION) { + switch (p[1]) { + + case 0: // no authentication required + Debug("Socks", "No authentication required for Socks server"); + //make sure this is ok for us. right now it is always ok for us. + *h_ptr = NULL; + break; + + case 2: + Debug("Socks", "Socks server wants username/passwd"); + if (!pass_phrase) { + Debug("Socks", "Buggy Socks server: asks for username/passwd " "when not supplied as an option"); + ret = -1; + *h_ptr = NULL; + } else + *(SocksAuthHandler *) h_ptr = &socks5PasswdAuthHandler; + + break; + + case 0xff: + Debug("Socks", "None of the Socks authentcations is acceptable " "to the server"); + *h_ptr = NULL; + ret = -1; + break; + + default: + Debug("Socks", "Unexpected Socks auth method (%d) from the server", (int) p[1]); + ret = -1; + break; + } + } else { + Debug("Socks", "authEvent got wrong version %d from the Socks server", (int) p[0]); + ret = -1; + } + + break; + + default: + //This should be inpossible + ink_debug_assert(!"bad case value"); + ret = -1; + break; + } + return ret; +} + +int +socks5PasswdAuthHandler(int event, unsigned char *p, void (**h_ptr) (void)) +{ + //for more info see RFC 1929 + int ret = 0; + char *pass_phrase; + int pass_len; + + switch (event) { + + case SOCKS_AUTH_OPEN: + pass_phrase = netProcessor.socks_conf_stuff->user_name_n_passwd; + pass_len = netProcessor.socks_conf_stuff->user_name_n_passwd_len; + ink_debug_assert(pass_phrase); + + p[0] = 1; //version + memcpy(&p[1], pass_phrase, pass_len); + + ret = 1 + pass_len; + break; + + case SOCKS_AUTH_WRITE_COMPLETE: + //return number of bytes to read + ret = 2; + break; + + case SOCKS_AUTH_READ_COMPLETE: + + //if (p[0] == 1) { // skip this. its not clear what this should be. + // NEC thinks it is 5 RFC seems to indicate 1. + switch (p[1]) { + + case 0: + Debug("Socks", "Username/Passwd succeded"); + *h_ptr = NULL; + break; + + default: + Debug("Socks", "Username/Passwd authentication failed ret_code: %d", (int) p[1]); + ret = -1; + } + //} + //else { + // Debug("Socks", "authPassEvent got wrong version %d from " + // "Socks server\n", (int)p[0]); + // ret = -1; + //} + + break; + + default: + ink_debug_assert(!"bad case value"); + ret = -1; + break; + } + return ret; +} diff --git a/iocore/net/UDPIOEvent.cc b/iocore/net/UDPIOEvent.cc new file mode 100644 index 00000000..0309d909 --- /dev/null +++ b/iocore/net/UDPIOEvent.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" +ClassAllocator UDPIOEventAllocator("UDPIOEventAllocator"); diff --git a/iocore/net/UnixConnection.cc b/iocore/net/UnixConnection.cc new file mode 100644 index 00000000..59446499 --- /dev/null +++ b/iocore/net/UnixConnection.cc @@ -0,0 +1,354 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + Connections + +**************************************************************************/ +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "P_Net.h" + +#define SET_NO_LINGER +// set in the OS +// #define RECV_BUF_SIZE (1024*64) +// #define SEND_BUF_SIZE (1024*64) +#define FIRST_RANDOM_PORT 16000 +#define LAST_RANDOM_PORT 32000 + +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) + +#if !defined(IP_TRANSPARENT) +unsigned int const IP_TRANSPARENT = 19; +#endif + +// +// Functions +// +int +Connection::setup_mc_send(unsigned int mc_ip, int mc_port, + unsigned int my_ip, int my_port, + bool non_blocking, unsigned char mc_ttl, bool mc_loopback, Continuation * c) +{ + (void) c; + ink_assert(fd == NO_FD); + int res = 0; + int enable_reuseaddr = 1; + + if ((res = socketManager.mc_socket(AF_INET, SOCK_DGRAM, 0, non_blocking)) < 0) + goto Lerror; + + fd = res; + + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable_reuseaddr, sizeof(enable_reuseaddr)) < 0)) { + goto Lerror; + } + + struct sockaddr_in bind_sa; + memset(&bind_sa, 0, sizeof(bind_sa)); + bind_sa.sin_family = AF_INET; + bind_sa.sin_port = htons(my_port); + bind_sa.sin_addr.s_addr = my_ip; + if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &bind_sa, sizeof(bind_sa), IPPROTO_UDP)) < 0) { + goto Lerror; + } + + sa.ss_family = AF_INET; + ((struct sockaddr_in *)(&sa))->sin_port = htons(mc_port); + ((struct sockaddr_in *)(&sa))->sin_addr.s_addr = mc_ip; + memset(&(((struct sockaddr_in *)(&sa))->sin_zero), 0, 8); + +#ifdef SET_CLOSE_ON_EXEC + if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0) + goto Lerror; +#endif + + if (non_blocking) + if ((res = safe_nonblocking(fd)) < 0) + goto Lerror; + + // Set MultiCast TTL to specified value + if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &mc_ttl, sizeof(mc_ttl)) < 0)) + goto Lerror; + + + // Disable MultiCast loopback if requested + if (!mc_loopback) { + char loop = 0; + + if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) < 0)) + goto Lerror; + } + return 0; + +Lerror: + if (fd != NO_FD) + close(); + return res; +} + + +int +Connection::setup_mc_receive(unsigned int mc_ip, int mc_port, + bool non_blocking, Connection * sendChan, Continuation * c) +{ + ink_assert(fd == NO_FD); + (void) sendChan; + (void) c; + int res = 0; + int enable_reuseaddr = 1; + + if ((res = socketManager.socket(AF_INET, SOCK_DGRAM, 0)) < 0) + goto Lerror; + + fd = res; + +#ifdef SET_CLOSE_ON_EXEC + if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0) + goto Lerror; +#endif + + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable_reuseaddr, sizeof(enable_reuseaddr)) < 0)) + goto Lerror; + + memset(&sa, 0, sizeof(sa)); + sa.ss_family = AF_INET; + ((struct sockaddr_in *)(&sa))->sin_addr.s_addr = mc_ip; + ((struct sockaddr_in *)(&sa))->sin_port = htons(mc_port); + + if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &sa, sizeof(sa), IPPROTO_TCP)) < 0) + goto Lerror; + + if (non_blocking) + if ((res = safe_nonblocking(fd)) < 0) + goto Lerror; + + struct ip_mreq mc_request; + // Add ourselves to the MultiCast group + mc_request.imr_multiaddr.s_addr = mc_ip; + mc_request.imr_interface.s_addr = htonl(INADDR_ANY); + + if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mc_request, sizeof(mc_request)) < 0)) + goto Lerror; + return 0; + +Lerror: + if (fd != NO_FD) + close(); + return res; +} + +namespace { + /** Struct to make cleaning up resources easier. + + By default, the @a method is invoked on the @a object when + this object is destructed. This can be prevented by calling + the @c reset method. + + This is not overly useful in the allocate, check, return case + but very handy if there are + - multiple resources (each can have its own cleaner) + - multiple checks against the resource + In such cases, rather than trying to track all the resources + that might need cleaned up, you can set up a cleaner at allocation + and only have to deal with them on success, which is generally + singular. + + @code + self::some_method (...) { + /// allocate resource + cleaner clean_up(this, &self::cleanup); + // modify or check the resource + if (fail) return FAILURE; // cleanup() is called + /// success! + clean_up.reset(); // cleanup() not called after this + return SUCCESS; + @endcode + */ + template struct cleaner { + T* obj; ///< Object instance. + typedef void (T::*method)(); ///< Method signature. + method m; + + cleaner(T* _obj, method _method) : obj(_obj), m(_method) {} + ~cleaner() { if (obj) (obj->*m)(); } + void reset() { obj = 0; } + }; +} + +/** Default options. + + @internal This structure is used to reduce the number of places in + which the defaults are set. Originally the argument defaulted to + @c NULL which meant that the defaults had to be encoded in any + methods that used it as well as the @c NetVCOptions + constructor. Now they are controlled only in the latter and not in + any of the methods. This makes handling global default values + (such as @c RECV_BUF_SIZE) more robust. It doesn't have to be + checked in the method, only in the @c NetVCOptions constructor. + + The methods are simpler because they never have to check for the + presence of the options, yet the clients aren't inconvenienced + because a default value for the argument is provided. Further, + clients can pass temporaries and not have to declare a variable in + order to tweak options. + */ +NetVCOptions const Connection::DEFAULT_OPTIONS; + +int +Connection::open(NetVCOptions const& opt) +{ + ink_assert(fd == NO_FD); + int enable_reuseaddr = 1; // used for sockopt setting + int res = 0; // temp result + uint32_t local_addr = NetVCOptions::ANY_ADDR == opt.addr_binding + ? INADDR_ANY + : opt.local_addr; + uint16_t local_port = NetVCOptions::ANY_PORT == opt.port_binding + ? 0 + : opt.local_port; + int sock_type = NetVCOptions::USE_UDP == opt.ip_proto + ? SOCK_DGRAM + : SOCK_STREAM; + + res = socketManager.socket(AF_INET, sock_type, 0); + if (-1 == res) return -errno; + + fd = res; + // mark fd for close until we succeed. + cleaner cleanup(this, &Connection::_cleanup); + + // Try setting the various socket options, if requested. + + if (-1 == safe_setsockopt(fd, + SOL_SOCKET, + SO_REUSEADDR, + reinterpret_cast(&enable_reuseaddr), + sizeof(enable_reuseaddr))) + return -errno; + + if (!opt.f_blocking_connect && -1 == safe_nonblocking(fd)) + return -errno; + + if (opt.socket_recv_bufsize > 0) { + if (socketManager.set_rcvbuf_size(fd, opt.socket_recv_bufsize)) { + // Round down until success + int rbufsz = ROUNDUP(opt.socket_recv_bufsize, 1024); + while (rbufsz && !socketManager.set_rcvbuf_size(fd, rbufsz)) + rbufsz -= 1024; + Debug("socket", "::open: recv_bufsize = %d of %d\n", rbufsz, opt.socket_recv_bufsize); + } + } + if (opt.socket_send_bufsize > 0) { + if (socketManager.set_sndbuf_size(fd, opt.socket_send_bufsize)) { + // Round down until success + int sbufsz = ROUNDUP(opt.socket_send_bufsize, 1024); + while (sbufsz && !socketManager.set_sndbuf_size(fd, sbufsz)) + sbufsz -= 1024; + Debug("socket", "::open: send_bufsize = %d of %d\n", sbufsz, opt.socket_send_bufsize); + } + } + + if (SOCK_STREAM == sock_type) { + if (opt.sockopt_flags & NetVCOptions::SOCK_OPT_NO_DELAY) { + safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int)); + Debug("socket", "::open: setsockopt() TCP_NODELAY on socket"); + } + if (opt.sockopt_flags & NetVCOptions::SOCK_OPT_KEEP_ALIVE) { + safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int)); + Debug("socket", "::open: setsockopt() SO_KEEPALIVE on socket"); + } + } + + if (NetVCOptions::FOREIGN_ADDR == opt.addr_binding && local_addr) { + static char const * const DEBUG_TEXT = "::open setsockopt() IP_TRANSPARENT"; +#if TS_USE_TPROXY + int value = 1; + if (-1 == safe_setsockopt(fd, SOL_IP, TS_IP_TRANSPARENT, + reinterpret_cast(&value), sizeof(value) + )) { + Debug("socket", "%s - fail %d:%s", DEBUG_TEXT, errno, strerror(errno)); + return -errno; + } else { + Debug("socket", "%s set", DEBUG_TEXT); + } +#else + Debug("socket", "%s - requested but TPROXY not configured", DEBUG_TEXT); +#endif + } + + // Local address/port. + struct sockaddr_in bind_sa; + memset(&bind_sa, 0, sizeof(bind_sa)); + bind_sa.sin_family = AF_INET; + bind_sa.sin_port = htons(local_port); + bind_sa.sin_addr.s_addr = local_addr; + if (-1 == socketManager.ink_bind(fd, + reinterpret_cast(&bind_sa), + sizeof(bind_sa))) + return -errno; + + cleanup.reset(); + is_bound = true; + return 0; +} + +int +Connection::connect(uint32_t addr, uint16_t port, NetVCOptions const& opt) { + ink_assert(fd != NO_FD); + ink_assert(is_bound); + ink_assert(!is_connected); + + int res; + + this->setRemote(addr, port); + + cleaner cleanup(this, &Connection::_cleanup); // mark for close until we succeed. + + res = ::connect(fd, + reinterpret_cast(&sa), + sizeof(struct sockaddr_in)); + // It's only really an error if either the connect was blocking + // or it wasn't blocking and the error was other than EINPROGRESS. + // (Is EWOULDBLOCK ok? Does that start the connect?) + // We also want to handle the cases where the connect blocking + // and IO blocking differ, by turning it on or off as needed. + if (-1 == res + && (opt.f_blocking_connect + || ! (EINPROGRESS == errno || EWOULDBLOCK == errno))) { + return -errno; + } else if (opt.f_blocking_connect && !opt.f_blocking) { + if (-1 == safe_nonblocking(fd)) return -errno; + } else if (!opt.f_blocking_connect && opt.f_blocking) { + if (-1 == safe_blocking(fd)) return -errno; + } + + cleanup.reset(); + is_connected = true; + return 0; +} + +void +Connection::_cleanup() +{ + this->close(); +} diff --git a/iocore/net/UnixNet.cc b/iocore/net/UnixNet.cc new file mode 100644 index 00000000..0d3badd8 --- /dev/null +++ b/iocore/net/UnixNet.cc @@ -0,0 +1,438 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" + +ink_hrtime last_throttle_warning; +ink_hrtime last_shedding_warning; +ink_hrtime emergency_throttle_time; +int net_connections_throttle; +int fds_throttle; +bool throttle_enabled; +int fds_limit = 8000; +ink_hrtime last_transient_accept_error; + +extern "C" void fd_reify(struct ev_loop *); + + +#ifndef INACTIVITY_TIMEOUT +// INKqa10496 +// One Inactivity cop runs on each thread once every second and +// loops through the list of NetVCs and calls the timeouts +struct InactivityCop : public Continuation { + InactivityCop(ProxyMutex *m):Continuation(m) { + SET_HANDLER(&InactivityCop::check_inactivity); + } + int check_inactivity(int event, Event *e) { + (void) event; + ink_hrtime now = ink_get_hrtime(); + NetHandler *nh = get_NetHandler(this_ethread()); + // Copy the list and use pop() to catch any closes caused by callbacks. + forl_LL(UnixNetVConnection, vc, nh->open_list) + nh->cop_list.push(vc); + while (UnixNetVConnection *vc = nh->cop_list.pop()) { + if (vc->closed) { + close_UnixNetVConnection(vc, e->ethread); + continue; + } + if (vc->next_inactivity_timeout_at && vc->next_inactivity_timeout_at < now) + vc->handleEvent(EVENT_IMMEDIATE, e); + } + return 0; + } +}; +#endif + +PollCont::PollCont(ProxyMutex *m, int pt):Continuation(m), net_handler(NULL), poll_timeout(pt) { + pollDescriptor = NEW(new PollDescriptor); + pollDescriptor->init(); + SET_HANDLER(&PollCont::pollEvent); +} + +PollCont::PollCont(ProxyMutex *m, NetHandler *nh, int pt):Continuation(m), net_handler(nh), poll_timeout(pt) +{ + pollDescriptor = NEW(new PollDescriptor); + pollDescriptor->init(); + SET_HANDLER(&PollCont::pollEvent); +} + +PollCont::~PollCont() { + delete pollDescriptor; +} + +// +// PollCont continuation which does the epoll_wait +// and stores the resultant events in ePoll_Triggered_Events +// +int +PollCont::pollEvent(int event, Event *e) { + (void) event; + (void) e; + + if (likely(net_handler)) { + /* checking to see whether there are connections on the ready_queue (either read or write) that need processing [ebalsa] */ + if (likely + (!net_handler->read_ready_list.empty() || !net_handler->read_ready_list.empty() || + !net_handler->read_enable_list.empty() || !net_handler->write_enable_list.empty())) { + NetDebug("iocore_net_poll", "rrq: %d, wrq: %d, rel: %d, wel: %d", net_handler->read_ready_list.empty(), + net_handler->write_ready_list.empty(), net_handler->read_enable_list.empty(), + net_handler->write_enable_list.empty()); + poll_timeout = 0; //poll immediately returns -- we have triggered stuff to process right now + } else { + poll_timeout = net_config_poll_timeout; + } + } + // wait for fd's to tigger, or don't wait if timeout is 0 +#if TS_USE_LIBEV + struct ev_loop *eio = pollDescriptor->eio; + double pt = (double)poll_timeout/1000.0; + fd_reify(eio); + eio->backend_poll(eio, pt); + pollDescriptor->result = eio->pendingcnt[0]; + NetDebug("iocore_net_poll", "[PollCont::pollEvent] backend_poll(%d,%f), result=%d", eio->backend_fd,pt,pollDescriptor->result); +#elif TS_USE_EPOLL + pollDescriptor->result = epoll_wait(pollDescriptor->epoll_fd, + pollDescriptor->ePoll_Triggered_Events, POLL_DESCRIPTOR_SIZE, poll_timeout); + NetDebug("iocore_net_poll", "[PollCont::pollEvent] epoll_fd: %d, timeout: %d, results: %d", pollDescriptor->epoll_fd, poll_timeout, + pollDescriptor->result); +#elif TS_USE_KQUEUE + struct timespec tv; + tv.tv_sec = poll_timeout / 1000; + tv.tv_nsec = 1000000 * (poll_timeout % 1000); + pollDescriptor->result = kevent(pollDescriptor->kqueue_fd, NULL, 0, + pollDescriptor->kq_Triggered_Events, + POLL_DESCRIPTOR_SIZE, + &tv); + NetDebug("iocore_net_poll", "[PollCont::pollEvent] kueue_fd: %d, timeout: %d, results: %d", pollDescriptor->kqueue_fd, poll_timeout, + pollDescriptor->result); +#elif TS_USE_PORT + int retval; + timespec_t ptimeout; + ptimeout.tv_sec = poll_timeout / 1000; + ptimeout.tv_nsec = 1000000 * (poll_timeout % 1000); + unsigned nget = 1; + if((retval = port_getn(pollDescriptor->port_fd, + pollDescriptor->Port_Triggered_Events, + POLL_DESCRIPTOR_SIZE, &nget, &ptimeout)) < 0) { + pollDescriptor->result = 0; + switch(errno) { + case EINTR: + case EAGAIN: + case ETIME: + if (nget > 0) { + pollDescriptor->result = (int)nget; + } + break; + default: + ink_assert(!"unhandled port_getn() case:"); + break; + } + } else { + pollDescriptor->result = (int)nget; + } + NetDebug("iocore_net_poll", "[PollCont::pollEvent] %d[%s]=port_getn(%d,%p,%d,%d,%d),results(%d)", + retval,retval < 0 ? strerror(errno) : "ok", + pollDescriptor->port_fd, pollDescriptor->Port_Triggered_Events, + POLL_DESCRIPTOR_SIZE, nget, poll_timeout, pollDescriptor->result); +#else +#error port me +#endif + return EVENT_CONT; +} + +static void +net_signal_hook_callback(EThread *thread) { +#if TS_HAS_EVENTFD + uint64_t counter; + NOWARN_UNUSED_RETURN(read(thread->evfd, &counter, sizeof(uint64_t))); +#else + char dummy[1024]; + NOWARN_UNUSED_RETURN(read(thread->evpipe[0], &dummy[0], 1024)); +#endif +} + +static void +net_signal_hook_function(EThread *thread) { +#if TS_HAS_EVENTFD + uint64_t counter = 1; + NOWARN_UNUSED_RETURN(write(thread->evfd, &counter, sizeof(uint64_t))); +#else + char dummy = 1; + NOWARN_UNUSED_RETURN(write(thread->evpipe[1], &dummy, 1)); +#endif +} + +void +initialize_thread_for_net(EThread *thread, int thread_index) +{ + NOWARN_UNUSED(thread_index); + + new((ink_dummy_for_new *) get_NetHandler(thread)) NetHandler(); + new((ink_dummy_for_new *) get_PollCont(thread)) PollCont(thread->mutex, get_NetHandler(thread)); + get_NetHandler(thread)->mutex = new_ProxyMutex(); + PollCont *pc = get_PollCont(thread); + PollDescriptor *pd = pc->pollDescriptor; +#if TS_USE_LIBEV + if (!thread_index) + pd->eio = ev_default_loop(LIBEV_BACKEND_LIST); + else + pd->eio = ev_loop_new(LIBEV_BACKEND_LIST); +#endif + thread->schedule_imm(get_NetHandler(thread)); + +#ifndef INACTIVITY_TIMEOUT + InactivityCop *inactivityCop = NEW(new InactivityCop(get_NetHandler(thread)->mutex)); + thread->schedule_every(inactivityCop, HRTIME_SECONDS(1)); +#endif + + thread->signal_hook = net_signal_hook_function; + thread->ep = (EventIO*)malloc(sizeof(EventIO)); + thread->ep->type = EVENTIO_ASYNC_SIGNAL; +#if TS_HAS_EVENTFD + thread->ep->start(pd, thread->evfd, 0, EVENTIO_READ); +#else + thread->ep->start(pd, thread->evpipe[0], 0, EVENTIO_READ); +#endif +} + +// NetHandler method definitions + +NetHandler::NetHandler():Continuation(NULL), trigger_event(0) +{ + SET_HANDLER((NetContHandler) & NetHandler::startNetEvent); +} + +// +// Initialization here, in the thread in which we will be executing +// from now on. +// +int +NetHandler::startNetEvent(int event, Event *e) +{ + (void) event; + SET_HANDLER((NetContHandler) & NetHandler::mainNetEvent); + e->schedule_every(NET_PERIOD); + trigger_event = e; + return EVENT_CONT; +} + +// +// Move VC's enabled on a different thread to the ready list +// +void +NetHandler::process_enabled_list(NetHandler *nh, EThread *t) +{ + NOWARN_UNUSED(t); + UnixNetVConnection *vc = NULL; + + SListM(UnixNetVConnection, NetState, read, enable_link) rq(nh->read_enable_list.popall()); + while ((vc = rq.pop())) { + vc->ep.modify(EVENTIO_READ); + vc->ep.refresh(EVENTIO_READ); + vc->read.in_enabled_list = 0; + if ((vc->read.enabled && vc->read.triggered) || vc->closed) + nh->read_ready_list.in_or_enqueue(vc); + } + + SListM(UnixNetVConnection, NetState, write, enable_link) wq(nh->write_enable_list.popall()); + while ((vc = wq.pop())) { + vc->ep.modify(EVENTIO_WRITE); + vc->ep.refresh(EVENTIO_WRITE); + vc->write.in_enabled_list = 0; + if ((vc->write.enabled && vc->write.triggered) || vc->closed) + nh->write_ready_list.in_or_enqueue(vc); + } +} + + +// +// The main event for NetHandler +// This is called every NET_PERIOD, and handles all IO operations scheduled +// for this period. +// +int +NetHandler::mainNetEvent(int event, Event *e) +{ + ink_assert(trigger_event == e && (event == EVENT_INTERVAL || event == EVENT_POLL)); + (void) event; + (void) e; + EventIO *epd = NULL; + int poll_timeout = net_config_poll_timeout; + + NET_INCREMENT_DYN_STAT(net_handler_run_stat); + + process_enabled_list(this, e->ethread); + if (likely(!read_ready_list.empty() || !write_ready_list.empty() || !read_enable_list.empty() || !write_enable_list.empty())) + poll_timeout = 0; // poll immediately returns -- we have triggered stuff to process right now + else + poll_timeout = net_config_poll_timeout; + + PollDescriptor *pd = get_PollDescriptor(trigger_event->ethread); + UnixNetVConnection *vc = NULL; +#if TS_USE_LIBEV + struct ev_loop *eio = pd->eio; + double pt = (double)poll_timeout/1000.0; + fd_reify(eio); + eio->backend_poll(eio, pt); + pd->result = eio->pendingcnt[0]; + NetDebug("iocore_net_main_poll", "[NetHandler::mainNetEvent] backend_poll(%d,%f), result=%d", eio->backend_fd,pt,pd->result); +#elif TS_USE_EPOLL + pd->result = epoll_wait(pd->epoll_fd, pd->ePoll_Triggered_Events, POLL_DESCRIPTOR_SIZE, poll_timeout); + NetDebug("iocore_net_main_poll", "[NetHandler::mainNetEvent] epoll_wait(%d,%f), result=%d", pd->epoll_fd,poll_timeout,pd->result); +#elif TS_USE_KQUEUE + struct timespec tv; + tv.tv_sec = poll_timeout / 1000; + tv.tv_nsec = 1000000 * (poll_timeout % 1000); + pd->result = kevent(pd->kqueue_fd, NULL, 0, pd->kq_Triggered_Events, POLL_DESCRIPTOR_SIZE, &tv); + NetDebug("iocore_net_main_poll", "[NetHandler::mainNetEvent] kevent(%d,%f), result=%d", pd->kqueue_fd,poll_timeout,pd->result); +#elif TS_USE_PORT + int retval; + timespec_t ptimeout; + ptimeout.tv_sec = poll_timeout / 1000; + ptimeout.tv_nsec = 1000000 * (poll_timeout % 1000); + unsigned nget = 1; + if((retval = port_getn(pd->port_fd, pd->Port_Triggered_Events, POLL_DESCRIPTOR_SIZE, &nget, &ptimeout)) < 0) { + pd->result = 0; + switch(errno) { + case EINTR: + case EAGAIN: + case ETIME: + if (nget > 0) { + pd->result = (int)nget; + } + break; + default: + ink_assert(!"unhandled port_getn() case:"); + break; + } + } else { + pd->result = (int)nget; + } + NetDebug("iocore_net_main_poll", "[NetHandler::mainNetEvent] %d[%s]=port_getn(%d,%p,%d,%d,%d),results(%d)", + retval,retval < 0 ? strerror(errno) : "ok", + pd->port_fd, pd->Port_Triggered_Events, + POLL_DESCRIPTOR_SIZE, nget, poll_timeout, pd->result); + +#else +#error port me +#endif + + vc = NULL; + for (int x = 0; x < pd->result; x++) { + epd = (EventIO*) get_ev_data(pd,x); + if (epd->type == EVENTIO_READWRITE_VC) { + vc = epd->data.vc; + if (get_ev_events(pd,x) & (EVENTIO_READ|EVENTIO_ERROR)) { + vc->read.triggered = 1; + if (!read_ready_list.in(vc)) + read_ready_list.enqueue(vc); + else if (get_ev_events(pd,x) & EVENTIO_ERROR) { + // check for unhandled epoll events that should be handled + Debug("iocore_net_main", "Unhandled epoll event on read: 0x%04x read.enabled=%d closed=%d read.netready_queue=%d", + get_ev_events(pd,x), vc->read.enabled, vc->closed, read_ready_list.in(vc)); + } + } + vc = epd->data.vc; + if (get_ev_events(pd,x) & (EVENTIO_WRITE|EVENTIO_ERROR)) { + vc->write.triggered = 1; + if (!write_ready_list.in(vc)) + write_ready_list.enqueue(vc); + else if (get_ev_events(pd,x) & EVENTIO_ERROR) { + // check for unhandled epoll events that should be handled + Debug("iocore_net_main", + "Unhandled epoll event on write: 0x%04x write.enabled=%d closed=%d write.netready_queue=%d", + get_ev_events(pd,x), vc->write.enabled, vc->closed, write_ready_list.in(vc)); + } + } else if (!get_ev_events(pd,x) & EVENTIO_ERROR) { + Debug("iocore_net_main", "Unhandled epoll event: 0x%04x", get_ev_events(pd,x)); + } + } else if (epd->type == EVENTIO_DNS_CONNECTION) { + if (epd->data.dnscon != NULL) { + epd->data.dnscon->trigger(); // Make sure the DNSHandler for this con knows we triggered +#if defined(USE_EDGE_TRIGGER) + epd->refresh(EVENTIO_READ); +#endif + } + } else if (epd->type == EVENTIO_ASYNC_SIGNAL) + net_signal_hook_callback(trigger_event->ethread); + ev_next_event(pd,x); + } + + pd->result = 0; + +#if defined(USE_EDGE_TRIGGER) + // UnixNetVConnection * + while ((vc = read_ready_list.dequeue())) { + if (vc->closed) + close_UnixNetVConnection(vc, trigger_event->ethread); + else if (vc->read.enabled && vc->read.triggered) + vc->net_read_io(this, trigger_event->ethread); + else if (!vc->read.enabled) { + read_ready_list.remove(vc); +#if defined(solaris) + if (vc->read.triggered && vc->write.enabled) { + vc->ep.modify(-EVENTIO_READ); + vc->ep.refresh(EVENTIO_WRITE); + vc->writeReschedule(this); + } +#endif + } + } + while ((vc = write_ready_list.dequeue())) { + if (vc->closed) + close_UnixNetVConnection(vc, trigger_event->ethread); + else if (vc->write.enabled && vc->write.triggered) + write_to_net(this, vc, pd, trigger_event->ethread); + else if (!vc->write.enabled) { + write_ready_list.remove(vc); +#if defined(solaris) + if (vc->write.triggered && vc->read.enabled) { + vc->ep.modify(-EVENTIO_WRITE); + vc->ep.refresh(EVENTIO_READ); + vc->readReschedule(this); + } +#endif + } + } +#else /* !USE_EDGE_TRIGGER */ + while ((vc = read_ready_list.dequeue())) { + if (vc->closed) + close_UnixNetVConnection(vc, trigger_event->ethread); + else if (vc->read.enabled && vc->read.triggered) + vc->net_read_io(this, trigger_event->ethread); + else if (!vc->read.enabled) + vc->ep.modify(-EVENTIO_READ); + } + while ((vc = write_ready_list.dequeue())) { + if (vc->closed) + close_UnixNetVConnection(vc, trigger_event->ethread); + else if (vc->write.enabled && vc->write.triggered) + write_to_net(this, vc, pd, trigger_event->ethread); + else if (!vc->write.enabled) + vc->ep.modify(-EVENTIO_WRITE); + } +#endif /* !USE_EDGE_TRIGGER */ + + return EVENT_CONT; +} + diff --git a/iocore/net/UnixNetAccept.cc b/iocore/net/UnixNetAccept.cc new file mode 100644 index 00000000..287f1665 --- /dev/null +++ b/iocore/net/UnixNetAccept.cc @@ -0,0 +1,576 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" + +#ifdef ROUNDUP +#undef ROUNDUP +#endif +#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) + +typedef int (NetAccept::*NetAcceptHandler) (int, void *); +volatile int dummy_volatile = 0; +int accept_till_done = 1; + +void +safe_delay(int msec) +{ + socketManager.poll(0, 0, msec); +} + + +// +// Send the throttling message to up to THROTTLE_AT_ONCE connections, +// delaying to let some of the current connections complete +// +int +send_throttle_message(NetAccept * na) +{ + struct pollfd afd; + Connection con[100]; + char dummy_read_request[4096]; + + afd.fd = na->server.fd; + afd.events = POLLIN; + + int n = 0; + while (check_net_throttle(ACCEPT, ink_get_hrtime()) && n < THROTTLE_AT_ONCE - 1 + && (socketManager.poll(&afd, 1, 0) > 0)) { + int res = 0; + if ((res = na->server.accept(&con[n])) < 0) + return res; + n++; + } + safe_delay(NET_THROTTLE_DELAY / 2); + int i = 0; + for (i = 0; i < n; i++) { + socketManager.read(con[i].fd, dummy_read_request, 4096); + socketManager.write(con[i].fd, unix_netProcessor.throttle_error_message, + strlen(unix_netProcessor.throttle_error_message)); + } + safe_delay(NET_THROTTLE_DELAY / 2); + for (i = 0; i < n; i++) + con[i].close(); + return 0; +} + + +// +// General case network connection accept code +// +int +net_accept(NetAccept * na, void *ep, bool blockable) +{ + Event *e = (Event *) ep; + int res = 0; + int count = 0; + int loop = accept_till_done; + UnixNetVConnection *vc = NULL; + + if (!blockable) + if (!MUTEX_TAKE_TRY_LOCK_FOR(na->action_->mutex, e->ethread, na->action_->continuation)) + return 0; + //do-while for accepting all the connections + //added by YTS Team, yamsat + do { + vc = (UnixNetVConnection *) na->alloc_cache; + if (!vc) { + vc = na->allocateThread(e->ethread); + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, 1); + vc->id = net_next_connection_number(); + na->alloc_cache = vc; + } + if ((res = na->server.accept(&vc->con)) < 0) { + if (res == -EAGAIN || res == -ECONNABORTED || res == -EPIPE) + goto Ldone; + if (na->server.fd != NO_FD && !na->action_->cancelled) { + if (!blockable) + na->action_->continuation->handleEvent(EVENT_ERROR, (void *)(intptr_t)res); + else { + MUTEX_LOCK(lock, na->action_->mutex, e->ethread); + na->action_->continuation->handleEvent(EVENT_ERROR, (void *)(intptr_t)res); + } + } + count = res; + goto Ldone; + } + count++; + na->alloc_cache = NULL; + + vc->submit_time = ink_get_hrtime(); + vc->ip = ((struct sockaddr_in *)(&(vc->con.sa)))->sin_addr.s_addr; + vc->port = ntohs(((struct sockaddr_in *)(&(vc->con.sa)))->sin_port); + vc->accept_port = ntohs(((struct sockaddr_in *)(&(na->server.sa)))->sin_port); + vc->mutex = new_ProxyMutex(); + vc->action_ = *na->action_; + vc->set_is_transparent(na->server.f_inbound_transparent); + vc->set_is_other_side_transparent(na->server.f_outbound_transparent); + Debug("http_tproxy", "Marking accepted %sconnection on %x as%s outbound transparent.\n", + na->server.f_inbound_transparent ? "transparent " : "", + na, na->server.f_outbound_transparent ? "" : " not" + ); + vc->closed = 0; + SET_CONTINUATION_HANDLER(vc, (NetVConnHandler) & UnixNetVConnection::acceptEvent); + + if (e->ethread->is_event_type(na->etype)) + vc->handleEvent(EVENT_NONE, e); + else + eventProcessor.schedule_imm(vc, na->etype); + } while (loop); + +Ldone: + if (!blockable) + MUTEX_UNTAKE_LOCK(na->action_->mutex, e->ethread); + return count; +} + + +// +// Special purpose MAIN proxy accept code +// Seperate accept thread function +// +int +net_accept_main_blocking(NetAccept * na, Event * e, bool blockable) +{ + (void) blockable; + (void) e; + + EThread *t = this_ethread(); + + while (1) + na->do_blocking_accept(na, t); + return -1; +} + + +UnixNetVConnection * +NetAccept::allocateThread(EThread * t) +{ + return ((UnixNetVConnection *)THREAD_ALLOC(netVCAllocator, t)); +} + +void +NetAccept::freeThread(UnixNetVConnection * vc, EThread * t) +{ + ink_assert(!vc->from_accept_thread); + THREAD_FREE(vc, netVCAllocator, t); +} + +// This allocates directly on the class allocator, used for accept threads. +UnixNetVConnection * +NetAccept::allocateGlobal() +{ + return (UnixNetVConnection *)netVCAllocator.alloc(); +} + +// Virtual function allows the correct +// etype to be used in NetAccept functions (ET_SSL +// or ET_NET). +EventType NetAccept::getEtype() +{ + return (ET_NET); +} + + +// +// Initialize the NetAccept for execution in its own thread. +// This should be done for low latency, high connection rate sockets. +// +void +NetAccept::init_accept_loop() +{ + if (!action_->continuation->mutex) { + action_->continuation->mutex = new_ProxyMutex(); + action_->mutex = action_->continuation->mutex; + } + SET_CONTINUATION_HANDLER(this, &NetAccept::acceptLoopEvent); + eventProcessor.spawn_thread(this, "[ACCEPT]"); +} + + +// +// Initialize the NetAccept for execution in a etype thread. +// This should be done for low connection rate sockets. +// (Management, Cluster, etc.) Also, since it adapts to the +// number of connections arriving, it should be reasonable to +// use it for high connection rates as well. +// +void +NetAccept::init_accept(EThread * t) +{ + if (!t) + t = eventProcessor.assign_thread(etype); + + if (!action_->continuation->mutex) { + action_->continuation->mutex = t->mutex; + action_->mutex = t->mutex; + } + if (do_listen(NON_BLOCKING)) + return; + SET_HANDLER((NetAcceptHandler) & NetAccept::acceptEvent); + period = ACCEPT_PERIOD; + t->schedule_every(this, period, etype); +} + + +void +NetAccept::init_accept_per_thread() +{ + int i, n; + + if (do_listen(NON_BLOCKING)) + return; + if (accept_fn == net_accept) + SET_HANDLER((NetAcceptHandler) & NetAccept::acceptFastEvent); + else + SET_HANDLER((NetAcceptHandler) & NetAccept::acceptEvent); + period = ACCEPT_PERIOD; + + NetAccept *a; + n = eventProcessor.n_threads_for_type[ET_NET]; + for (i = 0; i < n; i++) { + if (i < n - 1) { + a = NEW(new NetAccept); + *a = *this; + } else + a = this; + EThread *t = eventProcessor.eventthread[ET_NET][i]; + PollDescriptor *pd = get_PollDescriptor(t); + if (a->ep.start(pd, a, EVENTIO_READ) < 0) + Warning("[NetAccept::init_accept_per_thread]:error starting EventIO"); + a->mutex = get_NetHandler(t)->mutex; + t->schedule_every(a, period, etype); + } +} + + +int +NetAccept::do_listen(bool non_blocking) +{ + int res = 0; + + if (server.fd != NO_FD) { + if ((res = server.setup_fd_for_listen(non_blocking, recv_bufsize, send_bufsize))) { + Warning("unable to listen on main accept port %d: errno = %d, %s", port, errno, strerror(errno)); + goto Lretry; + } + } else { + Lretry: + if ((res = server.listen(port, domain, non_blocking, recv_bufsize, send_bufsize))) + Warning("unable to listen on port %d: %d %d, %s", port, res, errno, strerror(errno)); + } + if (callback_on_open && !action_->cancelled) { + if (res) + action_->continuation->handleEvent(NET_EVENT_ACCEPT_FAILED, this); + else + action_->continuation->handleEvent(NET_EVENT_ACCEPT_SUCCEED, this); + mutex = NULL; + } + return res; +} + + +int +NetAccept::do_blocking_accept(NetAccept * master_na, EThread * t) +{ + int res = 0; + int loop = accept_till_done; + UnixNetVConnection *vc = NULL; + + //do-while for accepting all the connections + //added by YTS Team, yamsat + do { + vc = (UnixNetVConnection *) master_na->alloc_cache; + if (likely(!vc)) { + //vc = allocateThread(t); + vc = allocateGlobal(); // Bypass proxy / thread allocator + vc->from_accept_thread = true; + vc->id = net_next_connection_number(); + master_na->alloc_cache = vc; + } + ink_hrtime now = ink_get_hrtime(); + + // Throttle accepts + + while (check_net_throttle(ACCEPT, now)) { + check_throttle_warning(); + if (!unix_netProcessor.throttle_error_message) { + safe_delay(NET_THROTTLE_DELAY); + } else if (send_throttle_message(this) < 0) + goto Lerror; + } + + if ((res = server.accept(&vc->con)) < 0) { + Lerror: + int seriousness = accept_error_seriousness(res); + if (seriousness >= 0) { // not so bad + if (!seriousness) // bad enough to warn about + check_transient_accept_error(res); + safe_delay(NET_THROTTLE_DELAY); + return 0; + } + if (!action_->cancelled) { + MUTEX_LOCK(lock, action_->mutex, t); + action_->continuation->handleEvent(EVENT_ERROR, (void *)(intptr_t)res); + MUTEX_UNTAKE_LOCK(action_->mutex, t); + Warning("accept thread received fatal error: errno = %d", errno); + } + return -1; + } + check_emergency_throttle(vc->con); + master_na->alloc_cache = NULL; + + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, 1); + vc->submit_time = now; + vc->ip = ((struct sockaddr_in *)(&(vc->con.sa)))->sin_addr.s_addr; + vc->port = ntohs(((struct sockaddr_in *)(&(vc->con.sa)))->sin_port); + vc->accept_port = ntohs(((struct sockaddr_in *)(&(server.sa)))->sin_port); + vc->set_is_transparent(master_na->server.f_inbound_transparent); + vc->set_is_other_side_transparent(master_na->server.f_outbound_transparent); + Debug("http_tproxy", "Marking accepted %sconnect on %x as%s outbound transparent.\n", + master_na->server.f_inbound_transparent ? "transparent " : "", + master_na, master_na->server.f_outbound_transparent ? "" : " not" + ); + vc->mutex = new_ProxyMutex(); + vc->action_ = *action_; + SET_CONTINUATION_HANDLER(vc, (NetVConnHandler) & UnixNetVConnection::acceptEvent); + //eventProcessor.schedule_imm(vc, getEtype()); + eventProcessor.schedule_imm_signal(vc, getEtype()); + } while (loop); + + return 1; +} + + +int +NetAccept::acceptEvent(int event, void *ep) +{ + (void) event; + Event *e = (Event *) ep; + //PollDescriptor *pd = get_PollDescriptor(e->ethread); + ProxyMutex *m = 0; + + if (action_->mutex) + m = action_->mutex; + else + m = mutex; + MUTEX_TRY_LOCK(lock, m, e->ethread); + if (lock) { + if (action_->cancelled) { + e->cancel(); + NET_DECREMENT_DYN_STAT(net_accepts_currently_open_stat); + delete this; + return EVENT_DONE; + } + + //ink_debug_assert(ifd < 0 || event == EVENT_INTERVAL || (pd->nfds > ifd && pd->pfd[ifd].fd == server.fd)); + //if (ifd < 0 || event == EVENT_INTERVAL || (pd->pfd[ifd].revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL))) { + //ink_debug_assert(!"incomplete"); + int res; + if ((res = accept_fn(this, e, false)) < 0) { + NET_DECREMENT_DYN_STAT(net_accepts_currently_open_stat); + /* INKqa11179 */ + Warning("Accept on port %d failed with error no %d", ntohs(((struct sockaddr_in *)(&(server.sa)))->sin_port), res); + Warning("Traffic Server may be unable to accept more network" "connections on %d", ntohs(((struct sockaddr_in *)(&(server.sa)))->sin_port)); + e->cancel(); + delete this; + return EVENT_DONE; + } + //} + } + return EVENT_CONT; +} + + +int +NetAccept::acceptFastEvent(int event, void *ep) +{ + Event *e = (Event *) ep; + (void) event; + (void) e; + int bufsz, res; + + PollDescriptor *pd = get_PollDescriptor(e->ethread); + UnixNetVConnection *vc = NULL; + int loop = accept_till_done; + + do { + if (check_net_throttle(ACCEPT, ink_get_hrtime())) { + ifd = -1; + return EVENT_CONT; + } + vc = allocateThread(e->ethread); + + socklen_t sz = sizeof(vc->con.sa); + int fd = socketManager.accept(server.fd, (struct sockaddr *) &vc->con.sa, &sz); + + if (likely(fd >= 0)) { + Debug("iocore_net", "accepted a new socket: %d", fd); + if (send_bufsize > 0) { + if (unlikely(socketManager.set_sndbuf_size(fd, send_bufsize))) { + bufsz = ROUNDUP(send_bufsize, 1024); + while (bufsz > 0) { + if (!socketManager.set_sndbuf_size(fd, bufsz)) + break; + bufsz -= 1024; + } + } + } + if (recv_bufsize > 0) { + if (unlikely(socketManager.set_rcvbuf_size(fd, recv_bufsize))) { + bufsz = ROUNDUP(recv_bufsize, 1024); + while (bufsz > 0) { + if (!socketManager.set_rcvbuf_size(fd, bufsz)) + break; + bufsz -= 1024; + } + } + } + if (sockopt_flags & 1) { // we have to disable Nagle + safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, ON, sizeof(int)); + Debug("socket", "::acceptFastEvent: setsockopt() TCP_NODELAY on socket"); + } + if (sockopt_flags & 2) { + safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, ON, sizeof(int)); + Debug("socket", "::acceptFastEvent: setsockopt() SO_KEEPALIVE on socket"); + } + do { + res = safe_nonblocking(fd); + } while (res < 0 && (errno == EAGAIN || errno == EINTR)); + } else { + res = fd; + } + if (res < 0) { + res = -errno; + if (res == -EAGAIN || res == -ECONNABORTED +#if defined(linux) + || res == -EPIPE +#endif + ) { + ink_assert(vc->con.fd == NO_FD); + ink_assert(!vc->link.next && !vc->link.prev); + freeThread(vc, e->ethread); + goto Ldone; + } else if (accept_error_seriousness(res) >= 0) { + check_transient_accept_error(res); + freeThread(vc, e->ethread); + goto Ldone; + } + if (!action_->cancelled) + action_->continuation->handleEvent(EVENT_ERROR, (void *)(intptr_t)res); + goto Lerror; + } + vc->con.fd = fd; + + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, 1); + vc->id = net_next_connection_number(); + + vc->submit_time = ink_get_hrtime(); + vc->ip = ((struct sockaddr_in *)(&(vc->con.sa)))->sin_addr.s_addr; + vc->port = ntohs(((struct sockaddr_in *)(&(vc->con.sa)))->sin_port); + vc->accept_port = ntohs(((struct sockaddr_in *)(&(server.sa)))->sin_port); + vc->set_is_transparent(server.f_inbound_transparent); + vc->set_is_other_side_transparent(server.f_outbound_transparent); + Debug("http_tproxy", "Marking fast accepted %sconnection on as%s outbound transparent.\n", + server.f_inbound_transparent ? "transparent " : "", + server.f_outbound_transparent ? "" : " not" + ); + vc->mutex = new_ProxyMutex(); + vc->thread = e->ethread; + + vc->nh = get_NetHandler(e->ethread); + + SET_CONTINUATION_HANDLER(vc, (NetVConnHandler) & UnixNetVConnection::mainEvent); + + if (vc->ep.start(pd, vc, EVENTIO_READ|EVENTIO_WRITE) < 0) { + Warning("[NetAccept::acceptFastEvent]: Error in inserting fd[%d] in kevent\n", vc->con.fd); + close_UnixNetVConnection(vc, e->ethread); + return EVENT_DONE; + } + + vc->nh->open_list.enqueue(vc); + +#ifdef USE_EDGE_TRIGGER + // Set the vc as triggered and place it in the read ready queue in case there is already data on the socket. + Debug("iocore_net", "acceptEvent : Setting triggered and adding to the read ready queue"); + vc->read.triggered = 1; + vc->nh->read_ready_list.enqueue(vc); +#endif + + if (!action_->cancelled) + action_->continuation->handleEvent(NET_EVENT_ACCEPT, vc); + else + close_UnixNetVConnection(vc, e->ethread); + } while (loop); + +Ldone: + return EVENT_CONT; + +Lerror: + server.close(); + e->cancel(); + freeThread(vc, e->ethread); + NET_DECREMENT_DYN_STAT(net_accepts_currently_open_stat); + delete this; + return EVENT_DONE; +} + + +int +NetAccept::acceptLoopEvent(int event, Event * e) +{ + (void) event; + (void) e; + while (1) + if (net_accept_main_blocking(this, e, true) < 0) + break; + NET_DECREMENT_DYN_STAT(net_accepts_currently_open_stat); + delete this; + return EVENT_DONE; +} + + +// +// Accept Event handler +// +// + +NetAccept::NetAccept() + : Continuation(NULL), + port(0), + period(0), + alloc_cache(0), + ifd(-1), callback_on_open(false), recv_bufsize(0), send_bufsize(0), sockopt_flags(0), etype(0) +{ } + + +// +// Stop listening. When the next poll takes place, an error will result. +// THIS ONLY WORKS WITH POLLING STYLE ACCEPTS! +// +void +NetAccept::cancel() +{ + action_->cancel(); + server.close(); +} diff --git a/iocore/net/UnixNetPages.cc b/iocore/net/UnixNetPages.cc new file mode 100644 index 00000000..797a65f9 --- /dev/null +++ b/iocore/net/UnixNetPages.cc @@ -0,0 +1,247 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#ifdef NON_MODULAR + +#include "P_Net.h" +#include "Show.h" +#include "I_Tasks.h" + +struct ShowNet; +typedef int (ShowNet::*ShowNetEventHandler) (int event, Event * data); +struct ShowNet: public ShowCont +{ + int ithread; + int port; + unsigned int ip; + + int showMain(int event, Event * e) + { + CHECK_SHOW(begin("Net")); + CHECK_SHOW(show("

Show Connections

\n" + "

Show Net Threads

\n" + "
\n" + "Show Connections to/from IP (e.g. 127.0.0.1):
\n" + "\n" + "
\n" + "
\n" + "Show Connections to/from Port (e.g. 80):
\n" + "\n" "
\n")); + return complete(event, e); + } + + int showConnectionsOnThread(int event, Event * e) + { + EThread *ethread = e->ethread; + NetHandler *nh = get_NetHandler(ethread); + MUTEX_TRY_LOCK(lock, nh->mutex, ethread); + if (!lock) { + ethread->schedule_in(this, NET_RETRY_DELAY); + return EVENT_DONE; + } + + ink_hrtime now = ink_get_hrtime(); + forl_LL(UnixNetVConnection, vc, nh->open_list) { + if (ip && ip != vc->ip) + continue; + if (port && port != vc->port && port != vc->accept_port) + continue; + char ipbuf[80]; + snprintf(ipbuf, sizeof(ipbuf), "%hhu.%hhu.%hhu.%hhu", PRINT_IP(vc->ip)); + char interbuf[80]; + snprintf(interbuf, sizeof(interbuf), "[%s] %hhu.%hhu.%hhu.%hhu", vc->options.toString(vc->options.addr_binding), PRINT_IP(vc->options.local_addr)); + CHECK_SHOW(show("" + // "%d" + "%d" // ID + "%s" // ipbuf + "%d" // port + "%d" // fd + "%s" // interbuf + "%d" // accept port + "%d secs ago" // start time + "%d" // thread id + "%d" // read enabled + "%d" // read NBytes + "%d" // read NDone + "%d" // write enabled + "%d" // write nbytes + "%d" // write ndone + "%d secs" // Inactivity timeout at + "%d secs" // Activity timeout at + "%d" // shutdown + "-%s" // comments + "\n", + vc->id, + ipbuf, + vc->port, + vc->con.fd, + interbuf, + vc->accept_port, + (int) ((now - vc->submit_time) / HRTIME_SECOND), + ethread->id, + vc->read.enabled, + vc->read.vio.nbytes, + vc->read.vio.ndone, + vc->write.enabled, + vc->write.vio.nbytes, + vc->write.vio.ndone, + (int) (vc->inactivity_timeout_in / HRTIME_SECOND), + (int) (vc->active_timeout_in / HRTIME_SECOND), vc->f.shutdown, vc->closed ? "closed " : "")); + } + ithread++; + if (ithread < eventProcessor.n_threads_for_type[ET_NET]) + eventProcessor.eventthread[ET_NET][ithread]->schedule_imm(this); + else { + CHECK_SHOW(show("\n")); + return complete(event, e); + } + return EVENT_CONT; + } + + int showConnections(int event, Event * e) + { + CHECK_SHOW(begin("Net Connections")); + CHECK_SHOW(show("

Connections

\n" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "\n")); + SET_HANDLER(&ShowNet::showConnectionsOnThread); + eventProcessor.eventthread[ET_NET][0]->schedule_imm(this); // This can not use ET_TASK. + return EVENT_CONT; + } + + int showSingleThread(int event, Event * e) + { + EThread *ethread = e->ethread; + NetHandler *nh = get_NetHandler(ethread); + PollDescriptor *pollDescriptor = get_PollDescriptor(ethread); + MUTEX_TRY_LOCK(lock, nh->mutex, ethread); + if (!lock) { + ethread->schedule_in(this, NET_RETRY_DELAY); + return EVENT_DONE; + } + + CHECK_SHOW(show("

Thread: %d

\n", ithread)); + CHECK_SHOW(show("
IDIPPortFDInterfaceAccept PortTime StartedThreadRead EnabledRead NBytesRead NDoneWrite EnabledWrite NBytesWrite NDoneInactive TimeoutActive TimeoutShutdownComments
\n")); + int connections = 0; + forl_LL(UnixNetVConnection, vc, nh->open_list) + connections++; + CHECK_SHOW(show("\n", "Connections", connections)); + //CHECK_SHOW(show("\n", "Last Poll Size", pollDescriptor->nfds)); + CHECK_SHOW(show("\n", "Last Poll Ready", pollDescriptor->result)); + CHECK_SHOW(show("
%s%d
%s%d
%s%d
\n")); + CHECK_SHOW(show("\n")); + CHECK_SHOW(show + ("\n")); + CHECK_SHOW(show("
#Read PriorityRead BucketWrite PriorityWrite Bucket
\n")); + ithread++; + if (ithread < eventProcessor.n_threads_for_type[ET_NET]) + eventProcessor.eventthread[ET_NET][ithread]->schedule_imm(this); + else + return complete(event, e); + return EVENT_CONT; + } + + int showThreads(int event, Event * e) + { + CHECK_SHOW(begin("Net Threads")); + SET_HANDLER(&ShowNet::showSingleThread); + eventProcessor.eventthread[ET_NET][0]->schedule_imm(this); // This can not use ET_TASK + return EVENT_CONT; + } + int showSingleConnection(int event, Event * e) + { + CHECK_SHOW(begin("Net Connection")); + return complete(event, e); + } + int showHostnames(int event, Event * e) + { + CHECK_SHOW(begin("Net Connections to/from Host")); + return complete(event, e); + } + +ShowNet(Continuation * c, HTTPHdr * h): + ShowCont(c, h), ithread(0), port(0), ip(0) { + SET_HANDLER(&ShowNet::showMain); + } +}; + +#undef STREQ_PREFIX +#define STREQ_PREFIX(_x,_n,_s) (!ptr_len_ncasecmp(_x,_n,_s,sizeof(_s)-1)) +Action * +register_ShowNet(Continuation * c, HTTPHdr * h) +{ + ShowNet *s = NEW(new ShowNet(c, h)); + int path_len; + const char *path = h->url_get()->path_get(&path_len); + + SET_CONTINUATION_HANDLER(s, &ShowNet::showMain); + if (STREQ_PREFIX(path, path_len, "connections")) { + SET_CONTINUATION_HANDLER(s, &ShowNet::showConnections); + } else if (STREQ_PREFIX(path, path_len, "threads")) { + SET_CONTINUATION_HANDLER(s, &ShowNet::showThreads); + } else if (STREQ_PREFIX(path, path_len, "ips")) { + int query_len; + const char *query = h->url_get()->query_get(&query_len); + s->sarg = xstrndup(query, query_len); + char *gn = NULL; + if (s->sarg) + gn = (char *)memchr(s->sarg, '=', strlen(s->sarg)); + if (gn) + s->ip = ink_inet_addr(gn + 1); + SET_CONTINUATION_HANDLER(s, &ShowNet::showConnections); + } else if (STREQ_PREFIX(path, path_len, "ports")) { + int query_len; + const char *query = h->url_get()->query_get(&query_len); + s->sarg = xstrndup(query, query_len); + char *gn = NULL; + if (s->sarg) + gn = (char *)memchr(s->sarg, '=', strlen(s->sarg)); + if (gn) + s->port = atoi(gn + 1); + SET_CONTINUATION_HANDLER(s, &ShowNet::showConnections); + } + eventProcessor.schedule_imm(s, ET_TASK); + return &s->action; +} + +#endif diff --git a/iocore/net/UnixNetProcessor.cc b/iocore/net/UnixNetProcessor.cc new file mode 100644 index 00000000..1a09dc9b --- /dev/null +++ b/iocore/net/UnixNetProcessor.cc @@ -0,0 +1,523 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" + +// For Stat Pages +#ifdef NON_MODULAR +#include "StatPages.h" +#endif + +NetProcessor::AcceptOptions const NetProcessor::DEFAULT_ACCEPT_OPTIONS; + +NetProcessor::AcceptOptions& +NetProcessor::AcceptOptions::reset() +{ + port = 0; + accept_threads = 0; + domain = AF_INET; + etype = ET_NET; + f_callback_on_open = false; + recv_bufsize = 0; + send_bufsize = 0; + sockopt_flags = 0; + f_outbound_transparent = false; + f_inbound_transparent = false; + return *this; +} + + +int net_connection_number = 1; +unsigned int +net_next_connection_number() +{ + unsigned int res = 0; + do { + res = (unsigned int) + ink_atomic_increment(&net_connection_number, 1); + } while (!res); + return res; +} + +Action * +NetProcessor::accept(Continuation * cont, + int port, + int domain, + int accept_threads, + bool frequent_accept, + unsigned int accept_ip, + char *accept_ip_str, + bool callback_on_open, + SOCKET listen_socket_in, + int accept_pool_size, + bool accept_only, + sockaddr * bound_sockaddr, + int *bound_sockaddr_size, + int recv_bufsize, int send_bufsize, uint32_t sockopt_flags, EventType etype) +{ + (void) listen_socket_in; // NT only + (void) accept_pool_size; // NT only + (void) accept_only; // NT only + (void) bound_sockaddr; // NT only + (void) bound_sockaddr_size; // NT only + Debug("iocore_net_processor", + "NetProcessor::accept - port %d,recv_bufsize %d, send_bufsize %d, sockopt 0x%0lX", + port, recv_bufsize, send_bufsize, sockopt_flags); + + AcceptOptions opt; + + opt.port = port; + opt.domain = domain; + opt.etype = etype; + opt.f_callback_on_open = callback_on_open; + opt.recv_bufsize = recv_bufsize; + opt.send_bufsize = send_bufsize; + opt.sockopt_flags = opt.sockopt_flags; + opt.accept_threads = accept_threads; + + return ((UnixNetProcessor *) this)->accept_internal(cont, NO_FD, + bound_sockaddr, + bound_sockaddr_size, + frequent_accept, + net_accept, + accept_ip, + accept_ip_str, + opt); +} + +Action * +NetProcessor::main_accept(Continuation * cont, SOCKET fd, sockaddr * bound_sockaddr, int *bound_sockaddr_size, + bool accept_only, bool localhost_only, AcceptOptions const& opt) +{ + (void) accept_only; // NT only + Debug("iocore_net_processor", "NetProcessor::main_accept - port %d,recv_bufsize %d, send_bufsize %d, sockopt 0x%0lX", + opt.port, opt.recv_bufsize, opt.send_bufsize, opt.sockopt_flags); + if (localhost_only) { + static char localhost[] = "127.0.0.1"; + + return ((UnixNetProcessor *) this)->accept_internal(cont, fd, + bound_sockaddr, + bound_sockaddr_size, + true, + net_accept, + inet_addr(localhost), + localhost, + opt); + } else { + return ((UnixNetProcessor *) this)->accept_internal(cont, fd, + bound_sockaddr, + bound_sockaddr_size, + true, + net_accept, + ((UnixNetProcessor *) this)->incoming_ip_to_bind_saddr, + ((UnixNetProcessor *) this)->incoming_ip_to_bind, + opt); + } +} + + + +Action * +UnixNetProcessor::accept_internal(Continuation * cont, + int fd, + struct sockaddr * bound_sockaddr, + int *bound_sockaddr_size, + bool frequent_accept, + AcceptFunction fn, + unsigned int accept_ip, + char *accept_ip_str, + AcceptOptions const& opt) +{ + EventType et = opt.etype; // setEtype requires non-const ref. + NetAccept *na = createNetAccept(); + EThread *thread = this_ethread(); + ProxyMutex *mutex = thread->mutex; + int accept_threads = opt.accept_threads; + + // Potentially upgrade to SSL. + upgradeEtype(et); + + // Fill in accept thread from configuration if necessary. + if (opt.accept_threads < 0) + IOCORE_ReadConfigInteger(accept_threads, "proxy.config.accept_threads"); + + NET_INCREMENT_DYN_STAT(net_accepts_currently_open_stat); + na->port = opt.port; + na->domain = opt.domain; + na->accept_fn = fn; + na->server.fd = fd; + na->server.accept_ip = accept_ip; + na->server.accept_ip_str = accept_ip_str; + na->server.f_outbound_transparent = opt.f_outbound_transparent; + na->server.f_inbound_transparent = opt.f_inbound_transparent; + if (opt.f_outbound_transparent) Debug("http_tproxy", "Marking accept server %x on port %d as outbound transparent.\n", na, opt.port); + na->action_ = NEW(new NetAcceptAction()); + *na->action_ = cont; + na->action_->server = &na->server; + na->callback_on_open = opt.f_callback_on_open; + na->recv_bufsize = opt.recv_bufsize; + na->send_bufsize = opt.send_bufsize; + na->sockopt_flags = opt.sockopt_flags; + na->etype = opt.etype; + if (na->callback_on_open) + na->mutex = cont->mutex; + if (frequent_accept) { // true + if (accept_threads > 0) { + if (0 == na->do_listen(BLOCKING)) { + NetAccept *a; + + for (int i=1; i < accept_threads; ++i) { + a = createNetAccept(); + *a = *na; + a->init_accept_loop(); + Debug("iocore_net_accept", "Created accept thread #%d for port %d", i, opt.port); + } + // Start the "template" accept thread last. + Debug("iocore_net_accept", "Created accept thread #%d for port %d", accept_threads, opt.port); + na->init_accept_loop(); + } + } else { + na->init_accept_per_thread(); + } + } else + na->init_accept(); + if (bound_sockaddr && bound_sockaddr_size) + safe_getsockname(na->server.fd, bound_sockaddr, bound_sockaddr_size); + +#ifdef TCP_DEFER_ACCEPT + // set tcp defer accept timeout if it is configured, this will not trigger an accept until there is + // data on the socket ready to be read + int accept_timeout = 0; + IOCORE_ReadConfigInteger(accept_timeout, "proxy.config.net.defer_accept"); + if (accept_timeout > 0) { + setsockopt(na->server.fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &accept_timeout, sizeof(int)); + } +#endif + return na->action_; +} + +Action * +UnixNetProcessor::connect_re_internal(Continuation * cont, + unsigned int ip, int port, NetVCOptions * opt) +{ + ProxyMutex *mutex = cont->mutex; + EThread *t = mutex->thread_holding; + UnixNetVConnection *vc = allocateThread(t); + + if (opt) + vc->options = *opt; + else + opt = &vc->options; + + // virtual function used to upgrade etype to ET_SSL for SSLNetProcessor. + upgradeEtype(opt->etype); + +#ifndef INK_NO_SOCKS + bool using_socks = (socks_conf_stuff->socks_needed && opt->socks_support != NO_SOCKS +#ifdef SOCKS_WITH_TS + && (opt->socks_version != SOCKS_DEFAULT_VERSION || + /* This implies we are tunnelling. + * we need to connect using socks server even + * if this ip is in no_socks list. + */ + !socks_conf_stuff->ip_range.match(ip)) +#endif + ); + SocksEntry *socksEntry = NULL; +#endif + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, 1); + vc->id = net_next_connection_number(); + vc->submit_time = ink_get_hrtime(); + vc->setSSLClientConnection(true); + vc->ip = ip; + vc->port = port; + vc->mutex = cont->mutex; + Action *result = &vc->action_; +#ifndef INK_NO_SOCKS + if (using_socks) { + Debug("Socks", "Using Socks ip: %u.%u.%u.%u:%d\n", PRINT_IP(ip), port); + socksEntry = socksAllocator.alloc(); + socksEntry->init(cont->mutex, vc, opt->socks_support, opt->socks_version); /*XXXX remove last two args */ + socksEntry->action_ = cont; + cont = socksEntry; + if (socksEntry->server_ip == (uint32_t) - 1) { + socksEntry->lerrno = ESOCK_NO_SOCK_SERVER_CONN; + socksEntry->free(); + return ACTION_RESULT_DONE; + } + vc->ip = socksEntry->server_ip; + vc->port = socksEntry->server_port; + result = &socksEntry->action_; + vc->action_ = socksEntry; + } else { + Debug("Socks", "Not Using Socks %d \n", socks_conf_stuff->socks_needed); + vc->action_ = cont; + } +#else + vc->action_ = cont; +#endif /*INK_NO_SOCKS */ + + if (t->is_event_type(opt->etype)) { + MUTEX_TRY_LOCK(lock, cont->mutex, t); + if (lock) { + MUTEX_TRY_LOCK(lock2, get_NetHandler(t)->mutex, t); + if (lock2) { + int ret; + ret = vc->connectUp(t); +#ifndef INK_NO_SOCKS + if ((using_socks) && (ret == CONNECT_SUCCESS)) + return &socksEntry->action_; + else +#endif + return ACTION_RESULT_DONE; + } + } + } + eventProcessor.schedule_imm(vc, opt->etype); +#ifndef INK_NO_SOCKS + if (using_socks) { + return &socksEntry->action_; + } else +#endif + return result; +} + +Action * +UnixNetProcessor::connect(Continuation * cont, + UnixNetVConnection ** avc, + unsigned int ip, int port, NetVCOptions * opt) +{ + NOWARN_UNUSED(avc); + return connect_re(cont, ip, port, opt); +} + +struct CheckConnect:public Continuation +{ + UnixNetVConnection *vc; + Action action_; + MIOBuffer *buf; + IOBufferReader *reader; + int connect_status; + int recursion; + ink_hrtime timeout; + + int handle_connect(int event, Event * e) + { + connect_status = event; + switch (event) { + case NET_EVENT_OPEN: + vc = (UnixNetVConnection *) e; + Debug("iocore_net_connect", "connect Net open"); + vc->do_io_write(this, 10, /* some non-zero number just to get the poll going */ + reader); + /* dont wait for more than timeout secs */ + vc->set_inactivity_timeout(timeout); + return EVENT_CONT; + break; + + case NET_EVENT_OPEN_FAILED: + Debug("iocore_net_connect", "connect Net open failed"); + if (!action_.cancelled) + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *) e); + break; + + case VC_EVENT_WRITE_READY:int sl, ret; + socklen_t sz; + if (!action_.cancelled) + { + sz = sizeof(int); + ret = getsockopt(vc->con.fd, SOL_SOCKET, SO_ERROR, (char *) &sl, &sz); + if (!ret && sl == 0) + { + Debug("iocore_net_connect", "connection established"); + /* disable write on vc */ + vc->write.enabled = 0; + vc->cancel_inactivity_timeout(); + //write_disable(get_NetHandler(this_ethread()), vc); + /* clean up vc fields */ + vc->write.vio.nbytes = 0; + vc->write.vio.op = VIO::NONE; + vc->write.vio.buffer.clear(); + + + action_.continuation->handleEvent(NET_EVENT_OPEN, vc); + delete this; + return EVENT_DONE; + } + } + vc->do_io_close(); + if (!action_.cancelled) + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *) -ENET_CONNECT_FAILED); + break; + case VC_EVENT_INACTIVITY_TIMEOUT: + Debug("iocore_net_connect", "connect timed out"); + vc->do_io_close(); + if (!action_.cancelled) + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *) -ENET_CONNECT_TIMEOUT); + break; + default: + ink_debug_assert(!"unknown connect event"); + if (!action_.cancelled) + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *) -ENET_CONNECT_FAILED); + + } + if (!recursion) + delete this; + return EVENT_DONE; + } + + Action *connect_s(Continuation * cont, unsigned int ip, int port, + int _timeout, NetVCOptions * opt) + { + action_ = cont; + timeout = HRTIME_SECONDS(_timeout); + recursion++; + netProcessor.connect_re(this, ip, port, opt); + recursion--; + if (connect_status != NET_EVENT_OPEN_FAILED) + return &action_; + else { + delete this; + return ACTION_RESULT_DONE; + } + } + + CheckConnect(ProxyMutex * m = NULL):Continuation(m), connect_status(-1), recursion(0), timeout(0) { + SET_HANDLER(&CheckConnect::handle_connect); + buf = new_empty_MIOBuffer(1); + reader = buf->alloc_reader(); + } + + ~CheckConnect() { + buf->dealloc_all_readers(); + buf->clear(); + free_MIOBuffer(buf); + } +}; + +Action * +NetProcessor::connect_s(Continuation * cont, unsigned int ip, + int port, int timeout, NetVCOptions * opt) +{ + Debug("iocore_net_connect", "NetProcessor::connect_s called"); + CheckConnect *c = NEW(new CheckConnect(cont->mutex)); + return c->connect_s(cont, ip, port, timeout, opt); +} + + + +struct PollCont; + +int +UnixNetProcessor::start(int) +{ + EventType etype = ET_NET; + + netHandler_offset = eventProcessor.allocate(sizeof(NetHandler)); + pollCont_offset = eventProcessor.allocate(sizeof(PollCont)); + + // etype is ET_NET for netProcessor + // and ET_SSL for sslNetProcessor + upgradeEtype(etype); + + n_netthreads = eventProcessor.n_threads_for_type[etype]; + netthreads = eventProcessor.eventthread[etype]; + for (int i = 0; i < n_netthreads; i++) { + initialize_thread_for_net(netthreads[i], i); + } + + if ((incoming_ip_to_bind = IOCORE_ConfigReadString("proxy.local.incoming_ip_to_bind")) != 0) + incoming_ip_to_bind_saddr = inet_addr(incoming_ip_to_bind); + else + incoming_ip_to_bind_saddr = 0; + + RecData d; + d.rec_int = 0; + change_net_connections_throttle(NULL, RECD_INT, d, NULL); + + // Socks +#ifndef INK_NO_SOCKS + if (!netProcessor.socks_conf_stuff) { + socks_conf_stuff = NEW(new socks_conf_struct); + loadSocksConfiguration(socks_conf_stuff); + if (!socks_conf_stuff->socks_needed && socks_conf_stuff->accept_enabled) { + Warning("We can not have accept_enabled and socks_needed turned off" " disabling Socks accept\n"); + socks_conf_stuff->accept_enabled = 0; + } else { + // this is sslNetprocessor + socks_conf_stuff = netProcessor.socks_conf_stuff; + } + } +#endif /*INK_NO_SOCKS */ + // commented by vijay - bug 2489945 + /*if (use_accept_thread) // 0 + { NetAccept * na = createNetAccept(); + SET_CONTINUATION_HANDLER(na,&NetAccept::acceptLoopEvent); + accept_thread_event = eventProcessor.spawn_thread(na); + if (!accept_thread_event) delete na; + } */ + + +/* + * Stat pages + */ +#ifdef NON_MODULAR + extern Action *register_ShowNet(Continuation * c, HTTPHdr * h); + if (etype == ET_NET) + statPagesManager.register_http("net", register_ShowNet); +#endif + return 1; +} + +// Functions all THREAD_FREE and THREAD_ALLOC to be performed +// for both SSL and regular UnixNetVConnection transparent to +// netProcessor connect functions. Yes it looks goofy to +// have them in both places, but it saves a bunch of +// code from being duplicated. +UnixNetVConnection * +UnixNetProcessor::allocateThread(EThread * t) +{ + return ((UnixNetVConnection *) THREAD_ALLOC(netVCAllocator, t)); +} + +void +UnixNetProcessor::freeThread(UnixNetVConnection * vc, EThread * t) +{ + ink_assert(!vc->from_accept_thread); + THREAD_FREE(vc, netVCAllocator, t); +} + +// Virtual function allows creation of an +// SSLNetAccept or NetAccept transparent to NetProcessor. +NetAccept * +UnixNetProcessor::createNetAccept() +{ + return (NEW(new NetAccept)); +} + +struct socks_conf_struct * +NetProcessor::socks_conf_stuff = NULL; +int NetProcessor::accept_mss = 0; + +UnixNetProcessor unix_netProcessor; +NetProcessor & netProcessor = unix_netProcessor; diff --git a/iocore/net/UnixNetVConnection.cc b/iocore/net/UnixNetVConnection.cc new file mode 100644 index 00000000..d99e226a --- /dev/null +++ b/iocore/net/UnixNetVConnection.cc @@ -0,0 +1,1129 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" + +#define STATE_VIO_OFFSET ((uintptr_t)&((NetState*)0)->vio) +#define STATE_FROM_VIO(_x) ((NetState*)(((char*)(_x)) - STATE_VIO_OFFSET)) + +#define disable_read(_vc) (_vc)->read.enabled = 0 +#define disable_write(_vc) (_vc)->write.enabled = 0 +#define enable_read(_vc) (_vc)->read.enabled = 1 +#define enable_write(_vc) (_vc)->write.enabled = 1 + +typedef struct iovec IOVec; +#ifndef UIO_MAXIOV +#define NET_MAX_IOV 16 // UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1) +#else +#define NET_MAX_IOV UIO_MAXIOV +#endif + +// Global +ClassAllocator netVCAllocator("netVCAllocator"); + +// +// Reschedule a UnixNetVConnection by moving it +// onto or off of the ready_list +// +static inline void +read_reschedule(NetHandler *nh, UnixNetVConnection *vc) +{ + vc->ep.refresh(EVENTIO_READ); + if (vc->read.triggered && vc->read.enabled) { + nh->read_ready_list.in_or_enqueue(vc); + } else + nh->read_ready_list.remove(vc); +} + +static inline void +write_reschedule(NetHandler *nh, UnixNetVConnection *vc) +{ + vc->ep.refresh(EVENTIO_WRITE); + if (vc->write.triggered && vc->write.enabled) { + nh->write_ready_list.in_or_enqueue(vc); + } else + nh->write_ready_list.remove(vc); +} + +void +net_activity(UnixNetVConnection *vc, EThread *thread) +{ + (void) thread; +#ifdef INACTIVITY_TIMEOUT + if (vc->inactivity_timeout && vc->inactivity_timeout_in && vc->inactivity_timeout->ethread == thread) + vc->inactivity_timeout->schedule_in(vc->inactivity_timeout_in); + else { + if (vc->inactivity_timeout) + vc->inactivity_timeout->cancel_action(); + if (vc->inactivity_timeout_in) { + vc->inactivity_timeout = vc->thread->schedule_in_local(vc, vc->inactivity_timeout_in); + } else + vc->inactivity_timeout = 0; + } +#else + if (vc->inactivity_timeout_in) + vc->next_inactivity_timeout_at = ink_get_hrtime() + vc->inactivity_timeout_in; + else + vc->next_inactivity_timeout_at = 0; +#endif + +} + +// +// Function used to close a UnixNetVConnection and free the vc +// +void +close_UnixNetVConnection(UnixNetVConnection *vc, EThread *t) +{ + NetHandler *nh = vc->nh; + vc->cancel_OOB(); + vc->ep.stop(); + vc->con.close(); +#ifdef INACTIVITY_TIMEOUT + if (vc->inactivity_timeout) { + vc->inactivity_timeout->cancel_action(vc); + vc->inactivity_timeout = NULL; + } +#else + vc->next_inactivity_timeout_at = 0; +#endif + vc->inactivity_timeout_in = 0; + if (vc->active_timeout) { + vc->active_timeout->cancel_action(vc); + vc->active_timeout = NULL; + } + vc->active_timeout_in = 0; + nh->open_list.remove(vc); + nh->cop_list.remove(vc); + nh->read_ready_list.remove(vc); + nh->write_ready_list.remove(vc); + if (vc->read.in_enabled_list) { + nh->read_enable_list.remove(vc); + vc->read.in_enabled_list = 0; + } + if (vc->write.in_enabled_list) { + nh->write_enable_list.remove(vc); + vc->write.in_enabled_list = 0; + } + vc->free(t); +} + +// +// Signal an event +// +static inline int +read_signal_and_update(int event, UnixNetVConnection *vc) +{ + vc->recursion++; + vc->read.vio._cont->handleEvent(event, &vc->read.vio); + if (!--vc->recursion && vc->closed) { + /* BZ 31932 */ + ink_debug_assert(vc->thread == this_ethread()); + close_UnixNetVConnection(vc, vc->thread); + return EVENT_DONE; + } else { + return EVENT_CONT; + } +} + +static inline int +write_signal_and_update(int event, UnixNetVConnection *vc) +{ + vc->recursion++; + vc->write.vio._cont->handleEvent(event, &vc->write.vio); + if (!--vc->recursion && vc->closed) { + /* BZ 31932 */ + ink_debug_assert(vc->thread == this_ethread()); + close_UnixNetVConnection(vc, vc->thread); + return EVENT_DONE; + } else { + return EVENT_CONT; + } +} + +static inline int +read_signal_done(int event, NetHandler *nh, UnixNetVConnection *vc) +{ + vc->read.enabled = 0; + if (read_signal_and_update(event, vc) == EVENT_DONE) { + return EVENT_DONE; + } else { + read_reschedule(nh, vc); + return EVENT_CONT; + } +} + +static inline int +write_signal_done(int event, NetHandler *nh, UnixNetVConnection *vc) +{ + vc->write.enabled = 0; + if (write_signal_and_update(event, vc) == EVENT_DONE) { + return EVENT_DONE; + } else { + write_reschedule(nh, vc); + return EVENT_CONT; + } +} + +static inline int +read_signal_error(NetHandler *nh, UnixNetVConnection *vc, int lerrno) +{ + vc->lerrno = lerrno; + return read_signal_done(VC_EVENT_ERROR, nh, vc); +} + +static inline int +write_signal_error(NetHandler *nh, UnixNetVConnection *vc, int lerrno) +{ + vc->lerrno = lerrno; + return write_signal_done(VC_EVENT_ERROR, nh, vc); +} + +// Read the data for a UnixNetVConnection. +// Rescheduling the UnixNetVConnection by moving the VC +// onto or off of the ready_list. +// Had to wrap this function with net_read_io for SSL. +static void +read_from_net(NetHandler *nh, UnixNetVConnection *vc, EThread *thread) +{ + NetState *s = &vc->read; + ProxyMutex *mutex = thread->mutex; + MIOBufferAccessor & buf = s->vio.buffer; + int64_t r = 0; + + MUTEX_TRY_LOCK_FOR(lock, s->vio.mutex, thread, s->vio._cont); + + if (!lock || lock.m.m_ptr != s->vio.mutex.m_ptr) { + read_reschedule(nh, vc); + return; + } + // if it is not enabled. + if (!s->enabled || s->vio.op != VIO::READ) { + read_disable(nh, vc); + return; + } + + ink_debug_assert(buf.writer()); + + // if there is nothing to do, disable connection + int64_t ntodo = s->vio.ntodo(); + if (ntodo <= 0) { + read_disable(nh, vc); + return; + } + int64_t toread = buf.writer()->write_avail(); + if (toread > ntodo) + toread = ntodo; + + // read data + int64_t rattempted = 0, total_read = 0; + int niov = 0; + IOVec tiovec[NET_MAX_IOV]; + if (toread) { + IOBufferBlock *b = buf.mbuf->_writer; + do { + niov = 0; + rattempted = 0; + while (b && niov < NET_MAX_IOV) { + int64_t a = b->write_avail(); + if (a > 0) { + tiovec[niov].iov_base = b->_end; + int64_t togo = toread - total_read - rattempted; + if (a > togo) + a = togo; + tiovec[niov].iov_len = a; + rattempted += a; + niov++; + if (a >= togo) + break; + } + b = b->next; + } + if (niov == 1) { + r = socketManager.read(vc->con.fd, tiovec[0].iov_base, tiovec[0].iov_len); + } else { + r = socketManager.readv(vc->con.fd, &tiovec[0], niov); + } + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_read_stat, 1); + total_read += rattempted; + } while (r == rattempted && total_read < toread); + + // if we have already moved some bytes successfully, summarize in r + if (total_read != rattempted) { + if (r <= 0) + r = total_read - rattempted; + else + r = total_read - rattempted + r; + } + // check for errors + if (r <= 0) { + + if (r == -EAGAIN || r == -ENOTCONN) { + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_read_nodata_stat, 1); + vc->read.triggered = 0; + nh->read_ready_list.remove(vc); + return; + } + + if (!r || r == -ECONNRESET) { + vc->read.triggered = 0; + nh->read_ready_list.remove(vc); + read_signal_done(VC_EVENT_EOS, nh, vc); + return; + } + vc->read.triggered = 0; + read_signal_error(nh, vc, (int)-r); + return; + } + NET_SUM_DYN_STAT(net_read_bytes_stat, r); + + // Add data to buffer and signal continuation. + buf.writer()->fill(r); +#ifdef DEBUG + if (buf.writer()->write_avail() <= 0) + Debug("iocore_net", "read_from_net, read buffer full"); +#endif + s->vio.ndone += r; + net_activity(vc, thread); + } else + r = 0; + + // Signal read ready, check if user is not done + if (r) { + // If there are no more bytes to read, signal read complete + ink_assert(ntodo >= 0); + if (s->vio.ntodo() <= 0) { + read_signal_done(VC_EVENT_READ_COMPLETE, nh, vc); + Debug("iocore_net", "read_from_net, read finished - signal done"); + return; + } else { + if (read_signal_and_update(VC_EVENT_READ_READY, vc) != EVENT_CONT) + return; + // change of lock... don't look at shared variables! + if (lock.m.m_ptr != s->vio.mutex.m_ptr) { + read_reschedule(nh, vc); + return; + } + } + } + // If here are is no more room, or nothing to do, disable the connection + if (!s->enabled || !buf.writer()->write_avail() || s->vio.ntodo() <= 0) { + read_disable(nh, vc); + return; + } + + read_reschedule(nh, vc); +} + + +// +// Write the data for a UnixNetVConnection. +// Rescheduling the UnixNetVConnection when necessary. +// +void +write_to_net(NetHandler *nh, UnixNetVConnection *vc, PollDescriptor *pd, EThread *thread) +{ + NOWARN_UNUSED(pd); + ProxyMutex *mutex = thread->mutex; + + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_writetonet_stat, 1); + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_writetonet_afterpoll_stat, 1); + + write_to_net_io(nh, vc, thread); +} + + +void +write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread) +{ + NetState *s = &vc->write; + ProxyMutex *mutex = thread->mutex; + + MUTEX_TRY_LOCK_FOR(lock, s->vio.mutex, thread, s->vio._cont); + + if (!lock || lock.m.m_ptr != s->vio.mutex.m_ptr) { + write_reschedule(nh, vc); + return; + } + + // This function will always return true unless + // vc is an SSLNetVConnection. + if (!vc->getSSLHandShakeComplete()) { + int err, ret; + + if (vc->getSSLClientConnection()) + ret = vc->sslStartHandShake(SSL_EVENT_CLIENT, err); + else + ret = vc->sslStartHandShake(SSL_EVENT_SERVER, err); + + if (ret == EVENT_ERROR) { + vc->write.triggered = 0; + write_signal_error(nh, vc, err); + } else if (ret == SSL_HANDSHAKE_WANT_READ || ret == SSL_HANDSHAKE_WANT_ACCEPT || ret == SSL_HANDSHAKE_WANT_CONNECT + || ret == SSL_HANDSHAKE_WANT_WRITE) { + vc->read.triggered = 0; + nh->read_ready_list.remove(vc); + vc->write.triggered = 0; + nh->write_ready_list.remove(vc); + } else if (ret == EVENT_DONE) { + vc->write.triggered = 1; + if (vc->write.enabled) + nh->write_ready_list.in_or_enqueue(vc); + } else + write_reschedule(nh, vc); + return; + } + // If it is not enabled,add to WaitList. + if (!s->enabled || s->vio.op != VIO::WRITE) { + write_disable(nh, vc); + return; + } + // If there is nothing to do, disable + int64_t ntodo = s->vio.ntodo(); + if (ntodo <= 0) { + write_disable(nh, vc); + return; + } + + MIOBufferAccessor & buf = s->vio.buffer; + ink_debug_assert(buf.writer()); + + // Calculate amount to write + int64_t towrite = buf.reader()->read_avail(); + if (towrite > ntodo) + towrite = ntodo; + int signalled = 0; + + // signal write ready to allow user to fill the buffer + if (towrite != ntodo && buf.writer()->write_avail()) { + if (write_signal_and_update(VC_EVENT_WRITE_READY, vc) != EVENT_CONT) { + return; + } + ntodo = s->vio.ntodo(); + if (ntodo <= 0) { + write_disable(nh, vc); + return; + } + signalled = 1; + // Recalculate amount to write + towrite = buf.reader()->read_avail(); + if (towrite > ntodo) + towrite = ntodo; + } + // if there is nothing to do, disable + ink_assert(towrite >= 0); + if (towrite <= 0) { + write_disable(nh, vc); + return; + } + + int64_t total_wrote = 0, wattempted = 0; + int64_t r = vc->load_buffer_and_write(towrite, wattempted, total_wrote, buf); + + // if we have already moved some bytes successfully, summarize in r + if (total_wrote != wattempted) { + if (r <= 0) + r = total_wrote - wattempted; + else + r = total_wrote - wattempted + r; + } + // check for errors + if (r <= 0) { // if the socket was not ready,add to WaitList + if (r == -EAGAIN || r == -ENOTCONN) { + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_write_nodata_stat, 1); + vc->write.triggered = 0; + nh->write_ready_list.remove(vc); + return; + } + if (!r || r == -ECONNRESET) { + vc->write.triggered = 0; + write_signal_done(VC_EVENT_EOS, nh, vc); + return; + } + vc->write.triggered = 0; + write_signal_error(nh, vc, (int)-r); + return; + } else { + NET_SUM_DYN_STAT(net_write_bytes_stat, r); + + // Remove data from the buffer and signal continuation. + ink_debug_assert(buf.reader()->read_avail() >= r); + buf.reader()->consume(r); + ink_debug_assert(buf.reader()->read_avail() >= 0); + s->vio.ndone += r; + + net_activity(vc, thread); + // If there are no more bytes to write, signal write complete, + ink_assert(ntodo >= 0); + if (s->vio.ntodo() <= 0) { + write_signal_done(VC_EVENT_WRITE_COMPLETE, nh, vc); + return; + } else if (!signalled) { + if (write_signal_and_update(VC_EVENT_WRITE_READY, vc) != EVENT_CONT) { + return; + } + // change of lock... don't look at shared variables! + if (lock.m.m_ptr != s->vio.mutex.m_ptr) { + write_reschedule(nh, vc); + return; + } + if (s->vio.ntodo() <= 0 || !buf.reader()->read_avail()) { + write_disable(nh, vc); + return; + } + } + + write_reschedule(nh, vc); + return; + } +} + + +VIO * +UnixNetVConnection::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + ink_assert(!closed); + read.vio.op = VIO::READ; + read.vio.mutex = c->mutex; + read.vio._cont = c; + read.vio.nbytes = nbytes; + read.vio.ndone = 0; + read.vio.vc_server = (VConnection *) this; + if (buf) { + read.vio.buffer.writer_for(buf); + if (nbytes && !read.enabled) + read.vio.reenable(); + } else { + read.vio.buffer.clear(); + disable_read(this); + } + return &read.vio; +} + +VIO * +UnixNetVConnection::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *reader, bool owner) +{ + ink_assert(!closed); + write.vio.op = VIO::WRITE; + write.vio.mutex = c->mutex; + write.vio._cont = c; + write.vio.nbytes = nbytes; + write.vio.ndone = 0; + write.vio.vc_server = (VConnection *) this; + if (reader) { + ink_assert(!owner); + write.vio.buffer.reader_for(reader); + if (nbytes && !write.enabled) + write.vio.reenable(); + } else { + write.vio.buffer.clear(); + disable_write(this); + } + return &write.vio; +} + +void +UnixNetVConnection::do_io_close(int alerrno /* = -1 */ ) +{ + disable_read(this); + disable_write(this); + read.vio.buffer.clear(); + read.vio.nbytes = 0; + read.vio.op = VIO::NONE; + write.vio.buffer.clear(); + write.vio.nbytes = 0; + write.vio.op = VIO::NONE; + + EThread *t = this_ethread(); + bool close_inline = !recursion && nh->mutex->thread_holding == t; + + INK_WRITE_MEMORY_BARRIER; + if (alerrno && alerrno != -1) + this->lerrno = alerrno; + if (alerrno == -1) + closed = 1; + else + closed = -1; + + if (close_inline) + close_UnixNetVConnection(this, t); +} + +void +UnixNetVConnection::do_io_shutdown(ShutdownHowTo_t howto) +{ + switch (howto) { + case IO_SHUTDOWN_READ: + socketManager.shutdown(((UnixNetVConnection *) this)->con.fd, 0); + disable_read(this); + read.vio.buffer.clear(); + read.vio.nbytes = 0; + f.shutdown = NET_VC_SHUTDOWN_READ; + break; + case IO_SHUTDOWN_WRITE: + socketManager.shutdown(((UnixNetVConnection *) this)->con.fd, 1); + disable_write(this); + write.vio.buffer.clear(); + write.vio.nbytes = 0; + f.shutdown = NET_VC_SHUTDOWN_WRITE; + break; + case IO_SHUTDOWN_READWRITE: + socketManager.shutdown(((UnixNetVConnection *) this)->con.fd, 2); + disable_read(this); + disable_write(this); + read.vio.buffer.clear(); + read.vio.nbytes = 0; + write.vio.buffer.clear(); + write.vio.nbytes = 0; + f.shutdown = NET_VC_SHUTDOWN_READ | NET_VC_SHUTDOWN_WRITE; + break; + default: + ink_assert(!"not reached"); + } +} + +int +OOB_callback::retry_OOB_send(int event, Event *e) +{ + (void) event; + (void) e; + ink_debug_assert(mutex->thread_holding == this_ethread()); + // the NetVC and the OOB_callback share a mutex + server_vc->oob_ptr = NULL; + server_vc->send_OOB(server_cont, data, length); + delete this; + return EVENT_DONE; +} + +void +UnixNetVConnection::cancel_OOB() +{ + UnixNetVConnection *u = (UnixNetVConnection *) this; + if (u->oob_ptr) { + if (u->oob_ptr->trigger) { + u->oob_ptr->trigger->cancel_action(); + u->oob_ptr->trigger = NULL; + } + delete u->oob_ptr; + u->oob_ptr = NULL; + } +} + +Action * +UnixNetVConnection::send_OOB(Continuation *cont, char *buf, int len) +{ + UnixNetVConnection *u = (UnixNetVConnection *) this; + ink_debug_assert(len > 0); + ink_debug_assert(buf); + ink_debug_assert(!u->oob_ptr); + int written; + ink_debug_assert(cont->mutex->thread_holding == this_ethread()); + written = socketManager.send(u->con.fd, buf, len, MSG_OOB); + if (written == len) { + cont->handleEvent(VC_EVENT_OOB_COMPLETE, NULL); + return ACTION_RESULT_DONE; + } else if (!written) { + cont->handleEvent(VC_EVENT_EOS, NULL); + return ACTION_RESULT_DONE; + } + if (written > 0 && written < len) { + u->oob_ptr = NEW(new OOB_callback(mutex, this, cont, buf + written, len - written)); + u->oob_ptr->trigger = mutex->thread_holding->schedule_in_local(u->oob_ptr, HRTIME_MSECONDS(10)); + return u->oob_ptr->trigger; + } else { + // should be a rare case : taking a new continuation should not be + // expensive for this + written = -errno; + ink_assert(written == -EAGAIN || written == -ENOTCONN); + u->oob_ptr = NEW(new OOB_callback(mutex, this, cont, buf, len)); + u->oob_ptr->trigger = mutex->thread_holding->schedule_in_local(u->oob_ptr, HRTIME_MSECONDS(10)); + return u->oob_ptr->trigger; + } +} + +// +// Function used to reenable the VC for reading or +// writing. +// +void +UnixNetVConnection::reenable(VIO *vio) +{ + if (STATE_FROM_VIO(vio)->enabled) + return; + set_enabled(vio); + if (!thread) + return; + EThread *t = vio->mutex->thread_holding; + ink_debug_assert(t == this_ethread()); + ink_debug_assert(!closed); + if (nh->mutex->thread_holding == t) { + if (vio == &read.vio) { + ep.modify(EVENTIO_READ); + ep.refresh(EVENTIO_READ); + if (read.triggered) + nh->read_ready_list.in_or_enqueue(this); + else + nh->read_ready_list.remove(this); + } else { + ep.modify(EVENTIO_WRITE); + ep.refresh(EVENTIO_WRITE); + if (write.triggered) + nh->write_ready_list.in_or_enqueue(this); + else + nh->write_ready_list.remove(this); + } + } else { + MUTEX_TRY_LOCK(lock, nh->mutex, t); + if (!lock) { + if (vio == &read.vio) { + if (!read.in_enabled_list) { + read.in_enabled_list = 1; + nh->read_enable_list.push(this); + } + } else { + if (!write.in_enabled_list) { + write.in_enabled_list = 1; + nh->write_enable_list.push(this); + } + } + if (nh->trigger_event && nh->trigger_event->ethread->signal_hook) + nh->trigger_event->ethread->signal_hook(nh->trigger_event->ethread); + } else { + if (vio == &read.vio) { + ep.modify(EVENTIO_READ); + ep.refresh(EVENTIO_READ); + if (read.triggered) + nh->read_ready_list.in_or_enqueue(this); + else + nh->read_ready_list.remove(this); + } else { + ep.modify(EVENTIO_WRITE); + ep.refresh(EVENTIO_WRITE); + if (write.triggered) + nh->write_ready_list.in_or_enqueue(this); + else + nh->write_ready_list.remove(this); + } + } + } +} + +void +UnixNetVConnection::reenable_re(VIO *vio) +{ + if (!thread) + return; + EThread *t = vio->mutex->thread_holding; + ink_debug_assert(t == this_ethread()); + if (nh->mutex->thread_holding == t) { + set_enabled(vio); + if (vio == &read.vio) { + ep.modify(EVENTIO_READ); + ep.refresh(EVENTIO_READ); + if (read.triggered) + net_read_io(nh, t); + else + nh->read_ready_list.remove(this); + } else { + ep.modify(EVENTIO_WRITE); + ep.refresh(EVENTIO_WRITE); + if (write.triggered) + write_to_net(nh, this, NULL, t); + else + nh->write_ready_list.remove(this); + } + } else + reenable(vio); +} + + +UnixNetVConnection::UnixNetVConnection() + : closed(0), inactivity_timeout_in(0), active_timeout_in(0), +#ifdef INACTIVITY_TIMEOUT + inactivity_timeout(NULL), +#else + next_inactivity_timeout_at(0), +#endif + active_timeout(NULL), nh(NULL), + id(0), ip(0), accept_port(0), port(0), flags(0), recursion(0), submit_time(0), oob_ptr(0), + from_accept_thread(false) +{ + memset(&local_sa, 0, sizeof local_sa); + SET_HANDLER((NetVConnHandler) & UnixNetVConnection::startEvent); +} + +// Private methods + +void +UnixNetVConnection::set_enabled(VIO *vio) +{ + ink_debug_assert(vio->mutex->thread_holding == this_ethread()); + ink_assert(!closed); + STATE_FROM_VIO(vio)->enabled = 1; +#ifdef INACTIVITY_TIMEOUT + if (!inactivity_timeout && inactivity_timeout_in) + inactivity_timeout = vio->mutex->thread_holding->schedule_in_local(this, inactivity_timeout_in); +#else + if (!next_inactivity_timeout_at && inactivity_timeout_in) + next_inactivity_timeout_at = ink_get_hrtime() + inactivity_timeout_in; +#endif +} + +void +UnixNetVConnection::net_read_io(NetHandler *nh, EThread *lthread) +{ + read_from_net(nh, this, lthread); +} + +// This code was pulled out of write_to_net so +// I could overwrite it for the SSL implementation +// (SSL read does not support overlapped i/o) +// without duplicating all the code in write_to_net. +int64_t +UnixNetVConnection::load_buffer_and_write(int64_t towrite, int64_t &wattempted, int64_t &total_wrote, MIOBufferAccessor & buf) +{ + int64_t r = 0; + int64_t offset = buf.entry->start_offset; + IOBufferBlock *b = buf.entry->block; + do { + IOVec tiovec[NET_MAX_IOV]; + int niov = 0; + int64_t total_wrote_last = total_wrote; + while (b && niov < NET_MAX_IOV) { + // check if we have done this block + int64_t l = b->read_avail(); + l -= offset; + if (l <= 0) { + offset = -l; + b = b->next; + continue; + } + // check if to amount to write exceeds that in this buffer + int64_t wavail = towrite - total_wrote; + if (l > wavail) + l = wavail; + if (!l) + break; + total_wrote += l; + // build an iov entry + tiovec[niov].iov_len = l; + tiovec[niov].iov_base = b->start() + offset; + niov++; + // on to the next block + offset = 0; + b = b->next; + } + wattempted = total_wrote - total_wrote_last; + if (niov == 1) + r = socketManager.write(con.fd, tiovec[0].iov_base, tiovec[0].iov_len); + else + r = socketManager.writev(con.fd, &tiovec[0], niov); + ProxyMutex *mutex = thread->mutex; + NET_DEBUG_COUNT_DYN_STAT(net_calls_to_write_stat, 1); + } while (r == wattempted && total_wrote < towrite); + + return (r); +} + +void +UnixNetVConnection::readDisable(NetHandler *nh) +{ + read_disable(nh, this); +} + +void +UnixNetVConnection::readSignalError(NetHandler *nh, int err) +{ + read_signal_error(nh, this, err); +} + +int +UnixNetVConnection::readSignalDone(int event, NetHandler *nh) +{ + return (read_signal_done(event, nh, this)); +} + + +int +UnixNetVConnection::readSignalAndUpdate(int event) +{ + return (read_signal_and_update(event, this)); +} + +// Interface so SSL inherited class can call some static in-line functions +// without affecting regular net stuff or copying a bunch of code into +// the header files. +void +UnixNetVConnection::readReschedule(NetHandler *nh) +{ + read_reschedule(nh, this); +} + +void +UnixNetVConnection::writeReschedule(NetHandler *nh) +{ + write_reschedule(nh, this); +} + +void +UnixNetVConnection::netActivity(EThread *lthread) +{ + net_activity(this, lthread); +} + +int +UnixNetVConnection::startEvent(int event, Event *e) +{ + (void) event; + MUTEX_TRY_LOCK(lock, action_.mutex, e->ethread); + MUTEX_TRY_LOCK(lock2, get_NetHandler(e->ethread)->mutex, e->ethread); + + if (!lock || !lock2) { + e->schedule_in(NET_RETRY_DELAY); + return EVENT_CONT; + } + if (!action_.cancelled) + connectUp(e->ethread); + else + free(e->ethread); + return EVENT_DONE; +} + +int +UnixNetVConnection::acceptEvent(int event, Event *e) +{ + (void) event; + thread = e->ethread; + MUTEX_TRY_LOCK(lock, action_.mutex, e->ethread); + MUTEX_TRY_LOCK(lock2, get_NetHandler(thread)->mutex, e->ethread); + if (!lock || !lock2) { + if (event == EVENT_NONE) { + thread->schedule_in(this, NET_RETRY_DELAY); + return EVENT_DONE; + } else { + e->schedule_in(NET_RETRY_DELAY); + return EVENT_CONT; + } + } + + if (action_.cancelled) { + free(thread); + return EVENT_DONE; + } + + SET_HANDLER((NetVConnHandler) & UnixNetVConnection::mainEvent); + + nh = get_NetHandler(thread); + PollDescriptor *pd = get_PollDescriptor(thread); + if (ep.start(pd, this, EVENTIO_READ|EVENTIO_WRITE) < 0) { + Debug("iocore_net", "acceptEvent : failed EventIO::start\n"); + close_UnixNetVConnection(this, e->ethread); + return EVENT_DONE; + } + + nh->open_list.enqueue(this); + + if (inactivity_timeout_in) + UnixNetVConnection::set_inactivity_timeout(inactivity_timeout_in); + if (active_timeout_in) + UnixNetVConnection::set_active_timeout(active_timeout_in); + action_.continuation->handleEvent(NET_EVENT_ACCEPT, this); + return EVENT_DONE; +} + +// +// The main event for UnixNetVConnections. +// This is called by the Event subsystem to initialize the UnixNetVConnection +// and for active and inactivity timeouts. +// +int +UnixNetVConnection::mainEvent(int event, Event *e) +{ + ink_debug_assert(event == EVENT_IMMEDIATE || event == EVENT_INTERVAL); + ink_debug_assert(thread == this_ethread()); + + MUTEX_TRY_LOCK(hlock, get_NetHandler(thread)->mutex, e->ethread); + MUTEX_TRY_LOCK(rlock, read.vio.mutex ? (ProxyMutex *) read.vio.mutex : (ProxyMutex *) e->ethread->mutex, e->ethread); + MUTEX_TRY_LOCK(wlock, write.vio.mutex ? (ProxyMutex *) write.vio.mutex : + (ProxyMutex *) e->ethread->mutex, e->ethread); + if (!hlock || !rlock || !wlock || + (read.vio.mutex.m_ptr && rlock.m.m_ptr != read.vio.mutex.m_ptr) || + (write.vio.mutex.m_ptr && wlock.m.m_ptr != write.vio.mutex.m_ptr)) { +#ifndef INACTIVITY_TIMEOUT + if (e == active_timeout) +#endif + e->schedule_in(NET_RETRY_DELAY); + return EVENT_CONT; + } + if (e->cancelled) + return EVENT_DONE; + + int signal_event; + Event **signal_timeout; + Continuation *reader_cont = NULL; + Continuation *writer_cont = NULL; + ink_hrtime next_activity_timeout_at = 0; + ink_hrtime *signal_timeout_at = &next_activity_timeout_at; + Event *t = NULL; + signal_timeout = &t; + +#ifdef INACTIVITY_TIMEOUT + if (e == inactivity_timeout) { + signal_event = VC_EVENT_INACTIVITY_TIMEOUT; + signal_timeout = &inactivity_timeout; + } +#else + if (event == EVENT_IMMEDIATE) { + /* BZ 49408 */ + //ink_debug_assert(inactivity_timeout_in); + //ink_debug_assert(next_inactivity_timeout_at < ink_get_hrtime()); + if (!inactivity_timeout_in || next_inactivity_timeout_at > ink_get_hrtime()) + return EVENT_CONT; + signal_event = VC_EVENT_INACTIVITY_TIMEOUT; + signal_timeout_at = &next_inactivity_timeout_at; + } +#endif + else { + ink_debug_assert(e == active_timeout); + signal_event = VC_EVENT_ACTIVE_TIMEOUT; + signal_timeout = &active_timeout; + } + *signal_timeout = 0; + *signal_timeout_at = 0; + writer_cont = write.vio._cont; + + if (closed) { + close_UnixNetVConnection(this, thread); + return EVENT_DONE; + } + + if (read.vio.op == VIO::READ && !(f.shutdown & NET_VC_SHUTDOWN_READ)) { + reader_cont = read.vio._cont; + if (read_signal_and_update(signal_event, this) == EVENT_DONE) + return EVENT_DONE; + } + + if (!*signal_timeout && + !*signal_timeout_at && + !closed && write.vio.op == VIO::WRITE && + !(f.shutdown & NET_VC_SHUTDOWN_WRITE) && reader_cont != write.vio._cont && writer_cont == write.vio._cont) + if (write_signal_and_update(signal_event, this) == EVENT_DONE) + return EVENT_DONE; + return EVENT_DONE; +} + + +int +UnixNetVConnection::connectUp(EThread *t) +{ + thread = t; + if (check_net_throttle(CONNECT, submit_time)) { + check_throttle_warning(); + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *) -ENET_THROTTLING); + free(t); + return CONNECT_FAILURE; + } + // + // Initialize this UnixNetVConnection + // + int res = 0; + Debug("iocore_net", "connectUp:: local_addr=%u.%u.%u.%u [%s]\n", + PRINT_IP(options.local_addr), + NetVCOptions::toString(options.addr_binding) + ); + + + nh = get_NetHandler(t); + res = con.open(options); + if (0 == res) { + // Must connect after EventIO::Start() to avoid a race condition + // when edge triggering is used. + if (ep.start(get_PollDescriptor(t), this, EVENTIO_READ|EVENTIO_WRITE) < 0) { + lerrno = errno; + Debug("iocore_net", "connectUp : Failed to add to epoll list\n"); + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *)0); // 0 == res + free(t); + return CONNECT_FAILURE; + } + res = con.connect(ip, port, options); + } + + if (res) { + lerrno = errno; + action_.continuation->handleEvent(NET_EVENT_OPEN_FAILED, (void *)(intptr_t)res); + free(t); + return CONNECT_FAILURE; + } + check_emergency_throttle(con); + + // start up next round immediately + + SET_HANDLER(&UnixNetVConnection::mainEvent); + // This function is empty for regular UnixNetVConnection, it has code + // in it for the inherited SSLUnixNetVConnection. Allows the connectUp + // function code not to be duplicated in the inherited SSL class. + // sslStartHandShake (SSL_EVENT_CLIENT, err); + + nh->open_list.enqueue(this); + + ink_assert(!inactivity_timeout_in); + ink_assert(!active_timeout_in); + action_.continuation->handleEvent(NET_EVENT_OPEN, this); + return CONNECT_SUCCESS; +} + + +void +UnixNetVConnection::free(EThread *t) +{ + NET_SUM_GLOBAL_DYN_STAT(net_connections_currently_open_stat, -1); + // clear variables for reuse + got_remote_addr = 0; + got_local_addr = 0; + read.vio.mutex.clear(); + write.vio.mutex.clear(); + action_.mutex.clear(); + this->mutex.clear(); + flags = 0; + accept_port = 0; + SET_CONTINUATION_HANDLER(this, (NetVConnHandler) & UnixNetVConnection::startEvent); + nh = NULL; + read.triggered = 0; + write.triggered = 0; + options.reset(); + closed = 0; + ink_debug_assert(!read.ready_link.prev && !read.ready_link.next); + ink_debug_assert(!read.enable_link.next); + ink_debug_assert(!write.ready_link.prev && !write.ready_link.next); + ink_debug_assert(!write.enable_link.next); + ink_debug_assert(!link.next && !link.prev); + ink_debug_assert(!active_timeout); + ink_debug_assert(con.fd == NO_FD); + ink_debug_assert(t == this_ethread()); + + if (from_accept_thread) { + netVCAllocator.free(this); + } else { + THREAD_FREE(this, netVCAllocator, t); + } +} diff --git a/iocore/net/UnixUDPConnection.cc b/iocore/net/UnixUDPConnection.cc new file mode 100644 index 00000000..521a359f --- /dev/null +++ b/iocore/net/UnixUDPConnection.cc @@ -0,0 +1,157 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + UnixUDPConnection.cc + Unix UDPConnection implementation + + + ****************************************************************************/ + +#include "P_Net.h" + +UnixUDPConnection::~UnixUDPConnection() +{ + UDPPacketInternal *p = (UDPPacketInternal *) ink_atomiclist_popall(&inQueue); + + if (!tobedestroyed) + tobedestroyed = 1; + + if (p) { + UDPPacketInternal *pnext = NULL; + while (p) { + pnext = p->alink.next; + p->alink.next = NULL; + p->free(); + p = pnext; + } + } + if (callbackAction) { + callbackAction->cancel(); + callbackAction = NULL; + } + Debug("udpnet", "Destroying udp port = %d", getPortNum()); + if (fd != NO_FD) { + socketManager.close(fd); + } + fd = NO_FD; +} + +// called with continuation lock taken out +// We call Release because AddRef was called before entering here. +int +UnixUDPConnection::callbackHandler(int event, void *data) +{ + (void) event; + (void) data; + callbackAction = NULL; + if (continuation == NULL) + return EVENT_CONT; + + if (m_errno) { + if (!shouldDestroy()) + continuation->handleEvent(NET_EVENT_DATAGRAM_ERROR, this); + destroy(); // don't destroy until after calling back with error + Release(); + return EVENT_CONT; + } else { + UDPPacketInternal *p = (UDPPacketInternal *) ink_atomiclist_popall(&inQueue); + if (p) { + Debug("udpnet", "UDPConnection::callbackHandler"); + UDPPacketInternal *pnext = NULL; + Queue result; + while (p) { + pnext = p->alink.next; + p->alink.next = NULL; + result.push(p); + p = pnext; + } + if (!shouldDestroy()) + continuation->handleEvent(NET_EVENT_DATAGRAM_READ_READY, &result); + else { + while ((p = result.dequeue())) + p->free(); + } + } + } + Release(); + return EVENT_CONT; +} + +void +UDPConnection::bindToThread(Continuation * c) +{ + UnixUDPConnection *uc = (UnixUDPConnection *) this; + //add to new connections queue for EThread. + EThread *t = eventProcessor.assign_thread(ET_UDP); + ink_assert(t); + ink_assert(get_UDPNetHandler(t)); + uc->ethread = t; + AddRef(); + uc->continuation = c; + mutex = c->mutex; + ink_atomiclist_push(&get_UDPNetHandler(t)->udpNewConnections, uc); +} + +Action * +UDPConnection::send(Continuation * c, UDPPacket * xp) +{ + UDPPacketInternal *p = (UDPPacketInternal *) xp; + UnixUDPConnection *conn = (UnixUDPConnection *) this; + + if (shouldDestroy()) { + ink_assert(!"freeing packet sent on dead connection"); + p->free(); + return ACTION_RESULT_NONE; + } + + ink_assert(mutex == c->mutex); + p->setContinuation(c); + p->setConnection(this); + conn->continuation = c; + ink_assert(conn->continuation != NULL); + mutex = c->mutex; + p->reqGenerationNum = conn->sendGenerationNum; + get_UDPNetHandler(conn->ethread)->udpOutQueue.send(p); + return ACTION_RESULT_NONE; +} + +void +UDPConnection::Release() +{ + UnixUDPConnection *p = (UnixUDPConnection *) this; + + p->ep.stop(); + + if (ink_atomic_increment(&p->refcount, -1) == 1) { + ink_debug_assert(p->callback_link.next == NULL); + ink_debug_assert(p->callback_link.prev == NULL); + ink_debug_assert(p->polling_link.next == NULL); + ink_debug_assert(p->polling_link.prev == NULL); + ink_debug_assert(p->newconn_alink.next == NULL); + + delete this; + } +} + diff --git a/iocore/net/UnixUDPNet.cc b/iocore/net/UnixUDPNet.cc new file mode 100644 index 00000000..b98ae865 --- /dev/null +++ b/iocore/net/UnixUDPNet.cc @@ -0,0 +1,1417 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + UnixUDPNet.cc + UDPNet implementation + + + ****************************************************************************/ + +#include "P_Net.h" + +typedef int (UDPNetHandler::*UDPNetContHandler) (int, void *); + +inkcoreapi ClassAllocator udpPacketAllocator("udpPacketAllocator"); + +inkcoreapi ClassAllocator udpWorkContinuationAllocator("udpWorkContinuationAllocator"); + +EventType ET_UDP; + +#if defined(linux) && !defined(DEBUG) +#define NODIAGS +#endif + +// +// Global Data +// + +UDPNetProcessorInternal udpNetInternal; +UDPNetProcessor &udpNet = udpNetInternal; + +uint64_t g_udp_bytesPending; +int32_t g_udp_periodicCleanupSlots; +int32_t g_udp_periodicFreeCancelledPkts; +int32_t g_udp_numSendRetries; + +#include "P_LibBulkIO.h" +void *G_bulkIOState = NULL; + +// +// Public functions +// See header for documentation +// + +InkPipeInfo G_inkPipeInfo; + +int G_bwGrapherFd; +struct sockaddr_in G_bwGrapherLoc; + +void +initialize_thread_for_udp_net(EThread * thread) +{ + new((ink_dummy_for_new *) get_UDPPollCont(thread)) PollCont(thread->mutex); + new((ink_dummy_for_new *) get_UDPNetHandler(thread)) UDPNetHandler; + +#if TS_USE_LIBEV + PollCont *pc = get_UDPPollCont(thread); + PollDescriptor *pd = pc->pollDescriptor; + pd->eio = ev_loop_new(LIBEV_BACKEND_LIST); +#endif + // These are hidden variables that control the amount of memory used by UDP + // packets. As usual, defaults are in RecordsConfig.cc + + // This variable controls how often we cleanup the cancelled packets. + // If it is set to 0, then cleanup never occurs. + REC_ReadConfigInt32(g_udp_periodicFreeCancelledPkts, "proxy.config.udp.free_cancelled_pkts_sec"); + // This variable controls how many "slots" of the udp calendar queue we cleanup. + // If it is set to 0, then cleanup never occurs. This value makes sense + // only if the above variable is set. + REC_ReadConfigInt32(g_udp_periodicFreeCancelledPkts, "proxy.config.udp.periodic_cleanup"); + + // UDP sends can fail with errno=EAGAIN. This variable determines the # of + // times the UDP thread retries before giving up. Set to 0 to keep trying forever. + REC_ReadConfigInt32(g_udp_numSendRetries, "proxy.config.udp.send_retries"); + g_udp_numSendRetries = g_udp_numSendRetries < 0 ? 0 : g_udp_numSendRetries; + + thread->schedule_every(get_UDPPollCont(thread), -9); + thread->schedule_imm(get_UDPNetHandler(thread)); + Debug("bulk-io", "%s bulk-io for sends", G_bulkIOState ? "Using" : "Not using"); +} + +int +UDPNetProcessorInternal::start(int n_upd_threads) +{ + if (n_upd_threads < 1) + return -1; + + ET_UDP = eventProcessor.spawn_event_threads(n_upd_threads, "ET_UDP"); + if (ET_UDP < 0) // Probably can't happen, maybe at some point EventType should be unsigned ? + return -1; + + pollCont_offset = eventProcessor.allocate(sizeof(PollCont)); + udpNetHandler_offset = eventProcessor.allocate(sizeof(UDPNetHandler)); + + for (int i = 0; i < eventProcessor.n_threads_for_type[ET_UDP]; i++) + initialize_thread_for_udp_net(eventProcessor.eventthread[ET_UDP][i]); + + return 0; +} + +void +UDPNetProcessorInternal::udp_read_from_net(UDPNetHandler * nh, + UDPConnection * xuc, PollDescriptor * pd, EThread * thread) +{ + NOWARN_UNUSED(pd); + (void) thread; + UnixUDPConnection *uc = (UnixUDPConnection *) xuc; + + // receive packet and queue onto UDPConnection. + // don't call back connection at this time. + int r; + int iters = 0; + do { + struct sockaddr_in fromaddr; + socklen_t fromlen = sizeof(fromaddr); + // XXX: want to be 0 copy. + // XXX: really should read into next contiguous region of an IOBufferData + // which gets referenced by IOBufferBlock. + char buf[65536]; + int buflen = sizeof(buf); + r = socketManager.recvfrom(uc->getFd(), buf, buflen, 0, (struct sockaddr *) &fromaddr, &fromlen); + if (r <= 0) { + // error + break; + } + // create packet + UDPPacket *p = new_incoming_UDPPacket(&fromaddr, buf, r); + p->setConnection(uc); + // XXX: is this expensive? I] really want to know this information + p->setArrivalTime(ink_get_hrtime_internal()); + // queue onto the UDPConnection + ink_atomiclist_push(&uc->inQueue, p); + iters++; + } while (r > 0); + if (iters >= 1) { + Debug("udp-read", "read %d at a time", iters); + } + // if not already on to-be-called-back queue, then add it. + if (!uc->onCallbackQueue) { + ink_assert(uc->callback_link.next == NULL); + ink_assert(uc->callback_link.prev == NULL); + uc->AddRef(); + nh->udp_callbacks.enqueue(uc); + uc->onCallbackQueue = 1; + } +} + + +int +UDPNetProcessorInternal::udp_callback(UDPNetHandler * nh, UDPConnection * xuc, EThread * thread) +{ + (void) nh; + UnixUDPConnection *uc = (UnixUDPConnection *) xuc; + + if (uc->continuation && uc->mutex) { + MUTEX_TRY_LOCK_FOR(lock, uc->mutex, thread, uc->continuation); + if (!lock) { + return 1; + } + uc->AddRef(); + uc->callbackHandler(0, 0); + return 0; + } else { + ink_assert(!"doesn't reach here"); + if (!uc->callbackAction) { + uc->AddRef(); + uc->callbackAction = eventProcessor.schedule_imm(uc); + } + return 0; + } +} + +// cheesy implementation of a asynchronous read and callback for Unix +class UDPReadContinuation:public Continuation +{ +public: + UDPReadContinuation(Event * completionToken); + UDPReadContinuation(); + ~UDPReadContinuation(); + inline void free(void); + inline void init_token(Event * completionToken); + + inline void init_read(int fd, IOBufferBlock * buf, int len, struct sockaddr *fromaddr, socklen_t *fromaddrlen); // start up polling + void set_timer(int seconds) + { + timeout_interval = HRTIME_SECONDS(seconds); + } + void cancel(); + int readPollEvent(int event, Event * e); + Action *getAction() + { + return event; + } + void setupPollDescriptor(); + +private: + Event * event; // the completion event token created + // on behalf of the client + Ptr readbuf; + int readlen; + struct sockaddr *fromaddr; + socklen_t *fromaddrlen; + int fd; // fd we are reading from + int ifd; // poll fd index + ink_hrtime period; // polling period + ink_hrtime elapsed_time; + ink_hrtime timeout_interval; +}; + +ClassAllocator udpReadContAllocator("udpReadContAllocator"); + +UDPReadContinuation::UDPReadContinuation(Event * completionToken) +: Continuation(NULL), event(completionToken), readbuf(NULL), + readlen(0), fromaddrlen(0), fd(-1), ifd(-1), period(0), elapsed_time(0), timeout_interval(0) +{ + if (completionToken->continuation) + this->mutex = completionToken->continuation->mutex; + else + this->mutex = new_ProxyMutex(); +} + +UDPReadContinuation::UDPReadContinuation() +: Continuation(NULL), event(0), readbuf(NULL), + readlen(0), fromaddrlen(0), fd(-1), ifd(-1), period(0), elapsed_time(0), timeout_interval(0) +{ +} + +inline void +UDPReadContinuation::free(void) +{ + ink_assert(event != NULL); + completionUtil::destroy(event); + event = NULL; + readbuf = NULL; + readlen = 0; + fromaddrlen = 0; + fd = -1; + ifd = -1; + period = 0; + elapsed_time = 0; + timeout_interval = 0; + mutex = NULL; + udpReadContAllocator.free(this); +} + +inline void +UDPReadContinuation::init_token(Event * completionToken) +{ + if (completionToken->continuation) { + this->mutex = completionToken->continuation->mutex; + } else { + this->mutex = new_ProxyMutex(); + } + event = completionToken; +} + +inline void +UDPReadContinuation::init_read(int rfd, IOBufferBlock * buf, int len, struct sockaddr *fromaddr_, socklen_t *fromaddrlen_) +{ + ink_assert(rfd >= 0 && buf != NULL && fromaddr_ != NULL && fromaddrlen_ != NULL); + fd = rfd; + readbuf = buf; + readlen = len; + fromaddr = fromaddr_; + fromaddrlen = fromaddrlen_; + SET_HANDLER(&UDPReadContinuation::readPollEvent); + period = NET_PERIOD; + setupPollDescriptor(); + this_ethread()->schedule_every(this, period); +} + +UDPReadContinuation::~UDPReadContinuation() +{ + ink_assert(event != NULL); + completionUtil::destroy(event); + event = NULL; +} + +void +UDPReadContinuation::cancel() +{ + // I don't think this actually cancels it correctly right now. + event->cancel(); +} + +void +UDPReadContinuation::setupPollDescriptor() +{ +#if TS_USE_EPOLL + Pollfd *pfd; + EThread *et = (EThread *) this_thread(); + PollCont *pc = get_PollCont(et); + pfd = pc->nextPollDescriptor->alloc(); + pfd->fd = fd; + ifd = pfd - pc->nextPollDescriptor->pfd; + ink_assert(pc->nextPollDescriptor->nfds > ifd); + pfd->events = POLLIN; + pfd->revents = 0; +#endif +} + +int +UDPReadContinuation::readPollEvent(int event_, Event * e) +{ + (void) event_; + (void) e; + + //PollCont *pc = get_PollCont(e->ethread); + Continuation *c; + + if (event->cancelled) { + e->cancel(); + free(); + // delete this; + return EVENT_DONE; + } + // See if the request has timed out + if (timeout_interval) { + elapsed_time += -period; + if (elapsed_time >= timeout_interval) { + c = completionUtil::getContinuation(event); + // TODO: Should we deal with the return code? + c->handleEvent(NET_EVENT_DATAGRAM_READ_ERROR, event); + e->cancel(); + free(); + // delete this; + return EVENT_DONE; + } + } + //ink_assert(ifd < 0 || event_ == EVENT_INTERVAL || (event_ == EVENT_POLL && pc->pollDescriptor->nfds > ifd && pc->pollDescriptor->pfd[ifd].fd == fd)); + //if (ifd < 0 || event_ == EVENT_INTERVAL || (pc->pollDescriptor->pfd[ifd].revents & POLLIN)) { + ink_debug_assert(!"incomplete"); + c = completionUtil::getContinuation(event); + // do read + socklen_t tmp_fromlen = *fromaddrlen; + int rlen = socketManager.recvfrom(fd, readbuf->end(), readlen, + 0, // default flags + fromaddr, &tmp_fromlen); + completionUtil::setThread(event, e->ethread); + // call back user with their event + if (rlen > 0) { + // do callback if read is successful + *fromaddrlen = tmp_fromlen; + completionUtil::setInfo(event, fd, readbuf, rlen, errno); + readbuf->fill(rlen); + // TODO: Should we deal with the return code? + c->handleEvent(NET_EVENT_DATAGRAM_READ_COMPLETE, event); + e->cancel(); + free(); + // delete this; + return EVENT_DONE; + } else if (rlen < 0 && rlen != -EAGAIN) { + // signal error. + *fromaddrlen = tmp_fromlen; + completionUtil::setInfo(event, fd, (IOBufferBlock *) readbuf, rlen, errno); + c = completionUtil::getContinuation(event); + // TODO: Should we deal with the return code? + c->handleEvent(NET_EVENT_DATAGRAM_READ_ERROR, event); + e->cancel(); + free(); + //delete this; + return EVENT_DONE; + } else { + completionUtil::setThread(event, NULL); + } +//} + if (event->cancelled) { + e->cancel(); + free(); + //delete this; + return EVENT_DONE; + } + // reestablish poll + setupPollDescriptor(); + + return EVENT_CONT; +} + +/* recvfrom: + * Unix: + * assert(buf->write_avail() >= len); + * *actual_len = recvfrom(fd,addr,buf->end(),len) + * if successful then + * buf->fill(*actual_len); + * return ACTION_RESULT_DONE + * else if nothing read + * *actual_len is 0 + * create "UDP read continuation" C with 'cont's lock + * set user callback to 'cont' + * return C's action. + * else + * return error; + */ +Action * +UDPNetProcessor::recvfrom_re(Continuation * cont, + void *token, + int fd, + struct sockaddr * fromaddr, socklen_t *fromaddrlen, + IOBufferBlock * buf, int len, bool useReadCont, int timeout) +{ + (void) useReadCont; + ink_assert(buf->write_avail() >= len); + int actual; + Event *event = completionUtil::create(); + completionUtil::setContinuation(event, cont); + completionUtil::setHandle(event, token); + actual = socketManager.recvfrom(fd, buf->end(), len, 0, // default flags + fromaddr, fromaddrlen); + if (actual > 0) { + completionUtil::setThread(event, this_ethread()); + completionUtil::setInfo(event, fd, buf, actual, errno); + buf->fill(actual); + cont->handleEvent(NET_EVENT_DATAGRAM_READ_COMPLETE, event); + completionUtil::destroy(event); + return ACTION_RESULT_DONE; + } else if (actual == 0 || (actual < 0 && actual == -EAGAIN)) { + UDPReadContinuation *c = udpReadContAllocator.alloc(); + c->init_token(event); + c->init_read(fd, buf, len, fromaddr, fromaddrlen); + if (timeout) { + c->set_timer(timeout); + } + return event; + } else { + completionUtil::setThread(event, this_ethread()); + completionUtil::setInfo(event, fd, buf, actual, errno); + cont->handleEvent(NET_EVENT_DATAGRAM_READ_ERROR, event); + completionUtil::destroy(event); + return ACTION_IO_ERROR; + } +} + +/* sendmsg: + * Unix: + * *actual_len = sendmsg(fd,msg,default-flags); + * if successful, + * return ACTION_RESULT_DONE + * else + * return error + */ +Action * +UDPNetProcessor::sendmsg_re(Continuation * cont, void *token, int fd, struct msghdr * msg) +{ + int actual; + Event *event = completionUtil::create(); + completionUtil::setContinuation(event, cont); + completionUtil::setHandle(event, token); + + actual = socketManager.sendmsg(fd, msg, 0); + if (actual >= 0) { + completionUtil::setThread(event, this_ethread()); + completionUtil::setInfo(event, fd, msg, actual, errno); + cont->handleEvent(NET_EVENT_DATAGRAM_WRITE_COMPLETE, event); + completionUtil::destroy(event); + return ACTION_RESULT_DONE; + } else { + completionUtil::setThread(event, this_ethread()); + completionUtil::setInfo(event, fd, msg, actual, errno); + cont->handleEvent(NET_EVENT_DATAGRAM_WRITE_ERROR, event); + completionUtil::destroy(event); + return ACTION_IO_ERROR; + } +} + +/* sendto: + * If this were implemented, it might be implemented like this: + * Unix: + * call sendto(fd,addr,buf->reader()->start(),len); + * if successful, + * buf->consume(len); + * return ACTION_RESULT_DONE + * else + * return error + * + */ +Action * +UDPNetProcessor::sendto_re(Continuation * cont, + void *token, int fd, struct sockaddr * toaddr, int toaddrlen, IOBufferBlock * buf, int len) +{ + (void) token; + ink_assert(buf->read_avail() >= len); + int nbytes_sent = socketManager.sendto(fd, buf->start(), len, 0, + toaddr, toaddrlen); + if (nbytes_sent >= 0) { + ink_assert(nbytes_sent == len); + buf->consume(nbytes_sent); + cont->handleEvent(NET_EVENT_DATAGRAM_WRITE_COMPLETE, (void *) -1); + return ACTION_RESULT_DONE; + } else { + cont->handleEvent(NET_EVENT_DATAGRAM_WRITE_ERROR, (void *)(intptr_t)nbytes_sent); + return ACTION_IO_ERROR; + } +} + +Action * +UDPNetProcessor::UDPCreatePortPairs(Continuation * cont, + int nPairs, + unsigned int myIP, unsigned int destIP, int send_bufsize, int recv_bufsize) +{ + + UDPWorkContinuation *worker = udpWorkContinuationAllocator.alloc(); + // UDPWorkContinuation *worker = NEW(new UDPWorkContinuation); + + worker->init(cont, nPairs, myIP, destIP, send_bufsize, recv_bufsize); + eventProcessor.schedule_imm(worker, ET_UDP); + return &(worker->action); +} + + +bool +UDPNetProcessor::CreateUDPSocket(int *resfd, + struct sockaddr_in * addr, + Action ** status, int my_port, unsigned int my_ip, int send_bufsize, int recv_bufsize) +{ + int res = 0, fd = -1; + struct sockaddr_in bind_sa; + struct sockaddr_in myaddr; + int myaddr_len = sizeof(myaddr); + + *resfd = -1; + if ((res = socketManager.socket(AF_INET, SOCK_DGRAM, 0)) < 0) + goto HardError; + fd = res; + if ((res = safe_fcntl(fd, F_SETFL, O_NONBLOCK)) < 0) + goto HardError; + memset(&bind_sa, 0, sizeof(bind_sa)); + bind_sa.sin_family = AF_INET; + bind_sa.sin_port = htons(my_port); + bind_sa.sin_addr.s_addr = my_ip; + if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &bind_sa, sizeof(bind_sa), IPPROTO_UDP)) < 0) { + unsigned char *pt = (unsigned char *) &my_ip; + Debug("udpnet", "ink bind failed --- my_ip = %d.%d.%d.%d", pt[0], pt[1], pt[2], pt[3]); + goto SoftError; + } + + if (recv_bufsize) { + if (unlikely(socketManager.set_rcvbuf_size(fd, recv_bufsize))) + Debug("udpnet", "set_dnsbuf_size(%d) failed", recv_bufsize); + } + if (send_bufsize) { + if (unlikely(socketManager.set_sndbuf_size(fd, send_bufsize))) + Debug("udpnet", "set_dnsbuf_size(%d) failed", send_bufsize); + } + if ((res = safe_getsockname(fd, (struct sockaddr *) &myaddr, &myaddr_len)) < 0) { + Debug("udpnet", "CreateUdpsocket: getsockname didnt' work"); + goto HardError; + } + if (!myaddr.sin_addr.s_addr) { + // set to default IP address for machine + /** netfixme ... this_machine() is in proxy. + if (this_machine()) { + myaddr.sin_addr.s_addr = this_machine()->ip; + } else { + Debug("udpnet","CreateUdpSocket -- machine not initialized"); + } + */ + } + *resfd = fd; + memcpy(addr, &myaddr, myaddr_len); + *status = NULL; + Debug("udpnet", "creating a udp socket port = %d, %d---success", my_port, addr->sin_port); + return true; +SoftError: + Debug("udpnet", "creating a udp socket port = %d---soft failure", my_port); + if (fd != -1) + socketManager.close(fd); + *resfd = -1; + *status = NULL; + return false; +HardError: + Debug("udpnet", "creating a udp socket port = %d---hard failure", my_port); + if (fd != -1) + socketManager.close(fd); + *resfd = -1; + *status = ACTION_IO_ERROR; + return false; +} + +void +UDPNetProcessor::UDPClassifyConnection(Continuation * udpConn, int destIP) +{ + int i; + UDPConnectionInternal *p = (UDPConnectionInternal *) udpConn; + + if (G_inkPipeInfo.numPipes == 0) { + p->pipe_class = 0; + return; + } + p->pipe_class = -1; + // find a match: 0 is best-effort + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) + if (G_inkPipeInfo.perPipeInfo[i].destIP == destIP) + p->pipe_class = i; + // no match; set it to the destIP=0 class + if (p->pipe_class == -1) { + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) + if (G_inkPipeInfo.perPipeInfo[i].destIP == 0) { + p->pipe_class = i; + break; + } + } + Debug("udpnet-pipe", "Pipe class = %d", p->pipe_class); + ink_debug_assert(p->pipe_class != -1); + if (p->pipe_class == -1) + p->pipe_class = 0; + G_inkPipeInfo.perPipeInfo[p->pipe_class].count++; +} + +Action * +UDPNetProcessor::UDPBind(Continuation * cont, int my_port, int my_ip, int send_bufsize, int recv_bufsize) +{ + int res = 0; + int fd = -1; + UnixUDPConnection *n = NULL; + struct sockaddr_in bind_sa; + struct sockaddr_in myaddr; + int myaddr_len = sizeof(myaddr); + + if ((res = socketManager.socket(AF_INET, SOCK_DGRAM, 0)) < 0) + goto Lerror; + fd = res; + if ((res = fcntl(fd, F_SETFL, O_NONBLOCK) < 0)) + goto Lerror; + + // If this is a class D address (i.e. multicast address), use REUSEADDR. + if ((((unsigned int) (ntohl(my_ip))) & 0xf0000000) == 0xe0000000) { + int enable_reuseaddr = 1; + + if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable_reuseaddr, sizeof(enable_reuseaddr)) < 0)) { + goto Lerror; + } + } + + memset(&bind_sa, 0, sizeof(bind_sa)); + bind_sa.sin_family = AF_INET; + bind_sa.sin_port = htons(my_port); + bind_sa.sin_addr.s_addr = my_ip; + if ((res = socketManager.ink_bind(fd, (struct sockaddr *) &bind_sa, sizeof(bind_sa))) < 0) { + goto Lerror; + } + + if (recv_bufsize) { + if (unlikely(socketManager.set_rcvbuf_size(fd, recv_bufsize))) + Debug("udpnet", "set_dnsbuf_size(%d) failed", recv_bufsize); + } + if (send_bufsize) { + if (unlikely(socketManager.set_sndbuf_size(fd, send_bufsize))) + Debug("udpnet", "set_dnsbuf_size(%d) failed", send_bufsize); + } + if ((res = safe_getsockname(fd, (struct sockaddr *) &myaddr, &myaddr_len)) < 0) { + goto Lerror; + } + if (!myaddr.sin_addr.s_addr) { + // set to default IP address for machine + /** netfixme this_machine is in proxy/ + if (this_machine()) { + myaddr.sin_addr.s_addr = this_machine()->ip; + } else { + Debug("udpnet","UDPNetProcessor::UDPBind -- machine not initialized"); + } + */ + } + n = NEW(new UnixUDPConnection(fd)); + + Debug("udpnet", "UDPNetProcessor::UDPBind: %x fd=%d", n, fd); + n->setBinding(&myaddr); + n->bindToThread(cont); + + cont->handleEvent(NET_EVENT_DATAGRAM_OPEN, n); + return ACTION_RESULT_DONE; +Lerror: + if (fd != NO_FD) + socketManager.close(fd); + cont->handleEvent(NET_EVENT_DATAGRAM_ERROR, NULL); + return ACTION_IO_ERROR; +} + +bool +UDPNetProcessor::AllocBandwidth(Continuation * udpConn, double desiredMbps) +{ + UDPConnectionInternal *udpIntConn = (UDPConnectionInternal *) udpConn; + int64_t desiredbps = (int64_t) (desiredMbps * 1024.0 * 1024.0); + + if (G_inkPipeInfo.numPipes == 0) { + udpIntConn->flowRateBps = (desiredMbps * 1024.0 * 1024.0) / 8.0; + return true; + } + + if ((udpIntConn->pipe_class == 0) || + (G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc + desiredbps > + G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwLimit)) { + Debug("udpnet-admit", "Denying flow with %lf Mbps", desiredMbps); + return false; + } + udpIntConn->flowRateBps = (desiredMbps * 1024.0 * 1024.0) / 8.0; + udpIntConn->allocedbps = desiredbps; + ink_atomic_increment64(&G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc, desiredbps); + Debug("udpnet-admit", "Admitting flow with %lf Mbps (a=%" PRId64 ", lim=%" PRId64 ")", + desiredMbps, + G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc, + G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwLimit); + return true; +} + +bool +UDPNetProcessor::ChangeBandwidth(Continuation * udpConn, double desiredMbps) +{ + UDPConnectionInternal *udpIntConn = (UDPConnectionInternal *) udpConn; + int64_t desiredbps = (int64_t) (desiredMbps * 1024.0 * 1024.0); + int64_t oldbps = (int64_t) (udpIntConn->flowRateBps * 8.0); + + if (G_inkPipeInfo.numPipes == 0) { + udpIntConn->flowRateBps = (desiredMbps * 1024.0 * 1024.0) / 8.0; + return true; + } + // arithmetic here is in bits-per-sec. + if ((udpIntConn->pipe_class == 0) || + (G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc + + desiredbps - oldbps) > G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwLimit) { + Debug("udpnet-admit", "Unable to change b/w for flow to %lf Mbps", desiredMbps); + return false; + } + udpIntConn->flowRateBps = (desiredMbps * 1024.0 * 1024.0) / 8.0; + udpIntConn->allocedbps = desiredbps; + ink_atomic_increment64(&G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc, desiredbps - oldbps); + Debug("udpnet-admit", "Changing flow's b/w from %lf Mbps to %lf Mbps (a=%" PRId64 ", lim=%" PRId64 ")", + (double) oldbps / (1024.0 * 1024.0), + desiredMbps, + G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc, + G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwLimit); + return true; +} + +void +UDPNetProcessor::FreeBandwidth(Continuation * udpConn) +{ + UDPConnectionInternal *udpIntConn = (UDPConnectionInternal *) udpConn; + int64_t bps; + + if (G_inkPipeInfo.numPipes == 0) + return; + + Debug("udpnet-free", "Trying to releasing %lf (%" PRId64 ") Kbps", udpIntConn->flowRateBps, udpIntConn->allocedbps); + + bps = udpIntConn->allocedbps; + if (bps <= 0) + return; + + ink_atomic_increment64(&G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc, -bps); + + Debug("udpnet-free", "Releasing %lf Kbps", bps / 1024.0); + + if (G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc < 0) + G_inkPipeInfo.perPipeInfo[udpIntConn->pipe_class].bwAlloc = 0; + + udpIntConn->flowRateBps = 0.0; + udpIntConn->allocedbps = 0; +} + +double +UDPNetProcessor::GetAvailableBandwidth() +{ + int i; + double usedBw = 0.0; + + if (G_inkPipeInfo.numPipes == 0) + // return 100Mbps if there are no pipes + return 100.0; + + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) { + usedBw += G_inkPipeInfo.perPipeInfo[i].bwUsed; + } + return G_inkPipeInfo.interfaceMbps - usedBw; +} + +// send out all packets that need to be sent out as of time=now +UDPQueue::UDPQueue() +: last_report(0) +, last_service(0) +, last_byteperiod(0) +, bytesSent(0) +, packets(0) +, added(0) +{ +} + +UDPQueue::~UDPQueue() +{ + UDPPacketInternal *p; + + while ((p = reliabilityPktQueue.dequeue()) != NULL) + p->free(); +} + +/* + * Driver function that aggregates packets across cont's and sends them + */ +void +UDPQueue::service(UDPNetHandler * nh) +{ + ink_hrtime now = ink_get_hrtime_internal(); + uint64_t timeSpent = 0; + UDPPacketInternal *p; + ink_hrtime pktSendTime; + double minPktSpacing; + uint32_t pktSize; + int64_t pktLen; + int i; + bool addToGuaranteedQ; + (void) nh; + static ink_hrtime lastPrintTime = ink_get_hrtime_internal(); + static ink_hrtime lastSchedTime = ink_get_hrtime_internal(); + static uint32_t schedJitter = 0; + static uint32_t numTimesSched = 0; + + schedJitter += ink_hrtime_to_msec(now - lastSchedTime); + numTimesSched++; + + p = (UDPPacketInternal *) ink_atomiclist_popall(&atomicQueue); + if (p) { + + UDPPacketInternal *pnext = NULL; + Queue stk; + + while (p) { + pnext = p->alink.next; + p->alink.next = NULL; + stk.push(p); + p = pnext; + } + // walk backwards down list since this is actually an atomic stack. + while (stk.head) { + p = stk.pop(); + ink_assert(p->link.prev == NULL); + ink_assert(p->link.next == NULL); + if (p->isReliabilityPkt) { + reliabilityPktQueue.enqueue(p); + continue; + } + // insert into our queue. + Debug("udp-send", "Adding 0x%x", p); + addToGuaranteedQ = ((p->conn->pipe_class > 0) && (p->conn->flowRateBps > 10.0)); + pktLen = p->getPktLength(); + if (p->conn->lastPktStartTime == 0) { + p->pktSendStartTime = MAX(now, p->delivery_time); + } else { + pktSize = MAX(INK_ETHERNET_MTU_SIZE, pktLen); + if (addToGuaranteedQ) { + // NOTE: this is flow rate in Bytes per sec.; convert to milli-sec. + minPktSpacing = 1000.0 / (p->conn->flowRateBps / p->conn->avgPktSize); + + pktSendTime = p->conn->lastPktStartTime + ink_hrtime_from_msec((uint32_t) minPktSpacing); + } else { + minPktSpacing = 0.0; + pktSendTime = p->delivery_time; + } + p->pktSendStartTime = MAX(MAX(now, pktSendTime), p->delivery_time); + if (p->conn->flowRateBps > 25600.0) + Debug("udpnet-pkt", "Pkt size = %.1lf now = %" PRId64 ", send = %" PRId64 ", del = %" PRId64 ", Delay delta = %" PRId64 "; delta = %" PRId64 "", + p->conn->avgPktSize, + now, pktSendTime, p->delivery_time, + ink_hrtime_to_msec(p->pktSendStartTime - now), + ink_hrtime_to_msec(p->pktSendStartTime - p->conn->lastPktStartTime)); + + p->conn->avgPktSize = ((4.0 * p->conn->avgPktSize) / 5.0) + (pktSize / 5.0); + } + p->conn->lastPktStartTime = p->pktSendStartTime; + p->delivery_time = p->pktSendStartTime; + p->conn->nBytesTodo += pktLen; + + g_udp_bytesPending += pktLen; + + if (addToGuaranteedQ) + G_inkPipeInfo.perPipeInfo[p->conn->pipe_class].queue->addPacket(p, now); + else { + // stick in the best-effort queue: either it was a best-effort flow or + // the thingy wasn't alloc'ed bandwidth + G_inkPipeInfo.perPipeInfo[0].queue->addPacket(p, now); + } + } + } + + if ((now - lastPrintTime) > ink_hrtime_from_sec(30)) { + Debug("udp-pending-packets", "udp bytes pending: %" PRId64 "", g_udp_bytesPending); + Debug("udp-sched-jitter", "avg. udp sched jitter: %f", (double) schedJitter / numTimesSched); + schedJitter = 0; + numTimesSched = 0; + lastPrintTime = now; + } + + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) + G_inkPipeInfo.perPipeInfo[i].queue->advanceNow(now); + + if (G_bulkIOState) { + BulkIOSend(); + } else { + SendPackets(); + } + + timeSpent = ink_hrtime_to_msec(now - last_report); + if (timeSpent > 10000) { + // if (bytesSent > 0) + // timespent is in milli-seconds + char temp[2048], *p1; + double bw, totalBw; + + temp[0] = '\0'; + p1 = temp; + + if (bytesSent > 0) + totalBw = (bytesSent * 8.0 * 1000.0) / (timeSpent * 1024.0 * 1024.0); + else + totalBw = 1.0; + + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) { + // bw is in Mbps + bw = (G_inkPipeInfo.perPipeInfo[i].bytesSent * 8.0 * 1000.0) / (timeSpent * 1024.0 * 1024.0); + snprintf(p1, sizeof(temp), "\t class[%d] = %f Mbps, alloc = %f Mbps, (conf'ed = %f, got = %f) \n", + i, bw, (G_inkPipeInfo.perPipeInfo[i].bwAlloc / (1024.0 * 1024.0)), + G_inkPipeInfo.perPipeInfo[i].wt, bw / totalBw); + p1 += strlen(p1); + + // use a weighted estimator of current usage + G_inkPipeInfo.perPipeInfo[i].bwUsed = (4.0 * G_inkPipeInfo.perPipeInfo[i].bwUsed / 5.0) + (bw / 5.0); + G_inkPipeInfo.perPipeInfo[i].bytesSent = 0; + G_inkPipeInfo.perPipeInfo[i].pktsSent = 0; + } + if (temp[0]) + Debug("udpnet-bw", "B/w: %f Mbps; breakdown: \n%s", totalBw, temp); + + + bytesSent = 0; + last_report = now; + added = 0; + packets = 0; + } + last_service = now; +} + +void +UDPQueue::SendPackets() +{ + UDPPacketInternal *p; + static ink_hrtime lastCleanupTime = ink_get_hrtime_internal(); + ink_hrtime now = ink_get_hrtime_internal(); + // ink_hrtime send_threshold_time = now + HRTIME_MSECONDS(5); + // send packets for SLOT_TIME per attempt + ink_hrtime send_threshold_time = now + SLOT_TIME; + int32_t bytesThisSlot = INT_MAX, bytesUsed = 0, reliabilityBytes = 0; + int32_t bytesThisPipe, sentOne, i; + int64_t pktLen; + ink_hrtime timeDelta = 0; + + if (now > last_service) + timeDelta = ink_hrtime_to_msec(now - last_service); + + if (G_inkPipeInfo.numPipes > 0) { + bytesThisSlot = (int32_t) (((G_inkPipeInfo.reliabilityMbps * 1024.0 * 1024.0) / (8.0 * 1000.0)) * timeDelta); + if (bytesThisSlot == 0) { + // use at most 10% for reliability + bytesThisSlot = (int32_t) (((G_inkPipeInfo.interfaceMbps * 1024.0 * 1024.0) / (8.0 * 1000.0)) * timeDelta * 0.1); + reliabilityBytes = bytesThisSlot; + } + } + + while ((p = reliabilityPktQueue.dequeue()) != NULL) { + pktLen = p->getPktLength(); + g_udp_bytesPending -= pktLen; + + p->conn->nBytesTodo -= pktLen; + p->conn->nBytesDone += pktLen; + + if (p->conn->shouldDestroy()) + goto next_pkt_3; + if (p->conn->GetSendGenerationNumber() != p->reqGenerationNum) + goto next_pkt_3; + + SendUDPPacket(p, pktLen); + bytesThisSlot -= pktLen; + if (bytesThisSlot < 0) + break; + next_pkt_3: + p->free(); + } + + + if (G_inkPipeInfo.numPipes > 0) + bytesThisSlot = (int32_t) (((G_inkPipeInfo.interfaceMbps * 1024.0 * 1024.0) / + (8.0 * 1000.0)) * timeDelta - reliabilityBytes); + else + bytesThisSlot = INT_MAX; + +sendPackets: + sentOne = false; + send_threshold_time = now + SLOT_TIME; + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) { + bytesThisPipe = (int32_t) (bytesThisSlot * G_inkPipeInfo.perPipeInfo[i].wt); + while ((bytesThisPipe > 0) && (G_inkPipeInfo.perPipeInfo[i].queue->firstPacket(send_threshold_time))) { + p = G_inkPipeInfo.perPipeInfo[i].queue->getFirstPacket(); + pktLen = p->getPktLength(); + g_udp_bytesPending -= pktLen; + + p->conn->nBytesTodo -= pktLen; + p->conn->nBytesDone += pktLen; + if (p->conn->shouldDestroy()) + goto next_pkt; + if (p->conn->GetSendGenerationNumber() != p->reqGenerationNum) + goto next_pkt; + + G_inkPipeInfo.perPipeInfo[i].bytesSent += pktLen; + SendUDPPacket(p, pktLen); + bytesUsed += pktLen; + bytesThisPipe -= pktLen; + next_pkt: + sentOne = true; + p->free(); + + if (bytesThisPipe < 0) + break; + } + } + + bytesThisSlot -= bytesUsed; + + if ((bytesThisSlot > 0) && (sentOne)) { + // redistribute the slack... + now = ink_get_hrtime_internal(); + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) { + if (G_inkPipeInfo.perPipeInfo[i].queue->firstPacket(now) == NULL) { + G_inkPipeInfo.perPipeInfo[i].queue->advanceNow(now); + } + } + goto sendPackets; + } + + if ((g_udp_periodicFreeCancelledPkts) && + (now - lastCleanupTime > ink_hrtime_from_sec(g_udp_periodicFreeCancelledPkts))) { + uint64_t nbytes = g_udp_bytesPending; + ink_hrtime startTime = ink_get_hrtime_internal(), endTime; + for (i = 0; i < G_inkPipeInfo.numPipes + 1; i++) { + G_inkPipeInfo.perPipeInfo[i].queue->FreeCancelledPackets(g_udp_periodicCleanupSlots); + } + endTime = ink_get_hrtime_internal(); + Debug("udp-pending-packets", "Did cleanup of %d buckets: %" PRId64 " bytes in %d m.sec", + g_udp_periodicCleanupSlots, nbytes - g_udp_bytesPending, ink_hrtime_to_msec(endTime - startTime)); + lastCleanupTime = now; + } +} + +void +UDPQueue::SendUDPPacket(UDPPacketInternal * p, int32_t pktLen) +{ + IOBufferBlock *b; + struct msghdr msg; + struct iovec iov[32]; + int real_len = 0; + int n, count, iov_len = 0; + + if (!p->isReliabilityPkt) { + p->conn->lastSentPktStartTime = p->delivery_time; + } + + Debug("udp-send", "Sending 0x%x", p); +#if !defined(solaris) + msg.msg_control = 0; + msg.msg_controllen = 0; + msg.msg_flags = 0; +#endif + msg.msg_name = (caddr_t) & p->to; + msg.msg_namelen = sizeof(p->to); + iov_len = 0; + bytesSent += pktLen; + for (b = p->chain; b != NULL; b = b->next) { + iov[iov_len].iov_base = (caddr_t) b->start(); + iov[iov_len].iov_len = b->size(); + real_len += iov[iov_len].iov_len; + iov_len++; + } + msg.msg_iov = iov; + msg.msg_iovlen = iov_len; + + count = 0; + while (1) { + // stupid Linux problem: sendmsg can return EAGAIN + n =::sendmsg(p->conn->getFd(), &msg, 0); + if ((n >= 0) || ((n < 0) && (errno != EAGAIN))) + // send succeeded or some random error happened. + break; + if (errno == EAGAIN) { + count++; + if ((g_udp_numSendRetries > 0) && (count >= g_udp_numSendRetries)) { + // tried too many times; give up + Debug("udpnet", "Send failed: too many retries"); + break; + } + } + } +} + +#ifndef BULK_IO_SEND_IS_BROKEN +void +UDPQueue::BulkIOSend() +{ + ink_assert(!"Don't call here..."); +} +#else +void +UDPQueue::BulkIOSend() +{ + bool sentOne = false; + UDPPacketInternal *p; + ink_hrtime now = ink_get_hrtime_internal(); + ink_hrtime send_threshold_time = now + SLOT_TIME; + + for (int i = 0; i < G_inkPipeInfo.numPipes + 1; i++) { + while (p = G_inkPipeInfo.perPipeInfo[i].queue->firstPacket(send_threshold_time)) { + p = G_inkPipeInfo.perPipeInfo[i].queue->getFirstPacket(); + sentOne = true; + Debug("bulk-io-pkt", "Adding a packet..."); + BulkIOAddPkt(G_bulkIOState, &G_bulkIOAggregator, p, p->conn->getPortNum()); + bytesSent += p->getPktLength(); + // Now the packet is "sent"; get rid of it + p->free(); + } + } + if (sentOne) { + BulkIOFlush(G_bulkIOState, &G_bulkIOAggregator); + } +} +#endif + +void +UDPQueue::send(UDPPacket * p) +{ + // XXX: maybe fastpath for immediate send? + ink_atomiclist_push(&atomicQueue, p); +} + +#undef LINK + +UDPNetHandler::UDPNetHandler() +{ + mutex = new_ProxyMutex(); + ink_atomiclist_init(&udpOutQueue.atomicQueue, "Outgoing UDP Packet queue", offsetof(UDPPacketInternal, alink.next)); + ink_atomiclist_init(&udpNewConnections, "UDP Connection queue", offsetof(UnixUDPConnection, newconn_alink.next)); + nextCheck = ink_get_hrtime_internal() + HRTIME_MSECONDS(1000); + lastCheck = 0; + SET_HANDLER((UDPNetContHandler) & UDPNetHandler::startNetEvent); +} + +int +UDPNetHandler::startNetEvent(int event, Event * e) +{ + (void) event; + SET_HANDLER((UDPNetContHandler) & UDPNetHandler::mainNetEvent); + trigger_event = e; + e->schedule_every(-HRTIME_MSECONDS(9)); + return EVENT_CONT; +} + +int +UDPNetHandler::mainNetEvent(int event, Event * e) +{ + ink_assert(trigger_event == e && event == EVENT_POLL); + (void) event; + (void) e; + + PollCont *pc = get_UDPPollCont(e->ethread); + + // handle UDP outgoing engine + udpOutQueue.service(this); + + // handle UDP read operations + UnixUDPConnection *uc, *next; + int i; + int nread = 0; + + EventIO *temp_eptr = NULL; + for (i = 0; i < pc->pollDescriptor->result; i++) { + temp_eptr = (EventIO*) get_ev_data(pc->pollDescriptor,i); + if ((get_ev_events(pc->pollDescriptor,i) & EVENTIO_READ) + && temp_eptr->type == EVENTIO_UDP_CONNECTION) { + uc = temp_eptr->data.uc; + ink_assert(uc && uc->mutex && uc->continuation); + ink_assert(uc->refcount >= 1); + if (uc->shouldDestroy()) { + // udp_polling->remove(uc,uc->polling_link); + uc->Release(); + } else { + udpNetInternal.udp_read_from_net(this, uc, pc->pollDescriptor, trigger_event->ethread); + nread++; + } + } //if EPOLLIN + } //end for + + // remove dead UDP connections + ink_hrtime now = ink_get_hrtime_internal(); + if (now >= nextCheck) { + for (uc = udp_polling.head; uc; uc = next) { + ink_assert(uc->mutex && uc->continuation); + ink_assert(uc->refcount >= 1); + next = uc->polling_link.next; + if (uc->shouldDestroy()) { + if (G_inkPipeInfo.numPipes > 0) + G_inkPipeInfo.perPipeInfo[uc->pipe_class].count--; + //changed by YTS Team, yamsat + //udp_polling->remove(uc,uc->polling_link); + uc->Release(); + } + } + nextCheck = ink_get_hrtime_internal() + HRTIME_MSECONDS(1000); + } + // service UDPConnections with data ready for callback. + Que(UnixUDPConnection, callback_link) q = udp_callbacks; + udp_callbacks.clear(); + while ((uc = q.dequeue())) { + ink_assert(uc->mutex && uc->continuation); + if (udpNetInternal.udp_callback(this, uc, trigger_event->ethread)) { // not successful + // schedule on a thread of its own. + ink_assert(uc->callback_link.next == NULL); + ink_assert(uc->callback_link.prev == NULL); + udp_callbacks.enqueue(uc); + } else { + ink_assert(uc->callback_link.next == NULL); + ink_assert(uc->callback_link.prev == NULL); + uc->onCallbackQueue = 0; + uc->Release(); + } + } + + return EVENT_CONT; +} + +///////////////////////////////////////////////////////////////////// +// +// A helper continuation that creates a pair of UDP ports in a non-blocking +// way. This continuation runs on the UDP thread; a run lasts for at most 500ms. +// +///////////////////////////////////////////////////////////////////// + +void +UDPWorkContinuation::init(Continuation * c, int num_pairs, + unsigned int my_ip, unsigned int dest_ip, int s_bufsize, int r_bufsize) +{ + mutex = c->mutex; + cont = c; + action = c; + numPairs = num_pairs; + myIP = my_ip; + destIP = dest_ip; + sendbufsize = s_bufsize; + recvbufsize = r_bufsize; + udpConns = NULL; + SET_HANDLER((UDPWorkContinuation_Handler) & UDPWorkContinuation::StateCreatePortPairs); +} + +int +UDPWorkContinuation::StateCreatePortPairs(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); +// int res = 0; + int numUdpPorts = 2 * numPairs; + int fd1 = -1, fd2 = -1; +// struct sockaddr_in bind_sa; + struct sockaddr_in myaddr1, myaddr2; + int portNum, i; +// int myaddr_len = sizeof(myaddr1); + static int lastAllocPort = 10000; + ink_hrtime startTime, endTime; + Action *status; + //epoll changes + + PollCont *pc = NULL; + //epoll changes ends here + ink_debug_assert(mutex->thread_holding == this_ethread()); + + if (action.cancelled) { + action = NULL; + mutex = NULL; + udpWorkContinuationAllocator.free(this); + return EVENT_CONT; + } + + startTime = ink_get_hrtime_internal(); + + udpConns = NEW(new UnixUDPConnection *[numUdpPorts]); + for (i = 0; i < numUdpPorts; i++) + udpConns[i] = NULL; + ink_atomic_swap(&portNum, lastAllocPort); + portNum %= 50000; + if (portNum == 0) + portNum = 10000; + + i = 0; + while (i < numUdpPorts) { + + if (udpNet.CreateUDPSocket(&fd1, &myaddr1, &status, portNum, myIP, sendbufsize, recvbufsize)) { + if (udpNet.CreateUDPSocket(&fd2, &myaddr2, &status, portNum + 1, myIP, sendbufsize, recvbufsize)) { + udpConns[i] = NEW(new UnixUDPConnection(fd1)); // new_UnixUDPConnection(fd1); + udpConns[i]->setBinding(&myaddr1); + i++; + udpConns[i] = NEW(new UnixUDPConnection(fd2)); // new_UnixUDPConnection(fd2); + udpConns[i]->setBinding(&myaddr2); + i++; + // remember the last alloc'ed port + ink_atomic_swap(&lastAllocPort, portNum + 2); + } else { + if (fd1 != NO_FD) + socketManager.close(fd1); + if (status == ACTION_IO_ERROR) + goto Lerror; + } + Debug("udpnet", "Created port pair with ports = %d, %d", portNum, portNum + 1); + } else if (status == ACTION_IO_ERROR) + goto Lerror; + // pick the next port pair value + portNum += 2; + // wrap around at 50K + portNum %= 50000; + if (portNum == 0) + portNum = 10000; + endTime = ink_get_hrtime_internal(); + // if we spend more than 500 ms. bail! + if (ink_hrtime_to_msec(endTime - startTime) > 500) { + status = ACTION_IO_ERROR; + goto Lerror; + } + + } + + for (i = 0; i < numUdpPorts; i++) { + udpNet.UDPClassifyConnection(udpConns[i], destIP); + Debug("udpnet-pipe", "Adding (port = %d) to Pipe class: %d", + udpConns[i]->getPortNum(), udpConns[i]->pipe_class); + } + + // assert should *never* fire; we check for this at the begin of the func. + ink_assert(!action.cancelled); + + // Bind to threads only on a success. Currently, after you have + // bound to have a thread, the only way to remove a UDPConnection is + // to call destroy(); the thread to which the UDPConnection will + // remove the connection from a linked list and call delete. + + for (i = 0; i < numUdpPorts; i++) { + udpConns[i]->bindToThread(cont); + pc = get_UDPPollCont(udpConns[i]->ethread); + udpConns[i]->ep.start(pc->pollDescriptor, udpConns[i], EVENTIO_READ); + } + + resultCode = NET_EVENT_DATAGRAM_OPEN; + goto out; + +Lerror: + resultCode = NET_EVENT_DATAGRAM_ERROR; + for (i = 0; i < numUdpPorts; i++) + delete udpConns[i]; + delete[] udpConns; + udpConns = NULL; + +out: + SET_HANDLER((UDPWorkContinuation_Handler) & UDPWorkContinuation::StateDoCallback); + return StateDoCallback(0, NULL); +} + +int +UDPWorkContinuation::StateDoCallback(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + MUTEX_TRY_LOCK(lock, action.mutex, this_ethread()); + if (!lock) { + this_ethread()->schedule_in(this, MUTEX_RETRY_DELAY); + return EVENT_CONT; + } + if (!action.cancelled) { + action.continuation->handleEvent(resultCode, udpConns); + } else { + // else action.cancelled + if (resultCode == NET_EVENT_DATAGRAM_OPEN) { + for (int i = 0; i < numPairs * 2; i++) + // don't call delete on individual connections; the udp thread will do + // that when it cleans up an fd. + udpConns[i]->destroy(); + delete[]udpConns; // I think this is OK to delete the array, what we shouldn't do is loop over + udpConns = NULL; // the conns and and do delete udpConns[i]. + } + } + + action = NULL; + mutex = NULL; + udpWorkContinuationAllocator.free(this); + + return EVENT_CONT; +} diff --git a/iocore/net/test_I_Net.cc b/iocore/net/test_I_Net.cc new file mode 100644 index 00000000..db2d165d --- /dev/null +++ b/iocore/net/test_I_Net.cc @@ -0,0 +1,183 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" +#ifndef _WIN32 +#include +#endif + +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" +//#define USE_SOCKS + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + +/* + * Choose a net test application + */ +//#include "NetTest-http-server.c" +#include "NetTest-simple-proxy.c" + + +int +main() +{ + // do not buffer stdout + setbuf(stdout, NULL); + int nproc = ink_number_of_processors(); + + RecModeT mode_type = RECM_STAND_ALONE; + + + init_diags("net_test", NULL); + RecProcessInit(mode_type); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + ink_net_init(NET_SYSTEM_MODULE_VERSION); + + + /* + * ignore broken pipe + */ +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif + + /* + * start processors + */ + + eventProcessor.start(nproc); + RecProcessStart(); + + /* + * Reset necessary config variables + */ + +#ifdef USE_SOCKS + net_config_socks_server_host = "209.131.52.54"; + net_config_socks_server_port = 1080; + net_config_socks_needed = 1; +#endif + + netProcessor.start(); + sslNetProcessor.start(1); + + /* + * Call the tests main function + */ + test_main(); + this_thread()->execute(); + return 0; +} diff --git a/iocore/net/test_I_UDPNet.cc b/iocore/net/test_I_UDPNet.cc new file mode 100644 index 00000000..62329f8b --- /dev/null +++ b/iocore/net/test_I_UDPNet.cc @@ -0,0 +1,214 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include + +#include "I_Net.h" +#include "List.h" + +//Diags stuff from test_I_Net.cc: +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i, e; + char *p, *dt, *at; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_IOCORE_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "a+"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + + +/*This implements a standard Unix echo server: just send every udp packet you + get back to where it came from*/ + +class EchoServer:public Continuation +{ + int sock_fd; + UDPConnection *conn; + + int handlePacket(int event, void *data); + +public: + EchoServer() + : Continuation(new_ProxyMutex()) + { + }; + + bool Start(int port); +}; + +bool +EchoServer::Start(int port) +{ + Action *action; + sockaddr_in addr; + + if (!udpNet.CreateUDPSocket(&sock_fd, &addr, &action, port)) + return false; + + conn = new_UDPConnection(sock_fd); + conn->bindToThread(this); + + SET_HANDLER(&EchoServer::handlePacket); + + conn->recv(this); +} + +int +EchoServer::handlePacket(int event, void *data) +{ + switch (event) { + + case NET_EVENT_DATAGRAM_READ_READY:{ + Queue *q = (Queue *)data; + UDPPacket *p; + + //send what ever we get back to the client + while (p = q->pop()) { + p->m_to = p->m_from; + conn->send(this, p); + } + break; + } + + case NET_EVENT_DATAGRAM_READ_ERROR: + printf("got Read Error exiting\n"); + _exit(1); + + case NET_EVENT_DATAGRAM_WRITE_ERROR: + printf("got write error: %d\n", (int) data); + break; + + default: + printf("got unknown event\n"); + } + + return EVENT_DONE; +} + +int +main(int argc, char *argv[]) +{ + int port = (argc > 1) ? atoi(argv[1]) : 39680; + + init_diags((argc > 2) ? argv[2] : "udp.*", NULL); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(2); + udpNet.start(1); + + signal(SIGPIPE, SIG_IGN); + + EchoServer server; + server.Start(port); + + this_thread()->execute(); +} diff --git a/iocore/net/test_I_simple_proxy.cc b/iocore/net/test_I_simple_proxy.cc new file mode 100644 index 00000000..1d45a80e --- /dev/null +++ b/iocore/net/test_I_simple_proxy.cc @@ -0,0 +1,294 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_Net.h" +#include + +static unsigned int +get_addr(char *host) +{ + unsigned int addr = inet_addr(host); + struct hostent *host_info = NULL; + + if (!addr || (-1 == (int) addr)) { + host_info = gethostbyname(host); + if (!host_info) { + perror("gethostbyname"); + return (unsigned int) -1; + } + addr = *((unsigned int *) host_info->h_addr); + } + + return addr; +} + + +#define MAX_INT 32767 + +char *origin_server = "trafficserver.apache.org"; +unsigned short origin_server_port = 8080; + +struct NetTesterSM:public Continuation +{ + VIO *client_read_vio; + VIO *client_resp_write_vio; + VIO *server_resp_read_vio; + + IOBufferReader *reader; + IOBufferReader *client_reader, *client_parse_reader; + + NetVConnection *client_vc, *server_vc; + MIOBuffer *request_buf; + MIOBuffer *response_buf; + char request[2000]; + int req_len; + + + NetTesterSM(ProxyMutex * _mutex, NetVConnection * _vc):Continuation(_mutex) + { + MUTEX_TRY_LOCK(lock, mutex, _vc->thread); + ink_release_assert(lock); + client_vc = _vc; + SET_HANDLER(&NetTesterSM::handle_request_read_from_client); + request_buf = new_MIOBuffer(8); + response_buf = new_MIOBuffer(8); + client_reader = request_buf->alloc_reader(); + client_parse_reader = request_buf->alloc_reader(); + client_read_vio = client_vc->do_io_read(this, INT64_MAX, request_buf); + client_vc->set_inactivity_timeout(HRTIME_SECONDS(60)); + req_len = 0; + } + + + ~NetTesterSM() + { + request_buf->dealloc_all_readers(); + request_buf->clear(); + free_MIOBuffer(request_buf); + response_buf->dealloc_all_readers(); + response_buf->clear(); + free_MIOBuffer(response_buf); + } + + /* ********************* jtest sample request ********************** + GET http://npdev:8080/0.5216393021/6000 HTTP/1.0 + Proxy-Connection: Keep-Alive + */ + + int handle_request_read_from_client(int event, void *data) + { + int r; + char *str; + switch (event) { + case VC_EVENT_READ_READY: + r = client_parse_reader->read_avail(); + client_parse_reader->read(&request[req_len], r); + req_len += r; + request[req_len] = 0; + //printf("%s\n", request); + fflush(stdout); + client_vc->set_inactivity_timeout(HRTIME_SECONDS(30)); + if (strcmp(&request[req_len - 4], "\r\n\r\n") == 0) { + //printf("The request header is :\n%s\n", request); + client_vc->cancel_inactivity_timeout(); + // connect to the origin server + SET_HANDLER(&NetTesterSM::handle_server_connect); + netProcessor.connect_re(this, get_addr(origin_server), origin_server_port); + } + break; + case VC_EVENT_READ_COMPLETE: + /* FALLSTHROUGH */ + case VC_EVENT_EOS: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + //printf("%s", str); + fflush(stdout); + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + client_vc->do_io_close(); + break; + default: + ink_release_assert(!"unknown event"); + + } + return EVENT_CONT; + } + + int handle_server_connect(int event, Event * e) + { + switch (event) { + case NET_EVENT_OPEN: + server_vc = (NetVConnection *) e; + SET_HANDLER(&NetTesterSM::handle_write_request_to_server); + //printf("connected to server\n"); + //printf("writing %d to server\n", client_reader->read_avail()); + server_vc->do_io_write(this, client_reader->read_avail(), client_reader); + //vc->set_inactivity_timeout(HRTIME_SECONDS(10)); + break; + case NET_EVENT_OPEN_FAILED: + default: + client_vc->do_io_close(); + delete this; + } + return EVENT_CONT; + } + + int handle_write_request_to_server(int event, Event * e) + { + IOBufferReader *resp_reader; + switch (event) { + case VC_EVENT_WRITE_READY: + //printf("wrote some bytes to server\n"); + break; + + case VC_EVENT_WRITE_COMPLETE: + //printf("wrote request to server\n"); + SET_HANDLER(&NetTesterSM::handle_response_pump); + resp_reader = response_buf->alloc_reader(); + + response_buf->autopilot = 1; + server_resp_read_vio = server_vc->do_io_read(this, MAX_INT, response_buf); + client_resp_write_vio = client_vc->do_io_write(this, MAX_INT, resp_reader); + response_buf->assign_reader_vio(client_resp_write_vio, resp_reader); + response_buf->assign_writer_vio(server_resp_read_vio); + break; + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + server_vc->do_io_close(); + client_vc->do_io_close(); + delete this; + return EVENT_DONE; + break; + default: + ink_release_assert(!"unknown event"); + } + return EVENT_CONT; + } + + int handle_response_pump(int event, Event * e) + { + int doc_len; + switch (event) { + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + server_vc->do_io_close(); + client_vc->do_io_close(); + delete this; + return EVENT_DONE; + break; + + + case VC_EVENT_WRITE_READY: + case VC_EVENT_READ_READY: + ink_release_assert(!"unexpected READY event in handle_response_pump"); + break; + + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + //printf("Got response from server\n"); + doc_len = server_resp_read_vio->ndone; + server_vc->do_io_close(); + if (client_resp_write_vio->ndone != doc_len) { + client_resp_write_vio->set_nbytes(doc_len); + client_vc->reenable(client_resp_write_vio); + } else { + client_vc->do_io_close(); + delete this; + return EVENT_DONE; + } + break; + case VC_EVENT_WRITE_COMPLETE: + client_vc->do_io_close(); + delete this; + return EVENT_DONE; + + default: + ink_release_assert(!"unexpected event in handle_response_pump"); + } + return EVENT_CONT; + + } + + +}; + + +struct NetTesterAccept:public Continuation +{ + + NetTesterAccept(ProxyMutex * _mutex):Continuation(_mutex) + { + SET_HANDLER(&NetTesterAccept::handle_accept); + } + + int handle_accept(int event, void *data) + { + //printf("Accepted a connection\n"); + NetVConnection *vc = (NetVConnection *) data; + NEW(new NetTesterSM(new_ProxyMutex(), vc)); + return EVENT_CONT; + } + + +}; + + + +struct Stop:public Continuation +{ + Action *a; + Stop(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&Stop::stop); + } + + int stop(int event, Event * e) + { + a->cancel(); + return EVENT_DONE; + } +}; + + +int +main() +{ + // do not buffer stdout + setbuf(stdout, NULL); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + init_buffer_allocators(); + eventProcessor.start(1, 0, 0, 0); + netProcessor.start(); + + Action *a = netProcessor.accept(NEW(new NetTesterAccept(new_ProxyMutex())), + 45080, false); + +#ifdef TEST_ACCEPT_CANCEL + Stop *s = NEW(new Stop(new_ProxyMutex())); + s->a = a; + eventProcessor.schedule_in(s, HRTIME_SECONDS(10)); +#endif + this_thread()->execute(); +} diff --git a/iocore/net/test_P_Net.cc b/iocore/net/test_P_Net.cc new file mode 100644 index 00000000..bb742c8e --- /dev/null +++ b/iocore/net/test_P_Net.cc @@ -0,0 +1,112 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_Net.h" + +Diags *diags; +struct NetTesterSM:public Continuation +{ + VIO *read_vio; + IOBufferReader *reader; + NetVConnection *vc; + MIOBuffer *buf; + + NetTesterSM(ProxyMutex * _mutex, NetVConnection * _vc):Continuation(_mutex) + { + MUTEX_TRY_LOCK(lock, mutex, _vc->thread); + ink_release_assert(lock); + vc = _vc; + SET_HANDLER(&NetTesterSM::handle_read); + buf = new_MIOBuffer(8); + reader = buf->alloc_reader(); + read_vio = vc->do_io_read(this, INT64_MAX, buf); + } + + + int handle_read(int event, void *data) + { + int r; + char *str; + switch (event) { + case VC_EVENT_READ_READY: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + printf("%s", str); + fflush(stdout); + break; + case VC_EVENT_READ_COMPLETE: + /* FALLSTHROUGH */ + case VC_EVENT_EOS: + r = reader->read_avail(); + str = NEW(new char[r + 10]); + reader->read(str, r); + printf("%s", str); + fflush(stdout); + case VC_EVENT_ERROR: + vc->do_io_close(); + break; + default: + ink_release_assert(!"unknown event"); + + } + return EVENT_CONT; + } + + +}; + + +struct NetTesterAccept:public Continuation +{ + + NetTesterAccept(ProxyMutex * _mutex):Continuation(_mutex) + { + SET_HANDLER(&NetTesterAccept::handle_accept); + } + + int handle_accept(int event, void *data) + { + printf("Accepted a connection\n"); + fflush(stdout); + NetVConnection *vc = (NetVConnection *) data; + NEW(new NetTesterSM(new_ProxyMutex(), vc)); + return EVENT_CONT; + } + + +}; + + + + +int +main() +{ + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + MIOBuffer *mbuf = new_MIOBuffer(5); + eventProcessor.start(1); + netProcessor.start(); + netProcessor.accept(NEW(new NetTesterAccept(new_ProxyMutex())), 8080, true); + this_thread()->execute(); +} diff --git a/iocore/net/test_P_UDPNet.cc b/iocore/net/test_P_UDPNet.cc new file mode 100644 index 00000000..b18ae1e5 --- /dev/null +++ b/iocore/net/test_P_UDPNet.cc @@ -0,0 +1,214 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include + +#include "P_Net.h" +#include "libts.h" + +//Diags stuff from test_I_Net.cc: +Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i, e; + char *p, *dt, *at; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_IOCORE_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "a+"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} + + +/*This implements a standard Unix echo server: just send every udp packet you + get back to where it came from*/ + +class EchoServer:public Continuation +{ + int sock_fd; + UDPConnection *conn; + + int handlePacket(int event, void *data); + +public: + EchoServer() + : Continuation(new_ProxyMutex()) + { + }; + + bool Start(int port); +}; + +bool +EchoServer::Start(int port) +{ + Action *action; + sockaddr_in addr; + + if (!udpNet.CreateUDPSocket(&sock_fd, &addr, &action, port)) + return false; + + conn = new_UDPConnection(sock_fd); + conn->bindToThread(this); + + SET_HANDLER(&EchoServer::handlePacket); + + conn->recv(this); +} + +int +EchoServer::handlePacket(int event, void *data) +{ + switch (event) { + + case NET_EVENT_DATAGRAM_READ_READY:{ + Queue *q = (Queue *)data; + UDPPacket *p; + + //send what ever we get back to the client + while (p = q->pop()) { + p->m_to = p->m_from; + conn->send(this, p); + } + break; + } + + case NET_EVENT_DATAGRAM_READ_ERROR: + printf("got Read Error exiting\n"); + _exit(1); + + case NET_EVENT_DATAGRAM_WRITE_ERROR: + printf("got write error: %d\n", (int) data); + break; + + default: + printf("got unknown event\n"); + } + + return EVENT_DONE; +} + +int +main(int argc, char *argv[]) +{ + int port = (argc > 1) ? atoi(argv[1]) : 39680; + + init_diags((argc > 2) ? argv[2] : "udp.*", NULL); + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(2); + udpNet.start(1); + + signal(SIGPIPE, SIG_IGN); + + EchoServer server; + server.Start(port); + + this_thread()->execute(); +} diff --git a/iocore/utils/I_Machine.h b/iocore/utils/I_Machine.h new file mode 100644 index 00000000..89ed7bd9 --- /dev/null +++ b/iocore/utils/I_Machine.h @@ -0,0 +1,75 @@ +/** @file + + Machine + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Part of the utils library which contains classes that use multiple + components of the IO-Core to implement some useful functionality. The + classes also serve as good examples of how to use the IO-Core. + + */ + +#ifndef _I_Machine_h +#define _I_Machine_h + + +/** + The Machine is a simple place holder for the hostname and the ip + address of an internet host. + + If a hostname or an IP address is not provided in the constructor, + the hostname defaults to the name of the current processor and the + IP address is the address of the current host. If the host has + multiple IP addresses, the numerically lowest IP address is used. + The IP address is stored in the network byte order. + + */ +struct Machine +{ + char *hostname; // name of the internet host + int hostname_len; // size of the string pointed to by hostname + + unsigned int ip; // IP address of the host (network order) + char *ip_string; // IP address of the host as a string. + int ip_string_len; + char *ip_hex_string; // IP address of the host as a hex string + int ip_hex_string_len; + + Machine(char *hostname = 0, unsigned int ip = 0); + ~Machine(); +}; + +/** + Creates a Machine Object with the hostname and IP address. If no + hostname or IP address is given, the hostname defaults to the name of + the current processor. + + */ +void create_this_machine(char *hostname = 0, unsigned int ip = 0); + +/** + Returns the Machine object created by create_this_machine(). + + */ +Machine *this_machine(); + +#endif diff --git a/iocore/utils/I_OneWayMultiTunnel.h b/iocore/utils/I_OneWayMultiTunnel.h new file mode 100644 index 00000000..96afe3fc --- /dev/null +++ b/iocore/utils/I_OneWayMultiTunnel.h @@ -0,0 +1,154 @@ +/** @file + + One way multi tunnel + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Part of the utils library which contains classes that use multiple + components of the IO-Core to implement some useful functionality. The + classes also serve as good examples of how to use the IO-Core. + + */ + +#if !defined (_I_OneWayMultiTunnel_h_) +#define _I_OneWayMultiTunnel_h_ + +#include "I_OneWayTunnel.h" + +/** Maximum number which can be tunnelled too */ +#define ONE_WAY_MULTI_TUNNEL_LIMIT 4 + +/** + A generic state machine that connects a source virtual conection to + multiple target virtual connections. A OneWayMultiTunnel is similar to + the OneWayTunnel module. However, instead of connection one source + to one target, it connects multiple virtual connections - a source + vc and multiple target vcs, and copies the data from the source + to the target vcs. The maximum number of Target VCs is limited by + ONE_WAY_MULTI_TUNNEL_LIMIT. + + If manipulate_fn is not NULL, then the tunnel acts as a filter, + processing all data arriving from the source vc by the manipulate_fn + function, before sending to the target vcs. By default, the + manipulate_fn is set to NULL, yielding the identity function. + + @see OneWayTunnel + +*/ +struct OneWayMultiTunnel: public OneWayTunnel +{ + // + // Public Interface + // + + // Use these to construct/destruct OneWayMultiTunnel objects + + /** + Allocates a OneWayMultiTunnel object. + + @return new OneWayTunnel object. + + */ + static OneWayMultiTunnel *OneWayMultiTunnel_alloc(); + + /** + Deallocates a OneWayTunnel object. + + */ + static void OneWayMultiTunnel_free(OneWayMultiTunnel *); + + OneWayMultiTunnel(); + + // Use One of the following init functions to start the tunnel. + + /** + This init function sets up the read (calls do_io_read) and the write + (calls do_io_write). + + @param vcSource source VConnection. A do_io_read should not have + been called on the vcSource. The tunnel calls do_io_read on this VC. + @param vcTargets array of Target VConnections. A do_io_write should + not have been called on any of the vcTargets. The tunnel calls + do_io_write on these VCs. + @param n_vcTargets size of vcTargets. + @param aCont continuation to call back when the tunnel finishes. If + not specified, the tunnel deallocates itself without calling + back anybody. + @param size_estimate size of the MIOBuffer to create for reading/ + writing to/from the VC's. + @param nbytes number of bytes to transfer. + @param asingle_buffer whether the same buffer should be used to read + from vcSource and write to vcTarget. This should be set to true + in most cases, unless the data needs be transformed. + @param aclose_source if true, the tunnel closes vcSource at the + end. If aCont is not specified, this should be set to true. + @param aclose_target if true, the tunnel closes vcTarget at the end. + If aCont is not specified, this should be set to true. + @param manipulate_fn if specified, the tunnel calls this function + with the input and the output buffer, whenever it gets new data + in the input buffer. This function can transform the data in the + input buffer. + @param water_mark for the MIOBuffer used for reading. + + */ + void init(VConnection * vcSource, VConnection ** vcTargets, int n_vcTargets, Continuation * aCont = NULL, int size_estimate = 0, // 0 == best guess + int64_t nbytes = TUNNEL_TILL_DONE, + bool asingle_buffer = true, + bool aclose_source = true, + bool aclose_target = true, Transform_fn manipulate_fn = NULL, int water_mark = 0); + + /** + Use this init function if both the read and the write sides have + already been setup. The tunnel assumes that the read VC and the + write VCs are using the same buffer and frees that buffer when the + transfer is done (either successful or unsuccessful). + + @param aCont continuation to call back when the tunnel finishes. If + not specified, the tunnel deallocates itself without calling back + anybody. + @param SourceVio read VIO of the Source VC. + @param TargetVios array of write VIOs of the Target VCs. + @param n_vioTargets size of TargetVios array. + @param aclose_source if true, the tunnel closes vcSource at the + end. If aCont is not specified, this should be set to true. + @param aclose_target ff true, the tunnel closes vcTarget at the + end. If aCont is not specified, this should be set to true. + + */ + void init(Continuation * aCont, VIO * SourceVio, VIO ** TargetVios, int n_vioTargets, bool aclose_source = true, + bool aclose_target = true); + + // + // Private + // + int startEvent(int event, void *data); + + virtual void reenable_all(); + virtual void close_target_vio(int result, VIO * vio = NULL); + + int n_vioTargets; + VIO *vioTargets[ONE_WAY_MULTI_TUNNEL_LIMIT]; + MIOBufferAccessor topOutBuffer; + bool source_read_previously_completed; +}; + +extern ClassAllocator OneWayMultiTunnelAllocator; +#endif diff --git a/iocore/utils/I_OneWayTunnel.h b/iocore/utils/I_OneWayTunnel.h new file mode 100644 index 00000000..8ebaf474 --- /dev/null +++ b/iocore/utils/I_OneWayTunnel.h @@ -0,0 +1,223 @@ +/** @file + + One way tunnel + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Part of the utils library which contains classes that use multiple + components of the IO-Core to implement some useful functionality. The + classes also serve as good examples of how to use the IO-Core. + + */ + +#if !defined (_I_OneWayTunnel_h_) +#define _I_OneWayTunnel_h_ + +#include "I_EventSystem.h" + +////////////////////////////////////////////////////////////////////////////// +// +// OneWayTunnel +// +////////////////////////////////////////////////////////////////////////////// + +#define TUNNEL_TILL_DONE INT64_MAX + +#define ONE_WAY_TUNNEL_CLOSE_ALL NULL + +typedef void (*Transform_fn) (MIOBufferAccessor & in_buf, MIOBufferAccessor & out_buf); + +/** + A generic state machine that connects two virtual conections. A + OneWayTunnel is a module that connects two virtual connections, a source + vc and a target vc, and copies the data between source and target. Once + the tunnel is started using the init() call, it handles all the events + from the source and target and optionally calls a continuation back when + its done. On success it calls back the continuation with VC_EVENT_EOS, + and with VC_EVENT_ERROR on failure. + + If manipulate_fn is not NULL, then the tunnel acts as a filter, + processing all data arriving from the source vc by the manipulate_fn + function, before sending to the target vc. By default, the manipulate_fn + is set to NULL, yielding the identity function. manipulate_fn takes + a IOBuffer containing the data to be written into the target virtual + connection which it may manipulate in any manner it sees fit. + +*/ +struct OneWayTunnel: public Continuation +{ + // + // Public Interface + // + + // Copy nbytes from vcSource to vcTarget. When done, call + // aCont back with either VC_EVENT_EOS (on success) or + // VC_EVENT_ERROR (on error) + // + + // Use these to construct/destruct OneWayTunnel objects + + /** + Allocates a OneWayTunnel object. + + @return new OneWayTunnel object. + + */ + static OneWayTunnel *OneWayTunnel_alloc(); + + /** Deallocates a OneWayTunnel object. */ + static void OneWayTunnel_free(OneWayTunnel *); + + static void SetupTwoWayTunnel(OneWayTunnel * east, OneWayTunnel * west); + OneWayTunnel(); + virtual ~ OneWayTunnel(); + + // Use One of the following init functions to start the tunnel. + /** + This init function sets up the read (calls do_io_read) and the write + (calls do_io_write). + + @param vcSource source VConnection. A do_io_read should not have + been called on the vcSource. The tunnel calls do_io_read on this VC. + @param vcTarget target VConnection. A do_io_write should not have + been called on the vcTarget. The tunnel calls do_io_write on this VC. + @param aCont continuation to call back when the tunnel finishes. If + not specified, the tunnel deallocates itself without calling back + anybody. Otherwise, its the callee's responsibility to deallocate + the tunnel with OneWayTunnel_free. + @param size_estimate size of the MIOBuffer to create for + reading/writing to/from the VC's. + @param aMutex lock that this tunnel will run under. If aCont is + specified, the Continuation's lock is used instead of aMutex. + @param nbytes number of bytes to transfer. + @param asingle_buffer whether the same buffer should be used to read + from vcSource and write to vcTarget. This should be set to true in + most cases, unless the data needs be transformed. + @param aclose_source if true, the tunnel closes vcSource at the + end. If aCont is not specified, this should be set to true. + @param aclose_target if true, the tunnel closes vcTarget at the + end. If aCont is not specified, this should be set to true. + @param manipulate_fn if specified, the tunnel calls this function + with the input and the output buffer, whenever it gets new data + in the input buffer. This function can transform the data in the + input buffer + @param water_mark watermark for the MIOBuffer used for reading. + + */ + void init(VConnection * vcSource, VConnection * vcTarget, Continuation * aCont = NULL, int size_estimate = 0, // 0 = best guess + ProxyMutex * aMutex = NULL, + int64_t nbytes = TUNNEL_TILL_DONE, + bool asingle_buffer = true, + bool aclose_source = true, + bool aclose_target = true, Transform_fn manipulate_fn = NULL, int water_mark = 0); + + /** + This init function sets up only the write side. It assumes that the + read VConnection has already been setup. + + @param vcSource source VConnection. Prior to calling this + init function, a do_io_read should have been called on this + VConnection. The tunnel uses the same MIOBuffer and frees + that buffer when the transfer is done (either successful or + unsuccessful). + @param vcTarget target VConnection. A do_io_write should not have + been called on the vcTarget. The tunnel calls do_io_write on + this VC. + @param aCont The Continuation to call back when the tunnel + finishes. If not specified, the tunnel deallocates itself without + calling back anybody. + @param SourceVio VIO of the vcSource. + @param reader IOBufferReader that reads from the vcSource. This + reader is provided to vcTarget. + @param aclose_source if true, the tunnel closes vcSource at the + end. If aCont is not specified, this should be set to true. + @param aclose_target if true, the tunnel closes vcTarget at the + end. If aCont is not specified, this should be set to true. + */ + void init(VConnection * vcSource, + VConnection * vcTarget, + Continuation * aCont, + VIO * SourceVio, IOBufferReader * reader, bool aclose_source = true, bool aclose_target = true); + + /** + Use this init function if both the read and the write sides have + already been setup. The tunnel assumes that the read VC and the + write VC are using the same buffer and frees that buffer + when the transfer is done (either successful or unsuccessful) + @param aCont The Continuation to call back when the tunnel finishes. If + not specified, the tunnel deallocates itself without calling back + anybody. + + @param SourceVio read VIO of the Source VC. + @param TargetVio write VIO of the Target VC. + @param aclose_source if true, the tunnel closes vcSource at the + end. If aCont is not specified, this should be set to true. + @param aclose_target if true, the tunnel closes vcTarget at the + end. If aCont is not specified, this should be set to true. + + */ + void init(Continuation * aCont, + VIO * SourceVio, VIO * TargetVio, bool aclose_source = true, bool aclose_target = true); + + // + // Private + // + OneWayTunnel(Continuation * aCont, + Transform_fn manipulate_fn = NULL, bool aclose_source = false, bool aclose_target = false); + + int startEvent(int event, void *data); + + virtual void transform(MIOBufferAccessor & in_buf, MIOBufferAccessor & out_buf); + + /** Result is -1 for any error. */ + void close_source_vio(int result); + + virtual void close_target_vio(int result, VIO * vio = ONE_WAY_TUNNEL_CLOSE_ALL); + + void connection_closed(int result); + + virtual void reenable_all(); + + bool last_connection(); + + VIO *vioSource; + VIO *vioTarget; + Continuation *cont; + Transform_fn manipulate_fn; + int n_connections; + int lerrno; + + bool single_buffer; + bool close_source; + bool close_target; + bool tunnel_till_done; + + /** Non-NULL when this is one side of a two way tunnel. */ + OneWayTunnel *tunnel_peer; + bool free_vcs; + +private: + OneWayTunnel(const OneWayTunnel &); + OneWayTunnel & operator =(const OneWayTunnel &); + +}; + +#endif diff --git a/iocore/utils/Machine.cc b/iocore/utils/Machine.cc new file mode 100644 index 00000000..de6eaf90 --- /dev/null +++ b/iocore/utils/Machine.cc @@ -0,0 +1,136 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "I_Machine.h" + +// Singleton +static Machine *machine = NULL; + +// Moved from HttpTransactHeaders.cc, we should probably move this somewhere ... +#define H(_x) (((_x)>9)?((_x)-10+'A'):((_x)+'0')) +int +nstrhex(char *d, unsigned int i) +{ + unsigned char *p = (unsigned char *) &i; + d[0] = H(p[0] >> 4); + d[1] = H(p[0] & 0xF); + d[2] = H(p[1] >> 4); + d[3] = H(p[1] & 0xF); + d[4] = H(p[2] >> 4); + d[5] = H(p[2] & 0xF); + d[6] = H(p[3] >> 4); + d[7] = H(p[3] & 0xF); + return 8; +} + + +// Machine class. TODO: This has to deal with IPv6! +Machine * +this_machine() +{ + if (machine == NULL) { + ink_assert("need to call create_this_machine before accessing" "this_machine()"); + } + return machine; +} + +void +create_this_machine(char *hostname, unsigned int ip) +{ + machine = NEW(new Machine(hostname, ip)); +} + +Machine::Machine(char *ahostname, unsigned int aip) + : hostname(ahostname), ip(aip) +{ + if (!aip) { + char localhost[1024]; + + if (!ahostname) { + ink_release_assert(!gethostname(localhost, 1023)); + ahostname = localhost; + } + hostname = xstrdup(ahostname); + + ink_gethostbyname_r_data data; + struct hostent *r = ink_gethostbyname_r(ahostname, &data); + + if (!r) { + Warning("unable to DNS %s: %d", ahostname, data.herrno); + ip = 0; + } else { + ip = (unsigned int) -1; // 0xFFFFFFFF + for (int i = 0; r->h_addr_list[i]; i++) { + if (ip > *(unsigned int *) r->h_addr_list[i]) + ip = *(unsigned int *) r->h_addr_list[i]; + } + if (ip == (unsigned int) -1) + ip = 0; + } + //ip = htonl(ip); for the alpha! TODO + } else { + ip = aip; + + ink_gethostbyaddr_r_data data; + struct hostent *r = ink_gethostbyaddr_r((char *) &ip, sizeof(int), AF_INET, &data); + + if (r == NULL) { + unsigned char x[4]; + + memset(x, 0, sizeof(x)); + *(uint32_t *) & x = (uint32_t) ip; + Debug("machine_debug", "unable to reverse DNS %hhu.%hhu.%hhu.%hhu: %d", x[0], x[1], x[2], x[3], data.herrno); + } else + hostname = xstrdup(r->h_name); + } + + if (hostname) + hostname_len = strlen(hostname); + else + hostname_len = 0; + + unsigned char x[4]; + + memset(x, 0, sizeof(x)); + *(uint32_t *) & x = (uint32_t) ip; + const size_t ip_string_size = sizeof(char) * 16; + ip_string = (char *) xmalloc(ip_string_size); + snprintf(ip_string, ip_string_size, "%hhu.%hhu.%hhu.%hhu", x[0], x[1], x[2], x[3]); + ip_string_len = strlen(ip_string); + + ip_hex_string = (char*)xmalloc(9); + memset(ip_hex_string, 0, 9); + nstrhex(ip_hex_string, ip); + ip_hex_string_len = strlen(ip_hex_string); +} + +Machine::~Machine() +{ + if (hostname) + xfree(hostname); + if (ip_string) + xfree(ip_string); + if (ip_hex_string) + xfree(ip_hex_string); +} diff --git a/iocore/utils/Makefile.am b/iocore/utils/Makefile.am new file mode 100644 index 00000000..827dea0c --- /dev/null +++ b/iocore/utils/Makefile.am @@ -0,0 +1,34 @@ +# Makefile.am for the traffic/iocore/utils hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/iocore/eventsystem + +DEFS += @IOCORE_MODULARIZED_DEFS@ + +noinst_LIBRARIES = libinkutils.a + +libinkutils_a_SOURCES = \ + I_Machine.h \ + I_OneWayMultiTunnel.h \ + I_OneWayTunnel.h \ + Machine.cc \ + OneWayMultiTunnel.cc \ + OneWayTunnel.cc + diff --git a/iocore/utils/Makefile.in b/iocore/utils/Makefile.in new file mode 100644 index 00000000..d293f992 --- /dev/null +++ b/iocore/utils/Makefile.in @@ -0,0 +1,705 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the traffic/iocore/utils hierarchy +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = iocore/utils +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libinkutils_a_AR = $(AR) $(ARFLAGS) +libinkutils_a_LIBADD = +am_libinkutils_a_OBJECTS = Machine.$(OBJEXT) \ + OneWayMultiTunnel.$(OBJEXT) OneWayTunnel.$(OBJEXT) +libinkutils_a_OBJECTS = $(am_libinkutils_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libinkutils_a_SOURCES) +DIST_SOURCES = $(libinkutils_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @IOCORE_MODULARIZED_DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/iocore/eventsystem + +noinst_LIBRARIES = libinkutils.a +libinkutils_a_SOURCES = \ + I_Machine.h \ + I_OneWayMultiTunnel.h \ + I_OneWayTunnel.h \ + Machine.cc \ + OneWayMultiTunnel.cc \ + OneWayTunnel.cc + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign iocore/utils/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign iocore/utils/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libinkutils.a: $(libinkutils_a_OBJECTS) $(libinkutils_a_DEPENDENCIES) + -rm -f libinkutils.a + $(libinkutils_a_AR) libinkutils.a $(libinkutils_a_OBJECTS) $(libinkutils_a_LIBADD) + $(RANLIB) libinkutils.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Machine.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OneWayMultiTunnel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OneWayTunnel.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/iocore/utils/OneWayMultiTunnel.cc b/iocore/utils/OneWayMultiTunnel.cc new file mode 100644 index 00000000..549f51dc --- /dev/null +++ b/iocore/utils/OneWayMultiTunnel.cc @@ -0,0 +1,256 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + OneWayMultiTunnel.h + ****************************************************************************/ + +#include "P_EventSystem.h" +#include "I_OneWayMultiTunnel.h" + +// #define TEST + +////////////////////////////////////////////////////////////////////////////// +// +// OneWayMultiTunnel::OneWayMultiTunnel() +// +////////////////////////////////////////////////////////////////////////////// + +ClassAllocator OneWayMultiTunnelAllocator("OneWayMultiTunnelAllocator"); + +OneWayMultiTunnel::OneWayMultiTunnel(): +OneWayTunnel(), n_vioTargets(0), source_read_previously_completed(false) +{ +} + +OneWayMultiTunnel * +OneWayMultiTunnel::OneWayMultiTunnel_alloc() +{ + return OneWayMultiTunnelAllocator.alloc(); +} + +void +OneWayMultiTunnel::OneWayMultiTunnel_free(OneWayMultiTunnel * pOWT) +{ + + pOWT->mutex = NULL; + OneWayMultiTunnelAllocator.free(pOWT); +} + +void +OneWayMultiTunnel::init(VConnection * vcSource, VConnection ** vcTargets, int n_vcTargets, Continuation * aCont, int size_estimate, int64_t nbytes, bool asingle_buffer, /* = true */ + bool aclose_source, /* = false */ + bool aclose_targets, /* = false */ + Transform_fn aManipulate_fn, int water_mark) +{ + mutex = aCont ? (ProxyMutex *) aCont->mutex : new_ProxyMutex(); + cont = aCont; + manipulate_fn = aManipulate_fn; + close_source = aclose_source; + close_target = aclose_targets; + source_read_previously_completed = false; + + SET_HANDLER(&OneWayMultiTunnel::startEvent); + + n_connections = n_vioTargets + 1; + + int64_t size_index = 0; + if (size_estimate) + size_index = buffer_size_to_index(size_estimate, default_large_iobuffer_size); + else + size_index = default_large_iobuffer_size; + + tunnel_till_done = (nbytes == TUNNEL_TILL_DONE); + + MIOBuffer *buf1 = new_MIOBuffer(size_index); + MIOBuffer *buf2 = NULL; + + single_buffer = asingle_buffer; + + if (single_buffer) + buf2 = buf1; + else + buf2 = new_MIOBuffer(size_index); + topOutBuffer.writer_for(buf2); + + buf1->water_mark = water_mark; + + vioSource = vcSource->do_io(VIO::READ, this, nbytes, buf1, 0); + + ink_assert(n_vcTargets <= ONE_WAY_MULTI_TUNNEL_LIMIT); + for (int i = 0; i < n_vcTargets; i++) + vioTargets[i] = vcTargets[i]->do_io(VIO::WRITE, this, INT64_MAX, buf2, 0); + + return; +} + +void +OneWayMultiTunnel::init(Continuation * aCont, + VIO * SourceVio, VIO ** TargetVios, int n_TargetVios, bool aclose_source, bool aclose_targets) +{ + + mutex = aCont ? (ProxyMutex *) aCont->mutex : new_ProxyMutex(); + cont = aCont; + single_buffer = true; + manipulate_fn = 0; + n_connections = n_TargetVios + 1;; + close_source = aclose_source; + close_target = aclose_targets; + // The read on the source vio may have already been completed, yet + // we still need to write data into the target buffers. Note this + // fact as we'll not get a VC_EVENT_READ_COMPLETE callback later. + source_read_previously_completed = (SourceVio->ntodo() == 0); + tunnel_till_done = true; + n_vioTargets = n_TargetVios; + topOutBuffer.writer_for(SourceVio->buffer.writer()); + + // do_io_read() read already posted on vcSource. + // do_io_write() already posted on vcTargets + SET_HANDLER(&OneWayMultiTunnel::startEvent); + + SourceVio->set_continuation(this); + vioSource = SourceVio; + + for (int i = 0; i < n_vioTargets; i++) { + vioTargets[i] = TargetVios[i]; + vioTargets[i]->set_continuation(this); + } + +} + +////////////////////////////////////////////////////////////////////////////// +// +// int OneWayMultiTunnel::startEvent() +// +////////////////////////////////////////////////////////////////////////////// + +int +OneWayMultiTunnel::startEvent(int event, void *data) +{ + VIO *vio = (VIO *) data; + int ret = VC_EVENT_DONE; + int result = 0; + +#ifdef TEST + const char *event_origin = (vio == vioSource ? "source" : "target"), *event_name = get_vc_event_name(event); + printf("OneWayMultiTunnel::startEvent --- %s received from %s VC\n", event_name, event_origin); +#endif + + // handle the event + // + switch (event) { + + case VC_EVENT_READ_READY:{ // SunCC uses old scoping rules + transform(vioSource->buffer, topOutBuffer); + for (int i = 0; i < n_vioTargets; i++) + if (vioTargets[i]) + vioTargets[i]->reenable(); + ret = VC_EVENT_CONT; + break; + } + + case VC_EVENT_WRITE_READY: + if (vioSource) + vioSource->reenable(); + ret = VC_EVENT_CONT; + break; + + case VC_EVENT_EOS: + if (!tunnel_till_done && vio->ntodo()) + goto Lerror; + if (vio == vioSource) { + transform(vioSource->buffer, topOutBuffer); + goto Lread_complete; + } else + goto Lwrite_complete; + + Lread_complete: + case VC_EVENT_READ_COMPLETE:{// SunCC uses old scoping rules + // set write nbytes to the current buffer size + // + for (int i = 0; i < n_vioTargets; i++) + if (vioTargets[i]) { + vioTargets[i]->nbytes = vioTargets[i]->ndone + vioTargets[i]->buffer.reader()->read_avail(); + vioTargets[i]->reenable(); + } + close_source_vio(0); + ret = VC_EVENT_DONE; + break; + } + + Lwrite_complete: + case VC_EVENT_WRITE_COMPLETE: + close_target_vio(0, (VIO *) data); + if ((n_connections == 0) || (n_connections == 1 && source_read_previously_completed)) + goto Ldone; + else if (vioSource) + vioSource->reenable(); + break; + + Lerror: + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + result = -1; + Ldone: + close_source_vio(result); + close_target_vio(result); + connection_closed(result); + break; + + default: + ret = VC_EVENT_CONT; + break; + } +#ifdef TEST + printf(" (OneWayMultiTunnel returning value: %s)\n", (ret == VC_EVENT_DONE ? "VC_EVENT_DONE" : "VC_EVENT_CONT")); +#endif + return (ret); +} + +void +OneWayMultiTunnel::close_target_vio(int result, VIO * vio) +{ + for (int i = 0; i < n_vioTargets; i++) { + VIO *v = vioTargets[i]; + if (v && (!vio || v == vio)) { + if (last_connection() || !single_buffer) + free_MIOBuffer(v->buffer.writer()); + if (close_target) + v->vc_server->do_io(result ? VIO::ABORT : VIO::CLOSE); + vioTargets[i] = NULL; + n_connections--; + } + } +} + +void +OneWayMultiTunnel::reenable_all() +{ + for (int i = 0; i < n_vioTargets; i++) + if (vioTargets[i]) + vioTargets[i]->reenable(); + if (vioSource) + vioSource->reenable(); +} diff --git a/iocore/utils/OneWayTunnel.cc b/iocore/utils/OneWayTunnel.cc new file mode 100644 index 00000000..7b4eee16 --- /dev/null +++ b/iocore/utils/OneWayTunnel.cc @@ -0,0 +1,384 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + OneWayTunnel.cc + + A OneWayTunnel is a module that connects two virtual connections, a + source vc and a target vc, and copies the data between source and target. + + This class used to be called HttpTunnelVC, but it doesn't seem to have + anything to do with HTTP, so it has been renamed to OneWayTunnel. + ****************************************************************************/ + +#include "P_EventSystem.h" +#include "I_OneWayTunnel.h" + +// #define TEST + +////////////////////////////////////////////////////////////////////////////// +// +// OneWayTunnel::OneWayTunnel() +// +////////////////////////////////////////////////////////////////////////////// + +ClassAllocator OneWayTunnelAllocator("OneWayTunnelAllocator"); + +inline void +transfer_data(MIOBufferAccessor & in_buf, MIOBufferAccessor & out_buf) +{ + ink_release_assert(!"Not Implemented."); + + int64_t n = in_buf.reader()->read_avail(); + int64_t o = out_buf.writer()->write_avail(); + + if (n > o) + n = o; + if (!n) + return; + memcpy(in_buf.reader()->start(), out_buf.writer()->end(), n); + in_buf.reader()->consume(n); + out_buf.writer()->fill(n); +} + +OneWayTunnel::OneWayTunnel():Continuation(0), +vioSource(0), vioTarget(0), cont(0), manipulate_fn(0), +n_connections(0), lerrno(0), single_buffer(0), +close_source(0), close_target(0), tunnel_till_done(0), tunnel_peer(0), free_vcs(true) +{ +} + +OneWayTunnel * +OneWayTunnel::OneWayTunnel_alloc() +{ + return OneWayTunnelAllocator.alloc(); +} + +void +OneWayTunnel::OneWayTunnel_free(OneWayTunnel * pOWT) +{ + + pOWT->mutex = NULL; + OneWayTunnelAllocator.free(pOWT); +} + +void +OneWayTunnel::SetupTwoWayTunnel(OneWayTunnel * east, OneWayTunnel * west) +{ + //make sure the both use the same mutex + ink_assert(east->mutex == west->mutex); + + east->tunnel_peer = west; + west->tunnel_peer = east; +} + +OneWayTunnel::~OneWayTunnel() +{ +} + +OneWayTunnel::OneWayTunnel(Continuation * aCont, Transform_fn aManipulate_fn, bool aclose_source, bool aclose_target) +: +Continuation(aCont + ? (ProxyMutex *) aCont->mutex + : new_ProxyMutex()), +cont(aCont), +manipulate_fn(aManipulate_fn), +n_connections(2), +lerrno(0), +single_buffer(true), close_source(aclose_source), close_target(aclose_target), tunnel_till_done(false), free_vcs(false) +{ + ink_assert(!"This form of OneWayTunnel() constructor not supported"); +} + +void +OneWayTunnel::init(VConnection * vcSource, + VConnection * vcTarget, + Continuation * aCont, + int size_estimate, + ProxyMutex * aMutex, + int64_t nbytes, + bool asingle_buffer, + bool aclose_source, bool aclose_target, Transform_fn aManipulate_fn, int water_mark) +{ + mutex = aCont ? (ProxyMutex *) aCont->mutex : (aMutex ? aMutex : new_ProxyMutex()); + cont = aMutex ? NULL : aCont; + single_buffer = asingle_buffer; + manipulate_fn = aManipulate_fn; + n_connections = 2; + close_source = aclose_source; + close_target = aclose_target; + lerrno = 0; + tunnel_till_done = (nbytes == TUNNEL_TILL_DONE); + + SET_HANDLER(&OneWayTunnel::startEvent); + + int64_t size_index = 0; + + if (size_estimate) + size_index = buffer_size_to_index(size_estimate); + else + size_index = default_large_iobuffer_size; + + Debug("one_way_tunnel", "buffer size index [%d] [%d]\n", size_index, size_estimate); + + // enqueue read request on vcSource. + MIOBuffer *buf1 = new_MIOBuffer(size_index); + MIOBuffer *buf2 = NULL; + if (single_buffer) + buf2 = buf1; + else + buf2 = new_MIOBuffer(size_index); + + buf1->water_mark = water_mark; + + MUTEX_LOCK(lock, mutex, this_ethread()); + vioSource = vcSource->do_io_read(this, nbytes, buf1); + vioTarget = vcTarget->do_io_write(this, nbytes, buf2->alloc_reader(), 0); + ink_assert(vioSource && vioTarget); + + return; +} + +void +OneWayTunnel::init(VConnection * vcSource, + VConnection * vcTarget, + Continuation * aCont, + VIO * SourceVio, IOBufferReader * reader, bool aclose_source, bool aclose_target) +{ + (void) vcSource; + mutex = aCont ? (ProxyMutex *) aCont->mutex : new_ProxyMutex(); + cont = aCont; + single_buffer = true; + manipulate_fn = 0; + n_connections = 2; + close_source = aclose_source; + close_target = aclose_target; + tunnel_till_done = true; + + // Prior to constructing the OneWayTunnel, we initiated a do_io(VIO::READ) + // on the source VC. We wish to use the same MIO buffer in the tunnel. + + // do_io() read already posted on vcSource. + SET_HANDLER(&OneWayTunnel::startEvent); + + SourceVio->set_continuation(this); + MUTEX_LOCK(lock, mutex, this_ethread()); + vioSource = SourceVio; + + vioTarget = vcTarget->do_io_write(this, TUNNEL_TILL_DONE, reader, 0); + ink_assert(vioSource && vioTarget); +} + +void +OneWayTunnel::init(Continuation * aCont, VIO * SourceVio, VIO * TargetVio, bool aclose_source, bool aclose_target) +{ + mutex = aCont ? (ProxyMutex *) aCont->mutex : new_ProxyMutex(); + cont = aCont; + single_buffer = true; + manipulate_fn = 0; + n_connections = 2; + close_source = aclose_source; + close_target = aclose_target; + tunnel_till_done = true; + + // do_io_read() read already posted on vcSource. + // do_io_write() already posted on vcTarget + SET_HANDLER(&OneWayTunnel::startEvent); + + ink_assert(SourceVio && TargetVio); + + SourceVio->set_continuation(this); + TargetVio->set_continuation(this); + vioSource = SourceVio; + vioTarget = TargetVio; +} + + +void +OneWayTunnel::transform(MIOBufferAccessor & in_buf, MIOBufferAccessor & out_buf) +{ + if (manipulate_fn) + manipulate_fn(in_buf, out_buf); + else if (in_buf.writer() != out_buf.writer()) + transfer_data(in_buf, out_buf); +} + +////////////////////////////////////////////////////////////////////////////// +// +// int OneWayTunnel::startEvent() +// +////////////////////////////////////////////////////////////////////////////// + +// +// tunnel was invoked with an event +// +int +OneWayTunnel::startEvent(int event, void *data) +{ + VIO *vio = (VIO *) data; + int ret = VC_EVENT_DONE; + int result = 0; + +#ifdef TEST + const char *event_origin = (vio == vioSource ? "source" : "target"), *event_name = get_vc_event_name(event); + printf("OneWayTunnel --- %s received from %s VC\n", event_name, event_origin); +#endif + + if (!vioTarget) + goto Lerror; + + // handle the event + // + switch (event) { + + case ONE_WAY_TUNNEL_EVENT_PEER_CLOSE: + /* This event is sent out by our peer */ + ink_assert(tunnel_peer); + tunnel_peer = NULL; + free_vcs = false; + goto Ldone; + + case VC_EVENT_READ_READY: + transform(vioSource->buffer, vioTarget->buffer); + vioTarget->reenable(); + ret = VC_EVENT_CONT; + break; + + case VC_EVENT_WRITE_READY: + if (vioSource) + vioSource->reenable(); + ret = VC_EVENT_CONT; + break; + + case VC_EVENT_EOS: + if (!tunnel_till_done && vio->ntodo()) + goto Lerror; + if (vio == vioSource) { + transform(vioSource->buffer, vioTarget->buffer); + goto Lread_complete; + } else + goto Ldone; + + Lread_complete: + case VC_EVENT_READ_COMPLETE: + // set write nbytes to the current buffer size + // + vioTarget->nbytes = vioTarget->ndone + vioTarget->buffer.reader()->read_avail(); + if (vioTarget->nbytes == vioTarget->ndone) + goto Ldone; + vioTarget->reenable(); + if (!tunnel_peer) + close_source_vio(0); + break; + + Lerror: + case VC_EVENT_ERROR: + lerrno = ((VIO *) data)->vc_server->lerrno; + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + result = -1; + Ldone: + case VC_EVENT_WRITE_COMPLETE: + if (tunnel_peer) { + //inform the peer: + tunnel_peer->startEvent(ONE_WAY_TUNNEL_EVENT_PEER_CLOSE, data); + } + close_source_vio(result); + close_target_vio(result); + connection_closed(result); + break; + + default: + ink_assert(!"bad case"); + ret = VC_EVENT_CONT; + break; + } +#ifdef TEST + printf(" (OneWayTunnel returning value: %s)\n", (ret == VC_EVENT_DONE ? "VC_EVENT_DONE" : "VC_EVENT_CONT")); +#endif + return ret; +} + +// If result is Non-zero, the vc should be aborted. +void +OneWayTunnel::close_source_vio(int result) +{ + + if (vioSource) { + if (last_connection() || !single_buffer) + free_MIOBuffer(vioSource->buffer.mbuf); + if (close_source && free_vcs) + vioSource->vc_server->do_io_close(result ? lerrno : -1); + vioSource = NULL; + n_connections--; + } +} + +void +OneWayTunnel::close_target_vio(int result, VIO * vio) +{ + + (void) vio; + if (vioTarget) { + if (last_connection() || !single_buffer) + free_MIOBuffer(vioTarget->buffer.mbuf); + if (close_target && free_vcs) + vioTarget->vc_server->do_io_close(result ? lerrno : -1); + vioTarget = NULL; + n_connections--; + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// void OneWayTunnel::connection_closed +// +////////////////////////////////////////////////////////////////////////////// +void +OneWayTunnel::connection_closed(int result) +{ + if (cont) { +#ifdef TEST + cout << "OneWayTunnel::connection_closed() ... calling cont" << endl; +#endif + cont->handleEvent(result ? VC_EVENT_ERROR : VC_EVENT_EOS, cont); + } else { + OneWayTunnel_free(this); + } +} + +void +OneWayTunnel::reenable_all() +{ + if (vioSource) + vioSource->reenable(); + if (vioTarget) + vioTarget->reenable(); +} + +bool +OneWayTunnel::last_connection() +{ + return n_connections == 1; +} diff --git a/iocore/utils/diags.i b/iocore/utils/diags.i new file mode 100644 index 00000000..33774de7 --- /dev/null +++ b/iocore/utils/diags.i @@ -0,0 +1,121 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +//Diags *diags; +#define DIAGS_LOG_FILE "diags.log" + +////////////////////////////////////////////////////////////////////////////// +// +// void reconfigure_diags() +// +// This function extracts the current diags configuration settings from +// records.config, and rebuilds the Diags data structures. +// +////////////////////////////////////////////////////////////////////////////// + +static void +reconfigure_diags() +{ + int i; + DiagsConfigState c; + + + // initial value set to 0 or 1 based on command line tags + c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL); + c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL); + + c.enabled[DiagsTagType_Debug] = 1; + c.enabled[DiagsTagType_Action] = 1; + diags->show_location = 1; + + + // read output routing values + for (i = 0; i < DiagsLevel_Count; i++) { + + c.outputs[i].to_stdout = 0; + c.outputs[i].to_stderr = 1; + c.outputs[i].to_syslog = 1; + c.outputs[i].to_diagslog = 1; + } + + ////////////////////////////// + // clear out old tag tables // + ////////////////////////////// + + diags->deactivate_all(DiagsTagType_Debug); + diags->deactivate_all(DiagsTagType_Action); + + ////////////////////////////////////////////////////////////////////// + // add new tag tables + ////////////////////////////////////////////////////////////////////// + + if (diags->base_debug_tags) + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + if (diags->base_action_tags) + diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action); + + //////////////////////////////////// + // change the diags config values // + //////////////////////////////////// +#if !defined (_WIN32) && !defined(__GNUC__) && !defined(hpux) + diags->config = c; +#else + memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState)); +#endif + +} + + + +static void +init_diags(char *bdt, char *bat) +{ + FILE *diags_log_fp; + char diags_logpath[500]; + strcpy(diags_logpath, DIAGS_LOG_FILE); + + diags_log_fp = fopen(diags_logpath, "w"); + if (diags_log_fp) { + int status; + status = setvbuf(diags_log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(diags_log_fp); + diags_log_fp = NULL; + } + } + + diags = NEW(new Diags(bdt, bat, diags_log_fp)); + + if (diags_log_fp == NULL) { + SrcLoc loc(__FILE__, __FUNCTION__, __LINE__); + + diags->print(NULL, DL_Warning, NULL, &loc, + "couldn't open diags log file '%s', " "will not log to this file", diags_logpath); + } + + diags->print(NULL, DL_Status, "STATUS", NULL, "opened %s", diags_logpath); + reconfigure_diags(); + +} diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..3507cfb2 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,24 @@ +# lib Makefile.am +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = ts records + +# TsConfig is only built for WCCP until the bugs are worked out. +if BUILD_WCCP +SUBDIRS += tsconfig wccp +endif diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 00000000..73ae4493 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,774 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# lib Makefile.am +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ + +# TsConfig is only built for WCCP until the bugs are worked out. +@BUILD_WCCP_TRUE@am__append_1 = tsconfig wccp +subdir = lib +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = ts records tsconfig wccp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +SUBDIRS = ts records $(am__append_1) +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/records/I_RecAlarms.h b/lib/records/I_RecAlarms.h new file mode 100644 index 00000000..985c656a --- /dev/null +++ b/lib/records/I_RecAlarms.h @@ -0,0 +1,58 @@ +/** @file + + Public REC_ALARM defines + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_ALARMS_H_ +#define _I_REC_ALARMS_H_ + +// copy from mgmt/Alarms.h +#define REC_ALARM_PROXY_PROCESS_DIED 1 +#define REC_ALARM_PROXY_PROCESS_BORN 2 +#define REC_ALARM_PROXY_PEER_BORN 3 +#define REC_ALARM_PROXY_PEER_DIED 4 +#define REC_ALARM_PROXY_CONFIG_ERROR 5 +#define REC_ALARM_PROXY_SYSTEM_ERROR 6 +#define REC_ALARM_PROXY_LOG_SPACE_CRISIS 7 +#define REC_ALARM_PROXY_CACHE_ERROR 8 +#define REC_ALARM_PROXY_CACHE_WARNING 9 +#define REC_ALARM_PROXY_LOGGING_ERROR 10 +#define REC_ALARM_PROXY_LOGGING_WARNING 11 +// Currently unused: 12 +#define REC_ALARM_REC_TEST 13 +#define REC_ALARM_CONFIG_UPDATE_FAILED 14 +#define REC_ALARM_WEB_ERROR 15 +#define REC_ALARM_PING_FAILURE 16 +#define REC_ALARM_REC_CONFIG_ERROR 17 +#define REC_ALARM_ADD_ALARM 18 +#define REC_ALARM_PROXY_LOG_SPACE_ROLLED 19 +#define REC_ALARM_PROXY_HTTP_CONGESTED_SERVER 20 +#define REC_ALARM_PROXY_HTTP_ALLEVIATED_SERVER 21 + +#define REC_ALARM_WDA_BILLING_CONNECTION_DIED 100 +#define REC_ALARM_WDA_BILLING_CORRUPTED_DATA 101 +#define REC_ALARM_WDA_XF_ENGINE_DOWN 102 +#define REC_ALARM_WDA_RADIUS_CORRUPTED_PACKETS 103 + +#define REC_ALARM_ACC_ALARMS_START 200 +#define REC_ALARM_ACC_ALARMS_END 299 + +#endif diff --git a/lib/records/I_RecCore.h b/lib/records/I_RecCore.h new file mode 100644 index 00000000..c3f22244 --- /dev/null +++ b/lib/records/I_RecCore.h @@ -0,0 +1,248 @@ +/** @file + + Public RecCore declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_CORE_H_ +#define _I_REC_CORE_H_ + +#include "ink_bool.h" +#include "Diags.h" + +#include "I_RecDefs.h" +#include "I_RecAlarms.h" +#include "I_RecSignals.h" +#include "I_RecEvents.h" + + +//------------------------------------------------------------------------- +// Diagnostic Output +//------------------------------------------------------------------------- +int RecSetDiags(Diags * diags); + + +//------------------------------------------------------------------------- +// Stat Registration +//------------------------------------------------------------------------- +int RecRegisterStatInt(RecT rec_type, const char *name, RecInt data_default, RecPersistT persist_type); +int RecRegisterStatFloat(RecT rec_type, const char *name, RecFloat data_default, RecPersistT persist_type); +int RecRegisterStatString(RecT rec_type, const char *name, RecString data_default, RecPersistT persist_type); +int RecRegisterStatCounter(RecT rec_type, const char *name, RecCounter data_default, RecPersistT persist_type); + + +//------------------------------------------------------------------------- +// Config Registration +//------------------------------------------------------------------------- + +int RecRegisterConfigInt(RecT rec_type, const char *name, + RecInt data_default, RecUpdateT update_type, + RecCheckT check_type, const char *ccheck_regex, RecAccessT access_type = RECA_NULL); + +int RecRegisterConfigFloat(RecT rec_type, const char *name, + RecFloat data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type = RECA_NULL); + +int RecRegisterConfigString(RecT rec_type, const char *name, + const char *data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type = RECA_NULL); + +int RecRegisterConfigCounter(RecT rec_type, const char *name, + RecCounter data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type = RECA_NULL); + +//------------------------------------------------------------------------- +// Config Change Notification +//------------------------------------------------------------------------- + +int RecLinkConfigInt(const char *name, RecInt * rec_int); +int RecLinkConfigInk32(const char *name, int32_t * p_int32); +int RecLinkConfigInkU32(const char *name, uint32_t * p_uint32); +int RecLinkConfigFloat(const char *name, RecFloat * rec_float); +int RecLinkConfigCounter(const char *name, RecCounter * rec_counter); +int RecLinkConfigString(const char *name, RecString * rec_string); +int RecLinkConfigByte(const char *name, RecByte * rec_byte); + +int RecRegisterConfigUpdateCb(const char *name, RecConfigUpdateCb update_cb, void *cookie); +int RecRegisterRawStatUpdateFunc(const char *name, RecRawStatBlock * rsb, int id, RecStatUpdateFunc update_func, void *cookie); + + +//------------------------------------------------------------------------- +// Record Reading/Writing +//------------------------------------------------------------------------- + +// WARNING! Avoid deadlocks by calling the following set/get calls +// with the appropiate locking conventions. If you're calling these +// functions from a configuration update callback (RecConfigUpdateCb), +// be sure to set 'lock' to 'false' as the hash-table rwlock has +// already been taken out for the callback. + +// RecSetRecordConvert -> WebMgmtUtils.cc::varSetFromStr() +int RecSetRecordConvert(const char *name, const RecString rec_string, bool lock = true); +int RecSetRecordInt(const char *name, RecInt rec_int, bool lock = true); +int RecSetRecordFloat(const char *name, RecFloat rec_float, bool lock = true); +int RecSetRecordString(const char *name, const RecString rec_string, bool lock = true); +int RecSetRecordCounter(const char *name, RecCounter rec_counter, bool lock = true); + +int RecGetRecordInt(const char *name, RecInt * rec_int, bool lock = true); +int RecGetRecordFloat(const char *name, RecFloat * rec_float, bool lock = true); +int RecGetRecordString(const char *name, char *buf, int buf_len, bool lock = true); +int RecGetRecordString_Xmalloc(const char *name, RecString * rec_string, bool lock = true); +int RecGetRecordCounter(const char *name, RecCounter * rec_counter, bool lock = true); +// Convenience to allow us to treat the RecInt as a single byte internally +int RecGetRecordByte(const char *name, RecByte * rec_byte, bool lock = true); + +//------------------------------------------------------------------------ +// Record Attributes Reading +//------------------------------------------------------------------------ +int RecGetRecordType(const char *name, RecT * rec_type, bool lock = true); +int RecGetRecordDataType(const char *name, RecDataT * data_type, bool lock = true); +int RecGetRecordUpdateCount(RecT data_type); +int RecGetRecordOrderAndId(const char *name, int *order, int *id, bool lock = true); + +int RecGetRecordUpdateType(const char *name, RecUpdateT * update_type, bool lock = true); +int RecGetRecordCheckType(const char *name, RecCheckT * check_type, bool lock = true); +int RecGetRecordCheckExpr(const char *name, char **check_expr, bool lock = true); +int RecGetRecordDefaultDataString_Xmalloc(char *name, char **buf, bool lock = true); + +int RecGetRecordAccessType(const char *name, RecAccessT * secure, bool lock = true); +int RecSetRecordAccessType(const char *name, RecAccessT secure, bool lock = true); + +void RecGetRecordTree(char *subtree = NULL); +void RecGetRecordList(char *, char ***, int *); +int RecGetRecordPrefix_Xmalloc(char *prefix, char **result, int *result_len); + + +//------------------------------------------------------------------------ +// Signal and Alarms +//------------------------------------------------------------------------ +void RecSignalManager(int, const char *); + + +//------------------------------------------------------------------------- +// Backwards Compatibility Items (REC_ prefix) +//------------------------------------------------------------------------- +#define REC_ReadConfigInt32(_var,_config_var_name) do { \ + RecInt tmp = 0; \ + RecGetRecordInt(_config_var_name, (RecInt*) &tmp); \ + _var = (int32_t)tmp; \ +} while (0) + +#define REC_ReadConfigInteger(_var,_config_var_name) do { \ + RecInt tmp = 0; \ + RecGetRecordInt(_config_var_name, &tmp); \ + _var = tmp; \ +} while (0) + +#define REC_ReadConfigFloat(_var,_config_var_name) do { \ + RecFloat tmp = 0; \ + RecGetRecordFloat(_config_var_name, &tmp); \ + _var = tmp; \ +} while (0) + +#define REC_ReadConfigStringAlloc(_var,_config_var_name) \ + RecGetRecordString_Xmalloc(_config_var_name, (RecString*)&_var) + +#define REC_ReadConfigString(_var, _config_var_name, _len) \ + RecGetRecordString(_config_var_name, _var, _len) + +#define REC_RegisterConfigUpdateFunc(_config_var_name, func, flag) \ + RecRegisterConfigUpdateCb(_config_var_name, func, flag) + +#define REC_EstablishStaticConfigInteger(_var, _config_var_name) do { \ + RecLinkConfigInt(_config_var_name, &_var); \ + _var = (int64_t)REC_ConfigReadInteger(_config_var_name); \ +} while (0) + +#define REC_EstablishStaticConfigInt32(_var, _config_var_name) do { \ + RecLinkConfigInk32(_config_var_name, &_var); \ + _var = (int32_t)REC_ConfigReadInteger(_config_var_name); \ +} while (0) + +#define REC_EstablishStaticConfigInt32U(_var, _config_var_name) do { \ + RecLinkConfigInkU32(_config_var_name, &_var); \ + _var = (int32_t)REC_ConfigReadInteger(_config_var_name); \ +} while (0) + +/* + * RecLinkConfigString allocates the RecString and stores the ptr to it (&var). + * So before changing _var (the RecString) we have to free the original one. + * Really, we somehow need to know whether RecLinkConfigString allocated _var. + * For now, we're using the return value to indicate this, even though it's + * not always the case. If we're wrong, we'll leak the RecString. + */ +#define REC_EstablishStaticConfigStringAlloc(_var, _config_var_name) do { \ + if (RecLinkConfigString(_config_var_name, &_var) == REC_ERR_OKAY) \ + xfree(_var); \ + _var = (RecString)REC_ConfigReadString(_config_var_name); \ +} while (0) + +#define REC_EstablishStaticConfigFloat(_var, _config_var_name) do { \ + RecLinkConfigFloat(_config_var_name, &_var); \ + _var = (RecFloat)REC_ConfigReadFloat(_config_var_name); \ +} while (0) + +// Allow to treat our "INT" configs as a byte type internally. Note +// that the byte type is just a wrapper around RECD_INT. +#define REC_EstablishStaticConfigByte(_var, _config_var_name) do { \ + RecLinkConfigByte(_config_var_name, &_var); \ + _var = (RecByte)REC_ConfigReadInteger(_config_var_name); \ + } while (0) + +RecInt REC_ConfigReadInteger(const char *name); +char *REC_ConfigReadString(const char *name); +RecFloat REC_ConfigReadFloat(const char *name); +RecCounter REC_ConfigReadCounter(const char *name); + +// MGMT2 Marco's -- converting lmgmt->record_data->readXXX +RecInt REC_readInteger(const char *name, bool * found, bool lock = true); +RecFloat REC_readFloat(char *name, bool * found, bool lock = true); +RecCounter REC_readCounter(char *name, bool * found, bool lock = true); +RecString REC_readString(const char *name, bool * found, bool lock = true); + +//------------------------------------------------------------------------ +// Clear Statistics +//------------------------------------------------------------------------ +int RecResetStatRecord(char *name); +int RecResetStatRecord(RecT type = RECT_NULL, bool all = false); + + +//------------------------------------------------------------------------ +// Set RecRecord attributes +//------------------------------------------------------------------------ +int RecSetSyncRequired(char *name, bool lock = true); + + +//------------------------------------------------------------------------ +// Signal Alarm/Warning +//------------------------------------------------------------------------ +#define REC_SignalManager RecSignalManager +#define REC_SignalWarning(_n,_d) { Warning(_d); RecSignalManager(_n,_d); } + + +//------------------------------------------------------------------------ +// Manager Callback +//------------------------------------------------------------------------ +typedef void *(*RecManagerCb) (void *opaque_cb_data, char *data_raw, int data_len); +int RecRegisterManagerCb(int _signal, RecManagerCb _fn, void *_data = NULL); + +void RecResizeAdditional(int add); + +#endif diff --git a/lib/records/I_RecDefs.h b/lib/records/I_RecDefs.h new file mode 100644 index 00000000..d19005ec --- /dev/null +++ b/lib/records/I_RecDefs.h @@ -0,0 +1,184 @@ +/** @file + + Public Rec defines and types + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_DEFS_H_ +#define _I_REC_DEFS_H_ + +#include "Compatability.h" +#include "ink_mutex.h" +#include "ink_rwlock.h" +#include "I_RecMutex.h" + +#define STAT_PROCESSOR + + +//------------------------------------------------------------------------- +// Error Values +//------------------------------------------------------------------------- +enum RecErrT +{ + REC_ERR_FAIL = -1, + REC_ERR_OKAY = 0 +}; + + +//------------------------------------------------------------------------- +// Types +//------------------------------------------------------------------------- +#define RecStringNull NULL + +typedef int64_t RecInt; +typedef float RecFloat; +typedef char *RecString; +typedef const char *RecStringConst; +typedef int64_t RecCounter; +typedef int8_t RecByte; + +enum RecT +{ + RECT_NULL = 0, + RECT_CONFIG, + RECT_PROCESS, + RECT_NODE, + RECT_CLUSTER, + RECT_LOCAL, + RECT_PLUGIN, + RECT_MAX +}; + +enum RecDataT +{ + RECD_NULL = 0, + RECD_INT, + RECD_FLOAT, + RECD_STRING, + RECD_COUNTER, + +#if defined(STAT_PROCESSOR) + RECD_STAT_CONST, // Added for the StatProcessor + RECD_STAT_FX, // Added for the StatProcessor +#endif + RECD_MAX +}; + +enum RecPersistT +{ + RECP_NULL, + RECP_PERSISTENT, + RECP_NON_PERSISTENT +}; + +enum RecUpdateT +{ + RECU_NULL, // default: don't know the behavior + RECU_DYNAMIC, // config can be updated dynamically w/ traffic_line -x + RECU_RESTART_TS, // config requires TS to be restarted to take effect + RECU_RESTART_TM, // config requires TM/TS to be restarted to take effect + RECU_RESTART_TC // config requires TC/TM/TS to be restarted to take effect +}; + +enum RecCheckT +{ + RECC_NULL, // default: no check type defined + RECC_STR, // config is a string + RECC_INT, // config is an integer with a range + RECC_IP // config is an ip address +}; + +enum RecModeT +{ + RECM_NULL, + RECM_CLIENT, + RECM_SERVER, + RECM_STAND_ALONE +}; + +enum RecAccessT +{ + RECA_NULL, + RECA_NO_ACCESS, + RECA_READ_ONLY +}; + + +//------------------------------------------------------------------------- +// Data Union +//------------------------------------------------------------------------- +union RecData +{ + RecInt rec_int; + RecFloat rec_float; + RecString rec_string; + RecCounter rec_counter; +}; + + +//------------------------------------------------------------------------- +// RawStat Structures +//------------------------------------------------------------------------- +struct RecRawStat +{ + int64_t sum; + int64_t count; + // XXX - these will waist some space because they are only needed for the globals + // this is a fix for bug TS-162, so I am trying to do as few code changes as + // possible, this should be revisted -bcall + int64_t last_sum; // value from the last global sync + int64_t last_count; // value from the last global sync +}; + + +// WARNING! It's advised that developers do not modify the contents of +// the RecRawStatBlock. ^_^ +struct RecRawStatBlock +{ + off_t ethr_stat_offset; // thread local raw-stat storage + RecRawStat **global; // global raw-stat storage (ptr to RecRecord) + int num_stats; // number of stats in this block + int max_stats; // maximum number of stats for this block + ink_mutex mutex; +}; + + +//------------------------------------------------------------------------- +// RecCore Callback Types +//------------------------------------------------------------------------- +typedef int (*RecConfigUpdateCb) (const char *name, RecDataT data_type, RecData data, void *cookie); +typedef int (*RecStatUpdateFunc) (const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id, void *cookie); +typedef int (*RecRawStatSyncCb) (const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id); + + +//------------------------------------------------------------------------- +// RecTree Defines +//------------------------------------------------------------------------- +#define REC_VAR_NAME_DELIMITOR '.' +#define REC_VAR_NAME_WILDCARD '*' + + +// System Defaults +extern char system_root_dir[PATH_NAME_MAX + 1]; +extern char system_runtime_dir[PATH_NAME_MAX + 1]; +extern char system_config_directory[PATH_NAME_MAX + 1]; +extern char system_log_dir[PATH_NAME_MAX + 1]; + +#endif diff --git a/lib/records/I_RecEvents.h b/lib/records/I_RecEvents.h new file mode 100644 index 00000000..bb7f5809 --- /dev/null +++ b/lib/records/I_RecEvents.h @@ -0,0 +1,39 @@ +/** @file + + Public REC_EVENT defines + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_EVENTS_H_ +#define _I_REC_EVENTS_H_ + +// copy from mgmt/BaseManager.h +#define REC_EVENT_SYNC_KEY 10000 +#define REC_EVENT_SHUTDOWN 10001 +#define REC_EVENT_RESTART 10002 +#define REC_EVENT_BOUNCE 10003 +#define REC_EVENT_CLEAR_STATS 10004 +#define REC_EVENT_CONFIG_FILE_UPDATE 10005 +#define REC_EVENT_PLUGIN_CONFIG_UPDATE 10006 +#define REC_EVENT_HTTP_CLUSTER_DELTA 10007 +#define REC_EVENT_ROLL_LOG_FILES 10008 +#define REC_EVENT_LIBRECORDS 10009 + +#endif diff --git a/lib/records/I_RecLocal.h b/lib/records/I_RecLocal.h new file mode 100644 index 00000000..89c23133 --- /dev/null +++ b/lib/records/I_RecLocal.h @@ -0,0 +1,37 @@ +/** @file + + Public RecLocal declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_LOCAL_H_ +#define _I_REC_LOCAL_H_ + +#include "I_RecCore.h" + +//------------------------------------------------------------------------- +// Initialization +//------------------------------------------------------------------------- + +int RecLocalInit(Diags * diags = NULL); +int RecLocalInitMessage(); +int RecLocalStart(); + +#endif diff --git a/lib/records/I_RecMutex.h b/lib/records/I_RecMutex.h new file mode 100644 index 00000000..5c59ea25 --- /dev/null +++ b/lib/records/I_RecMutex.h @@ -0,0 +1,46 @@ +/** @file + + Public RecMutex declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_MUTEX_H_ +#define _I_REC_MUTEX_H_ + +#include "ink_mutex.h" +#include "ink_thread.h" + +/** + A wrapper to ink_mutex class. It allows multiple acquire of mutex lock + by the SAME thread. This is a trimmed down version of ProxyMutex. + +*/ +struct RecMutex +{ + size_t nthread_holding; + ink_thread thread_holding; + ink_mutex the_mutex; +}; + +int rec_mutex_init(RecMutex * m, const char *name = NULL); +int rec_mutex_acquire(RecMutex * m); +int rec_mutex_release(RecMutex * m); + +#endif diff --git a/lib/records/I_RecProcess.h b/lib/records/I_RecProcess.h new file mode 100644 index 00000000..c277a72b --- /dev/null +++ b/lib/records/I_RecProcess.h @@ -0,0 +1,159 @@ +/** @file + + Public RecProcess declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_PROCESS_H_ +#define _I_REC_PROCESS_H_ + +#include "I_RecCore.h" +#include "I_EventSystem.h" + + +//------------------------------------------------------------------------- +// Initialization/Starting +//------------------------------------------------------------------------- +int RecProcessInit(RecModeT mode_type, Diags * diags = NULL); +int RecProcessInitMessage(RecModeT mode_type); +int RecProcessStart(); + + +//------------------------------------------------------------------------- +// RawStat Registration +//------------------------------------------------------------------------- +RecRawStatBlock *RecAllocateRawStatBlock(int num_stats); +int RecRegisterRawStat(RecRawStatBlock * rsb, RecT rec_type, const char *name, RecDataT data_type, RecPersistT persist_type, int id, RecRawStatSyncCb sync_cb); + + +// RecRawStatRange* RecAllocateRawStatRange (int num_buckets); + +// int RecRegisterRawStatRange (RecRawStatRange *rsr, +// RecT rec_type, +// char *name, +// RecPersistT persist_type, +// int id, +// RecInt min, +// RecInt max); + + +//------------------------------------------------------------------------- +// Predefined RawStat Callbacks +//------------------------------------------------------------------------- +int RecRawStatSyncSum(const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id); +int RecRawStatSyncCount(const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id); +int RecRawStatSyncAvg(const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id); +int RecRawStatSyncHrTimeAvg(const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id); +int RecRawStatSyncIntMsecsToFloatSeconds(const char *name, RecDataT data_type, + RecData * data, RecRawStatBlock * rsb, int id); +int RecRawStatSyncMHrTimeAvg(const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id); + + +//------------------------------------------------------------------------- +// RawStat Setting/Getting +//------------------------------------------------------------------------- + +// Note: The following RecIncrRawStatXXX calls are fast and don't +// require any ink_atomic_xxx64()'s to be executed. Use these RawStat +// functions over other RawStat functions whenever possible. +inline int RecIncrRawStat(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t incr = 1); +inline int RecIncrRawStatSum(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t incr = 1); +inline int RecIncrRawStatCount(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t incr = 1); +int RecIncrRawStatBlock(RecRawStatBlock * rsb, EThread * ethread, RecRawStat * stat_array); + +int RecSetRawStatSum(RecRawStatBlock * rsb, int id, int64_t data); +int RecSetRawStatCount(RecRawStatBlock * rsb, int id, int64_t data); +int RecSetRawStatBlock(RecRawStatBlock * rsb, RecRawStat * stat_array); + +int RecGetRawStatSum(RecRawStatBlock * rsb, int id, int64_t * data); +int RecGetRawStatCount(RecRawStatBlock * rsb, int id, int64_t * data); + + +//------------------------------------------------------------------------- +// Global RawStat Items (e.g. same as above, but no thread-local behavior) +//------------------------------------------------------------------------- +int RecIncrGlobalRawStat(RecRawStatBlock * rsb, int id, int64_t incr = 1); +int RecIncrGlobalRawStatSum(RecRawStatBlock * rsb, int id, int64_t incr = 1); +int RecIncrGlobalRawStatCount(RecRawStatBlock * rsb, int id, int64_t incr = 1); + +int RecSetGlobalRawStatSum(RecRawStatBlock * rsb, int id, int64_t data); +int RecSetGlobalRawStatCount(RecRawStatBlock * rsb, int id, int64_t data); + +int RecGetGlobalRawStatSum(RecRawStatBlock * rsb, int id, int64_t * data); +int RecGetGlobalRawStatCount(RecRawStatBlock * rsb, int id, int64_t * data); + +RecRawStat *RecGetGlobalRawStatPtr(RecRawStatBlock * rsb, int id); +int64_t *RecGetGlobalRawStatSumPtr(RecRawStatBlock * rsb, int id); +int64_t *RecGetGlobalRawStatCountPtr(RecRawStatBlock * rsb, int id); + + +//------------------------------------------------------------------------- +// RecIncrRawStatXXX +//------------------------------------------------------------------------- +// inlined functions that are used very frequently. +// FIXME: move it to Inline.cc +inline RecRawStat * +raw_stat_get_tlp(RecRawStatBlock * rsb, int id, EThread * ethread) +{ + ink_debug_assert((id >= 0) && (id < rsb->max_stats)); + if (ethread == NULL) { + ethread = this_ethread(); + } + return (((RecRawStat *) ((char *) (ethread) + rsb->ethr_stat_offset)) + id); +} + +inline int +RecIncrRawStat(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t incr) +{ + RecRawStat *tlp = raw_stat_get_tlp(rsb, id, ethread); + tlp->sum += incr; + tlp->count += 1; + return REC_ERR_OKAY; +} + +/* This does not seem to work as intended ... */ +inline int +RecDecrRawStat(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t decr) +{ + RecRawStat *tlp = raw_stat_get_tlp(rsb, id, ethread); + if (decr <= tlp->sum) { // Assure that we stay positive + tlp->sum -= decr; + tlp->count += 1; + } + return REC_ERR_OKAY; +} + +inline int +RecIncrRawStatSum(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t incr) +{ + RecRawStat *tlp = raw_stat_get_tlp(rsb, id, ethread); + tlp->sum += incr; + return REC_ERR_OKAY; +} + +inline int +RecIncrRawStatCount(RecRawStatBlock * rsb, EThread * ethread, int id, int64_t incr) +{ + RecRawStat *tlp = raw_stat_get_tlp(rsb, id, ethread); + tlp->count += incr; + return REC_ERR_OKAY; +} + +#endif /* !_I_REC_PROCESS_H_ */ diff --git a/lib/records/I_RecSignals.h b/lib/records/I_RecSignals.h new file mode 100644 index 00000000..0115e566 --- /dev/null +++ b/lib/records/I_RecSignals.h @@ -0,0 +1,56 @@ +/** @file + + Public REC_SIGNAL defines + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _I_REC_SIGNALS_H_ +#define _I_REC_SIGNALS_H_ + +// copy from mgmt/BaseManager.h +#define REC_SIGNAL_PID 0 +#define REC_SIGNAL_MACHINE_UP 1 +#define REC_SIGNAL_MACHINE_DOWN 2 +#define REC_SIGNAL_CONFIG_ERROR 3 +#define REC_SIGNAL_SYSTEM_ERROR 4 +#define REC_SIGNAL_LOG_SPACE_CRISIS 5 +#define REC_SIGNAL_CONFIG_FILE_READ 6 +#define REC_SIGNAL_CACHE_ERROR 7 +#define REC_SIGNAL_CACHE_WARNING 8 +#define REC_SIGNAL_LOGGING_ERROR 9 +#define REC_SIGNAL_LOGGING_WARNING 10 +// Currently unused: 11 +#define REC_SIGNAL_PLUGIN_CONFIG_REG 12 +#define REC_SIGNAL_PLUGIN_ADD_REC 13 +#define REC_SIGNAL_PLUGIN_SET_CONFIG 14 +#define REC_SIGNAL_LOG_FILES_ROLLED 15 +#define REC_SIGNAL_LIBRECORDS 16 +#define REC_SIGNAL_HTTP_CONGESTED_SERVER 20 +#define REC_SIGNAL_HTTP_ALLEVIATED_SERVER 21 + +#define REC_SIGNAL_WDA_BILLING_CONNECTION_DIED 100 +#define REC_SIGNAL_WDA_BILLING_CORRUPTED_DATA 101 +#define REC_SIGNAL_WDA_XF_ENGINE_DOWN 102 +#define REC_SIGNAL_WDA_RADIUS_CORRUPTED_PACKETS 103 + +#define REC_SIGNAL_ACC_ALARMS_START 200 +#define REC_SIGNAL_ACC_ALARMS_END 299 + +#endif diff --git a/lib/records/Makefile.am b/lib/records/Makefile.am new file mode 100644 index 00000000..f0e76b42 --- /dev/null +++ b/lib/records/Makefile.am @@ -0,0 +1,82 @@ +# Makefile.am for the lib/records +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +DEFS += @ink_with_modules_def@ + +AM_CPPFLAGS = \ + -I$(top_srcdir)/iocore/eventsystem \ + -I$(top_srcdir)/iocore/utils \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/web2 \ + -I$(top_srcdir)/mgmt/api/include \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libreclocal.a librecprocess.a + +libreclocal_a_CXXFLAGS = $(ink_with_modules_local) +libreclocal_a_SOURCES = \ + I_RecAlarms.h \ + I_RecCore.h \ + I_RecDefs.h \ + I_RecEvents.h \ + I_RecLocal.h \ + I_RecMutex.h \ + I_RecSignals.h \ + P_RecCompatibility.h \ + P_RecCore.h \ + P_RecCore.i \ + P_RecDefs.h \ + P_RecLocal.h \ + P_RecMessage.h \ + P_RecTree.h \ + P_RecUtils.h \ + RecCompatibility.cc \ + RecCore.cc \ + RecLocal.cc \ + RecMessage.cc \ + RecMutex.cc \ + RecTree.cc \ + RecUtils.cc + +librecprocess_a_CXXFLAGS = $(ink_with_modules_process) +librecprocess_a_SOURCES = \ + I_RecAlarms.h \ + I_RecCore.h \ + I_RecDefs.h \ + I_RecEvents.h \ + I_RecMutex.h \ + I_RecProcess.h \ + I_RecSignals.h \ + P_RecCompatibility.h \ + P_RecCore.h \ + P_RecCore.i \ + P_RecDefs.h \ + P_RecMessage.h \ + P_RecProcess.h \ + P_RecTree.h \ + P_RecUtils.h \ + RecCompatibility.cc \ + RecCore.cc \ + RecMessage.cc \ + RecMutex.cc \ + RecProcess.cc \ + RecTree.cc \ + RecUtils.cc + diff --git a/lib/records/Makefile.in b/lib/records/Makefile.in new file mode 100644 index 00000000..b2526941 --- /dev/null +++ b/lib/records/Makefile.in @@ -0,0 +1,980 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for the lib/records +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/records +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libreclocal_a_AR = $(AR) $(ARFLAGS) +libreclocal_a_LIBADD = +am_libreclocal_a_OBJECTS = libreclocal_a-RecCompatibility.$(OBJEXT) \ + libreclocal_a-RecCore.$(OBJEXT) \ + libreclocal_a-RecLocal.$(OBJEXT) \ + libreclocal_a-RecMessage.$(OBJEXT) \ + libreclocal_a-RecMutex.$(OBJEXT) \ + libreclocal_a-RecTree.$(OBJEXT) \ + libreclocal_a-RecUtils.$(OBJEXT) +libreclocal_a_OBJECTS = $(am_libreclocal_a_OBJECTS) +librecprocess_a_AR = $(AR) $(ARFLAGS) +librecprocess_a_LIBADD = +am_librecprocess_a_OBJECTS = \ + librecprocess_a-RecCompatibility.$(OBJEXT) \ + librecprocess_a-RecCore.$(OBJEXT) \ + librecprocess_a-RecMessage.$(OBJEXT) \ + librecprocess_a-RecMutex.$(OBJEXT) \ + librecprocess_a-RecProcess.$(OBJEXT) \ + librecprocess_a-RecTree.$(OBJEXT) \ + librecprocess_a-RecUtils.$(OBJEXT) +librecprocess_a_OBJECTS = $(am_librecprocess_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libreclocal_a_SOURCES) $(librecprocess_a_SOURCES) +DIST_SOURCES = $(libreclocal_a_SOURCES) $(librecprocess_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ @ink_with_modules_def@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/iocore/eventsystem \ + -I$(top_srcdir)/iocore/utils \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/web2 \ + -I$(top_srcdir)/mgmt/api/include \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libreclocal.a librecprocess.a +libreclocal_a_CXXFLAGS = $(ink_with_modules_local) +libreclocal_a_SOURCES = \ + I_RecAlarms.h \ + I_RecCore.h \ + I_RecDefs.h \ + I_RecEvents.h \ + I_RecLocal.h \ + I_RecMutex.h \ + I_RecSignals.h \ + P_RecCompatibility.h \ + P_RecCore.h \ + P_RecCore.i \ + P_RecDefs.h \ + P_RecLocal.h \ + P_RecMessage.h \ + P_RecTree.h \ + P_RecUtils.h \ + RecCompatibility.cc \ + RecCore.cc \ + RecLocal.cc \ + RecMessage.cc \ + RecMutex.cc \ + RecTree.cc \ + RecUtils.cc + +librecprocess_a_CXXFLAGS = $(ink_with_modules_process) +librecprocess_a_SOURCES = \ + I_RecAlarms.h \ + I_RecCore.h \ + I_RecDefs.h \ + I_RecEvents.h \ + I_RecMutex.h \ + I_RecProcess.h \ + I_RecSignals.h \ + P_RecCompatibility.h \ + P_RecCore.h \ + P_RecCore.i \ + P_RecDefs.h \ + P_RecMessage.h \ + P_RecProcess.h \ + P_RecTree.h \ + P_RecUtils.h \ + RecCompatibility.cc \ + RecCore.cc \ + RecMessage.cc \ + RecMutex.cc \ + RecProcess.cc \ + RecTree.cc \ + RecUtils.cc + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/records/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/records/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libreclocal.a: $(libreclocal_a_OBJECTS) $(libreclocal_a_DEPENDENCIES) + -rm -f libreclocal.a + $(libreclocal_a_AR) libreclocal.a $(libreclocal_a_OBJECTS) $(libreclocal_a_LIBADD) + $(RANLIB) libreclocal.a +librecprocess.a: $(librecprocess_a_OBJECTS) $(librecprocess_a_DEPENDENCIES) + -rm -f librecprocess.a + $(librecprocess_a_AR) librecprocess.a $(librecprocess_a_OBJECTS) $(librecprocess_a_LIBADD) + $(RANLIB) librecprocess.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecCompatibility.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecCore.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecLocal.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecMutex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecTree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libreclocal_a-RecUtils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecCompatibility.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecCore.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecMutex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecProcess.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecTree.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librecprocess_a-RecUtils.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +libreclocal_a-RecCompatibility.o: RecCompatibility.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecCompatibility.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecCompatibility.Tpo -c -o libreclocal_a-RecCompatibility.o `test -f 'RecCompatibility.cc' || echo '$(srcdir)/'`RecCompatibility.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecCompatibility.Tpo $(DEPDIR)/libreclocal_a-RecCompatibility.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCompatibility.cc' object='libreclocal_a-RecCompatibility.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecCompatibility.o `test -f 'RecCompatibility.cc' || echo '$(srcdir)/'`RecCompatibility.cc + +libreclocal_a-RecCompatibility.obj: RecCompatibility.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecCompatibility.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecCompatibility.Tpo -c -o libreclocal_a-RecCompatibility.obj `if test -f 'RecCompatibility.cc'; then $(CYGPATH_W) 'RecCompatibility.cc'; else $(CYGPATH_W) '$(srcdir)/RecCompatibility.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecCompatibility.Tpo $(DEPDIR)/libreclocal_a-RecCompatibility.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCompatibility.cc' object='libreclocal_a-RecCompatibility.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecCompatibility.obj `if test -f 'RecCompatibility.cc'; then $(CYGPATH_W) 'RecCompatibility.cc'; else $(CYGPATH_W) '$(srcdir)/RecCompatibility.cc'; fi` + +libreclocal_a-RecCore.o: RecCore.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecCore.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecCore.Tpo -c -o libreclocal_a-RecCore.o `test -f 'RecCore.cc' || echo '$(srcdir)/'`RecCore.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecCore.Tpo $(DEPDIR)/libreclocal_a-RecCore.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCore.cc' object='libreclocal_a-RecCore.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecCore.o `test -f 'RecCore.cc' || echo '$(srcdir)/'`RecCore.cc + +libreclocal_a-RecCore.obj: RecCore.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecCore.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecCore.Tpo -c -o libreclocal_a-RecCore.obj `if test -f 'RecCore.cc'; then $(CYGPATH_W) 'RecCore.cc'; else $(CYGPATH_W) '$(srcdir)/RecCore.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecCore.Tpo $(DEPDIR)/libreclocal_a-RecCore.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCore.cc' object='libreclocal_a-RecCore.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecCore.obj `if test -f 'RecCore.cc'; then $(CYGPATH_W) 'RecCore.cc'; else $(CYGPATH_W) '$(srcdir)/RecCore.cc'; fi` + +libreclocal_a-RecLocal.o: RecLocal.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecLocal.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecLocal.Tpo -c -o libreclocal_a-RecLocal.o `test -f 'RecLocal.cc' || echo '$(srcdir)/'`RecLocal.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecLocal.Tpo $(DEPDIR)/libreclocal_a-RecLocal.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecLocal.cc' object='libreclocal_a-RecLocal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecLocal.o `test -f 'RecLocal.cc' || echo '$(srcdir)/'`RecLocal.cc + +libreclocal_a-RecLocal.obj: RecLocal.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecLocal.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecLocal.Tpo -c -o libreclocal_a-RecLocal.obj `if test -f 'RecLocal.cc'; then $(CYGPATH_W) 'RecLocal.cc'; else $(CYGPATH_W) '$(srcdir)/RecLocal.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecLocal.Tpo $(DEPDIR)/libreclocal_a-RecLocal.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecLocal.cc' object='libreclocal_a-RecLocal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecLocal.obj `if test -f 'RecLocal.cc'; then $(CYGPATH_W) 'RecLocal.cc'; else $(CYGPATH_W) '$(srcdir)/RecLocal.cc'; fi` + +libreclocal_a-RecMessage.o: RecMessage.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecMessage.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecMessage.Tpo -c -o libreclocal_a-RecMessage.o `test -f 'RecMessage.cc' || echo '$(srcdir)/'`RecMessage.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecMessage.Tpo $(DEPDIR)/libreclocal_a-RecMessage.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMessage.cc' object='libreclocal_a-RecMessage.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecMessage.o `test -f 'RecMessage.cc' || echo '$(srcdir)/'`RecMessage.cc + +libreclocal_a-RecMessage.obj: RecMessage.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecMessage.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecMessage.Tpo -c -o libreclocal_a-RecMessage.obj `if test -f 'RecMessage.cc'; then $(CYGPATH_W) 'RecMessage.cc'; else $(CYGPATH_W) '$(srcdir)/RecMessage.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecMessage.Tpo $(DEPDIR)/libreclocal_a-RecMessage.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMessage.cc' object='libreclocal_a-RecMessage.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecMessage.obj `if test -f 'RecMessage.cc'; then $(CYGPATH_W) 'RecMessage.cc'; else $(CYGPATH_W) '$(srcdir)/RecMessage.cc'; fi` + +libreclocal_a-RecMutex.o: RecMutex.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecMutex.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecMutex.Tpo -c -o libreclocal_a-RecMutex.o `test -f 'RecMutex.cc' || echo '$(srcdir)/'`RecMutex.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecMutex.Tpo $(DEPDIR)/libreclocal_a-RecMutex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMutex.cc' object='libreclocal_a-RecMutex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecMutex.o `test -f 'RecMutex.cc' || echo '$(srcdir)/'`RecMutex.cc + +libreclocal_a-RecMutex.obj: RecMutex.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecMutex.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecMutex.Tpo -c -o libreclocal_a-RecMutex.obj `if test -f 'RecMutex.cc'; then $(CYGPATH_W) 'RecMutex.cc'; else $(CYGPATH_W) '$(srcdir)/RecMutex.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecMutex.Tpo $(DEPDIR)/libreclocal_a-RecMutex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMutex.cc' object='libreclocal_a-RecMutex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecMutex.obj `if test -f 'RecMutex.cc'; then $(CYGPATH_W) 'RecMutex.cc'; else $(CYGPATH_W) '$(srcdir)/RecMutex.cc'; fi` + +libreclocal_a-RecTree.o: RecTree.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecTree.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecTree.Tpo -c -o libreclocal_a-RecTree.o `test -f 'RecTree.cc' || echo '$(srcdir)/'`RecTree.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecTree.Tpo $(DEPDIR)/libreclocal_a-RecTree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecTree.cc' object='libreclocal_a-RecTree.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecTree.o `test -f 'RecTree.cc' || echo '$(srcdir)/'`RecTree.cc + +libreclocal_a-RecTree.obj: RecTree.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecTree.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecTree.Tpo -c -o libreclocal_a-RecTree.obj `if test -f 'RecTree.cc'; then $(CYGPATH_W) 'RecTree.cc'; else $(CYGPATH_W) '$(srcdir)/RecTree.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecTree.Tpo $(DEPDIR)/libreclocal_a-RecTree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecTree.cc' object='libreclocal_a-RecTree.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecTree.obj `if test -f 'RecTree.cc'; then $(CYGPATH_W) 'RecTree.cc'; else $(CYGPATH_W) '$(srcdir)/RecTree.cc'; fi` + +libreclocal_a-RecUtils.o: RecUtils.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecUtils.o -MD -MP -MF $(DEPDIR)/libreclocal_a-RecUtils.Tpo -c -o libreclocal_a-RecUtils.o `test -f 'RecUtils.cc' || echo '$(srcdir)/'`RecUtils.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecUtils.Tpo $(DEPDIR)/libreclocal_a-RecUtils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecUtils.cc' object='libreclocal_a-RecUtils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecUtils.o `test -f 'RecUtils.cc' || echo '$(srcdir)/'`RecUtils.cc + +libreclocal_a-RecUtils.obj: RecUtils.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -MT libreclocal_a-RecUtils.obj -MD -MP -MF $(DEPDIR)/libreclocal_a-RecUtils.Tpo -c -o libreclocal_a-RecUtils.obj `if test -f 'RecUtils.cc'; then $(CYGPATH_W) 'RecUtils.cc'; else $(CYGPATH_W) '$(srcdir)/RecUtils.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libreclocal_a-RecUtils.Tpo $(DEPDIR)/libreclocal_a-RecUtils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecUtils.cc' object='libreclocal_a-RecUtils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libreclocal_a_CXXFLAGS) $(CXXFLAGS) -c -o libreclocal_a-RecUtils.obj `if test -f 'RecUtils.cc'; then $(CYGPATH_W) 'RecUtils.cc'; else $(CYGPATH_W) '$(srcdir)/RecUtils.cc'; fi` + +librecprocess_a-RecCompatibility.o: RecCompatibility.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecCompatibility.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecCompatibility.Tpo -c -o librecprocess_a-RecCompatibility.o `test -f 'RecCompatibility.cc' || echo '$(srcdir)/'`RecCompatibility.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecCompatibility.Tpo $(DEPDIR)/librecprocess_a-RecCompatibility.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCompatibility.cc' object='librecprocess_a-RecCompatibility.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecCompatibility.o `test -f 'RecCompatibility.cc' || echo '$(srcdir)/'`RecCompatibility.cc + +librecprocess_a-RecCompatibility.obj: RecCompatibility.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecCompatibility.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecCompatibility.Tpo -c -o librecprocess_a-RecCompatibility.obj `if test -f 'RecCompatibility.cc'; then $(CYGPATH_W) 'RecCompatibility.cc'; else $(CYGPATH_W) '$(srcdir)/RecCompatibility.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecCompatibility.Tpo $(DEPDIR)/librecprocess_a-RecCompatibility.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCompatibility.cc' object='librecprocess_a-RecCompatibility.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecCompatibility.obj `if test -f 'RecCompatibility.cc'; then $(CYGPATH_W) 'RecCompatibility.cc'; else $(CYGPATH_W) '$(srcdir)/RecCompatibility.cc'; fi` + +librecprocess_a-RecCore.o: RecCore.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecCore.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecCore.Tpo -c -o librecprocess_a-RecCore.o `test -f 'RecCore.cc' || echo '$(srcdir)/'`RecCore.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecCore.Tpo $(DEPDIR)/librecprocess_a-RecCore.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCore.cc' object='librecprocess_a-RecCore.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecCore.o `test -f 'RecCore.cc' || echo '$(srcdir)/'`RecCore.cc + +librecprocess_a-RecCore.obj: RecCore.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecCore.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecCore.Tpo -c -o librecprocess_a-RecCore.obj `if test -f 'RecCore.cc'; then $(CYGPATH_W) 'RecCore.cc'; else $(CYGPATH_W) '$(srcdir)/RecCore.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecCore.Tpo $(DEPDIR)/librecprocess_a-RecCore.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecCore.cc' object='librecprocess_a-RecCore.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecCore.obj `if test -f 'RecCore.cc'; then $(CYGPATH_W) 'RecCore.cc'; else $(CYGPATH_W) '$(srcdir)/RecCore.cc'; fi` + +librecprocess_a-RecMessage.o: RecMessage.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecMessage.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecMessage.Tpo -c -o librecprocess_a-RecMessage.o `test -f 'RecMessage.cc' || echo '$(srcdir)/'`RecMessage.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecMessage.Tpo $(DEPDIR)/librecprocess_a-RecMessage.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMessage.cc' object='librecprocess_a-RecMessage.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecMessage.o `test -f 'RecMessage.cc' || echo '$(srcdir)/'`RecMessage.cc + +librecprocess_a-RecMessage.obj: RecMessage.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecMessage.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecMessage.Tpo -c -o librecprocess_a-RecMessage.obj `if test -f 'RecMessage.cc'; then $(CYGPATH_W) 'RecMessage.cc'; else $(CYGPATH_W) '$(srcdir)/RecMessage.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecMessage.Tpo $(DEPDIR)/librecprocess_a-RecMessage.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMessage.cc' object='librecprocess_a-RecMessage.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecMessage.obj `if test -f 'RecMessage.cc'; then $(CYGPATH_W) 'RecMessage.cc'; else $(CYGPATH_W) '$(srcdir)/RecMessage.cc'; fi` + +librecprocess_a-RecMutex.o: RecMutex.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecMutex.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecMutex.Tpo -c -o librecprocess_a-RecMutex.o `test -f 'RecMutex.cc' || echo '$(srcdir)/'`RecMutex.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecMutex.Tpo $(DEPDIR)/librecprocess_a-RecMutex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMutex.cc' object='librecprocess_a-RecMutex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecMutex.o `test -f 'RecMutex.cc' || echo '$(srcdir)/'`RecMutex.cc + +librecprocess_a-RecMutex.obj: RecMutex.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecMutex.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecMutex.Tpo -c -o librecprocess_a-RecMutex.obj `if test -f 'RecMutex.cc'; then $(CYGPATH_W) 'RecMutex.cc'; else $(CYGPATH_W) '$(srcdir)/RecMutex.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecMutex.Tpo $(DEPDIR)/librecprocess_a-RecMutex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecMutex.cc' object='librecprocess_a-RecMutex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecMutex.obj `if test -f 'RecMutex.cc'; then $(CYGPATH_W) 'RecMutex.cc'; else $(CYGPATH_W) '$(srcdir)/RecMutex.cc'; fi` + +librecprocess_a-RecProcess.o: RecProcess.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecProcess.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecProcess.Tpo -c -o librecprocess_a-RecProcess.o `test -f 'RecProcess.cc' || echo '$(srcdir)/'`RecProcess.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecProcess.Tpo $(DEPDIR)/librecprocess_a-RecProcess.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecProcess.cc' object='librecprocess_a-RecProcess.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecProcess.o `test -f 'RecProcess.cc' || echo '$(srcdir)/'`RecProcess.cc + +librecprocess_a-RecProcess.obj: RecProcess.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecProcess.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecProcess.Tpo -c -o librecprocess_a-RecProcess.obj `if test -f 'RecProcess.cc'; then $(CYGPATH_W) 'RecProcess.cc'; else $(CYGPATH_W) '$(srcdir)/RecProcess.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecProcess.Tpo $(DEPDIR)/librecprocess_a-RecProcess.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecProcess.cc' object='librecprocess_a-RecProcess.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecProcess.obj `if test -f 'RecProcess.cc'; then $(CYGPATH_W) 'RecProcess.cc'; else $(CYGPATH_W) '$(srcdir)/RecProcess.cc'; fi` + +librecprocess_a-RecTree.o: RecTree.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecTree.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecTree.Tpo -c -o librecprocess_a-RecTree.o `test -f 'RecTree.cc' || echo '$(srcdir)/'`RecTree.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecTree.Tpo $(DEPDIR)/librecprocess_a-RecTree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecTree.cc' object='librecprocess_a-RecTree.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecTree.o `test -f 'RecTree.cc' || echo '$(srcdir)/'`RecTree.cc + +librecprocess_a-RecTree.obj: RecTree.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecTree.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecTree.Tpo -c -o librecprocess_a-RecTree.obj `if test -f 'RecTree.cc'; then $(CYGPATH_W) 'RecTree.cc'; else $(CYGPATH_W) '$(srcdir)/RecTree.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecTree.Tpo $(DEPDIR)/librecprocess_a-RecTree.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecTree.cc' object='librecprocess_a-RecTree.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecTree.obj `if test -f 'RecTree.cc'; then $(CYGPATH_W) 'RecTree.cc'; else $(CYGPATH_W) '$(srcdir)/RecTree.cc'; fi` + +librecprocess_a-RecUtils.o: RecUtils.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecUtils.o -MD -MP -MF $(DEPDIR)/librecprocess_a-RecUtils.Tpo -c -o librecprocess_a-RecUtils.o `test -f 'RecUtils.cc' || echo '$(srcdir)/'`RecUtils.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecUtils.Tpo $(DEPDIR)/librecprocess_a-RecUtils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecUtils.cc' object='librecprocess_a-RecUtils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecUtils.o `test -f 'RecUtils.cc' || echo '$(srcdir)/'`RecUtils.cc + +librecprocess_a-RecUtils.obj: RecUtils.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -MT librecprocess_a-RecUtils.obj -MD -MP -MF $(DEPDIR)/librecprocess_a-RecUtils.Tpo -c -o librecprocess_a-RecUtils.obj `if test -f 'RecUtils.cc'; then $(CYGPATH_W) 'RecUtils.cc'; else $(CYGPATH_W) '$(srcdir)/RecUtils.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/librecprocess_a-RecUtils.Tpo $(DEPDIR)/librecprocess_a-RecUtils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecUtils.cc' object='librecprocess_a-RecUtils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librecprocess_a_CXXFLAGS) $(CXXFLAGS) -c -o librecprocess_a-RecUtils.obj `if test -f 'RecUtils.cc'; then $(CYGPATH_W) 'RecUtils.cc'; else $(CYGPATH_W) '$(srcdir)/RecUtils.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/records/P_RecCompatibility.h b/lib/records/P_RecCompatibility.h new file mode 100644 index 00000000..6f411c3c --- /dev/null +++ b/lib/records/P_RecCompatibility.h @@ -0,0 +1,68 @@ +/** @file + + Private RecFile and RecPipe declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_COMPATIBILITY_H_ +#define _P_REC_COMPATIBILITY_H_ + +#include "ink_platform.h" + +//------------------------------------------------------------------------- +// types/defines +//------------------------------------------------------------------------- + +#if defined(_WIN32) + +#define REC_HANDLE_INVALID INVALID_HANDLE_VALUE +typedef HANDLE RecHandle; + +#else + +#define REC_HANDLE_INVALID -1 +typedef int RecHandle; + +#endif + +//------------------------------------------------------------------------- +// RecFile +//------------------------------------------------------------------------- + +RecHandle RecFileOpenR(const char *file); +RecHandle RecFileOpenW(const char *file); +void RecFileClose(RecHandle h_file); +int RecFileRead(RecHandle h_file, char *buf, int size, int *bytes_read); +int RecFileWrite(RecHandle h_file, char *buf, int size, int *bytes_written); +int RecFileImport_Xmalloc(const char *file, char **file_buf, int *file_size); +int RecFileGetSize(RecHandle h_file); +int RecFileExists(const char *file); + +//------------------------------------------------------------------------- +// RecPipe +//------------------------------------------------------------------------- + +RecHandle RecPipeCreate(const char *base_path, const char *name); +RecHandle RecPipeConnect(const char *base_path, const char *name); +int RecPipeClose(RecHandle h_pipe); +int RecPipeRead(RecHandle h_pipe, char *buf, int size); +int RecPipeWrite(RecHandle h_pipe, char *buf, int size); + +#endif diff --git a/lib/records/P_RecCore.h b/lib/records/P_RecCore.h new file mode 100644 index 00000000..99716d26 --- /dev/null +++ b/lib/records/P_RecCore.h @@ -0,0 +1,104 @@ +/** @file + + Private record core declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_CORE_H_ +#define _P_REC_CORE_H_ + +#include "ink_thread.h" +#include "ink_hash_table.h" +#include "ink_llqueue.h" +#include "ink_rwlock.h" +#include "TextBuffer.h" + +#include "I_RecCore.h" +#include "P_RecDefs.h" +#include "P_RecTree.h" + +// records, record hash-table, and hash-table rwlock +extern RecRecord *g_records; +extern InkHashTable *g_records_ht; +extern ink_rwlock g_records_rwlock; +extern int g_num_records; +extern int g_num_update[]; +extern RecTree *g_records_tree; + +// records.config items +extern const char *g_rec_config_fpath; +extern LLQ *g_rec_config_contents_llq; +extern InkHashTable *g_rec_config_contents_ht; +extern ink_mutex g_rec_config_lock; + +// stats.snap items +extern const char *g_stats_snap_fpath; + +//------------------------------------------------------------------------- +// Initialization +//------------------------------------------------------------------------- + +int RecCoreInit(RecModeT mode_type, Diags * diags); + +//------------------------------------------------------------------------- +// Registration/Insertion +//------------------------------------------------------------------------- + +RecRecord *RecRegisterStat(RecT rec_type, const char *name, RecDataT data_type, + RecData data_default, RecPersistT persist_type); + +RecRecord *RecRegisterConfig(RecT rec_type, const char *name, RecDataT data_type, + RecData data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type = RECA_NULL); + +RecRecord *RecForceInsert(RecRecord * record); + +//------------------------------------------------------------------------- +// Setting/Getting +//------------------------------------------------------------------------- + +int RecSetRecord(RecT rec_type, const char *name, RecDataT data_type, + RecData *data, RecRawStat *raw_stat, bool lock = true); + +int RecGetRecord_Xmalloc(const char *name, RecDataT data_type, RecData * data, bool lock = true); + +//------------------------------------------------------------------------- +// Read/Sync to Disk +//------------------------------------------------------------------------- + +int RecReadStatsFile(); +int RecSyncStatsFile(); +int RecReadConfigFile(); +int RecSyncConfigToTB(textBuffer * tb); + +//------------------------------------------------------------------------- +// Misc +//------------------------------------------------------------------------- + +int RecExecConfigUpdateCbs(); +int RecExecStatUpdateFuncs(); +int RecExecRawStatUpdateFuncs(); + +void RecDumpRecordsHt(RecT rec_type = RECT_NULL); + +void +RecDumpRecords(RecT rec_type, RecDumpEntryCb callback, void *edata); + +#endif diff --git a/lib/records/P_RecCore.i b/lib/records/P_RecCore.i new file mode 100644 index 00000000..a5cf62a9 --- /dev/null +++ b/lib/records/P_RecCore.i @@ -0,0 +1,1078 @@ +/** @file + + Private record core definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "TextBuffer.h" +#include "Tokenizer.h" +#include "ink_string.h" + +#include "P_RecCompatibility.h" +#include "P_RecUtils.h" + + +//------------------------------------------------------------------------- +// i_am_the_record_owner +//------------------------------------------------------------------------- +static bool +i_am_the_record_owner(RecT rec_type) +{ +#if defined (REC_LOCAL) + + switch (rec_type) { + case RECT_CONFIG: + case RECT_NODE: + case RECT_CLUSTER: + case RECT_LOCAL: + return true; + case RECT_PROCESS: + case RECT_PLUGIN: + return false; + default: + ink_debug_assert(!"Unexpected RecT type"); + return false; + } + +#elif defined (REC_PROCESS) + + // g_mode_type is defined in either RecLocal.cc or RecProcess.cc. + // We can access it since we're inlined by on of these two files. + if (g_mode_type == RECM_CLIENT) { + switch (rec_type) { + case RECT_PROCESS: + case RECT_PLUGIN: + return true; + case RECT_CONFIG: + case RECT_NODE: + case RECT_CLUSTER: + case RECT_LOCAL: + return false; + default: + ink_debug_assert(!"Unexpected RecT type"); + return false; + } + } else if (g_mode_type == RECM_STAND_ALONE) { + switch (rec_type) { + case RECT_CONFIG: + case RECT_PROCESS: + case RECT_NODE: + case RECT_CLUSTER: + case RECT_LOCAL: + case RECT_PLUGIN: + return true; + default: + ink_debug_assert(!"Unexpected RecT type"); + return false; + } + } +#else + +#error "Required #define not specificed; expected REC_LOCAL or REC_PROCESS" + +#endif + + return false; +} + + +//------------------------------------------------------------------------- +// send_set_message +//------------------------------------------------------------------------- +static int +send_set_message(RecRecord * record) +{ + RecMessage *m; + + rec_mutex_acquire(&(record->lock)); + m = RecMessageAlloc(RECG_SET); + m = RecMessageMarshal_Realloc(m, record); + RecDebug(DL_Note, "[send] RECG_SET [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start); + RecMessageSend(m); + RecMessageFree(m); + rec_mutex_release(&(record->lock)); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// send_register_message +//------------------------------------------------------------------------- +static int +send_register_message(RecRecord * record) +{ + RecMessage *m; + + rec_mutex_acquire(&(record->lock)); + m = RecMessageAlloc(RECG_REGISTER); + m = RecMessageMarshal_Realloc(m, record); + RecDebug(DL_Note, "[send] RECG_REGISTER [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start); + RecMessageSend(m); + RecMessageFree(m); + rec_mutex_release(&(record->lock)); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// send_push_message +//------------------------------------------------------------------------- +static int +send_push_message() +{ + RecRecord *r; + RecMessage *m; + int i, num_records; + bool send_msg = false; + + m = RecMessageAlloc(RECG_PUSH); + num_records = g_num_records; + for (i = 0; i < num_records; i++) { + r = &(g_records[i]); + rec_mutex_acquire(&(r->lock)); + if (i_am_the_record_owner(r->rec_type)) { + if (r->sync_required & REC_PEER_SYNC_REQUIRED) { + m = RecMessageMarshal_Realloc(m, r); + r->sync_required = r->sync_required & ~REC_PEER_SYNC_REQUIRED; + send_msg = true; + } + } + rec_mutex_release(&(r->lock)); + } + if (send_msg) { + RecDebug(DL_Note, "[send] RECG_PUSH [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start); + RecMessageSend(m); + } + RecMessageFree(m); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// send_pull_message +//------------------------------------------------------------------------- +static int +send_pull_message(RecMessageT msg_type) +{ + RecRecord *r; + RecMessage *m; + int i, num_records; + + m = RecMessageAlloc(msg_type); + switch (msg_type) { + + case RECG_PULL_REQ: + // We're requesting all of the records from our peer. No payload + // here, just send the message. + RecDebug(DL_Note, "[send] RECG_PULL_REQ [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start); + break; + + case RECG_PULL_ACK: + // Respond to a RECG_PULL_REQ message from our peer. Send ALL + // records! Also be sure to send a response even if it has no + // payload. Our peer may be blocking and waiting for a response! + num_records = g_num_records; + for (i = 0; i < num_records; i++) { + r = &(g_records[i]); + if (i_am_the_record_owner(r->rec_type) || + (REC_TYPE_IS_STAT(r->rec_type) && !(r->registered)) || + (REC_TYPE_IS_STAT(r->rec_type) && !(r->stat_meta.persist_type != RECP_NON_PERSISTENT))) { + rec_mutex_acquire(&(r->lock)); + m = RecMessageMarshal_Realloc(m, r); + r->sync_required = r->sync_required & ~REC_PEER_SYNC_REQUIRED; + rec_mutex_release(&(r->lock)); + } + } + RecDebug(DL_Note, "[send] RECG_PULL_ACK [%d bytes]", sizeof(RecMessageHdr) + m->o_write - m->o_start); + break; + + default: + RecMessageFree(m); + return REC_ERR_FAIL; + + } + + RecMessageSend(m); + RecMessageFree(m); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// recv_message_cb +//------------------------------------------------------------------------- +static int +recv_message_cb(RecMessage * msg, RecMessageT msg_type, void *cookie) +{ + REC_NOWARN_UNUSED(cookie); + + RecRecord *r; + RecMessageItr itr; + + switch (msg_type) { + + case RECG_SET: + + RecDebug(DL_Note, "[recv] RECG_SET [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start); + if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) { + do { + if (REC_TYPE_IS_STAT(r->rec_type)) { + RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), &(r->stat_meta.data_raw)); + } else { + RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), NULL); + } + } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL); + } + break; + + case RECG_REGISTER: + RecDebug(DL_Note, "[recv] RECG_REGISTER [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start); + if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) { + do { + if (REC_TYPE_IS_STAT(r->rec_type)) { + RecRegisterStat(r->rec_type, r->name, r->data_type, r->data_default, r->stat_meta.persist_type); + } else if (REC_TYPE_IS_CONFIG(r->rec_type)) { + RecRegisterConfig(r->rec_type, r->name, r->data_type, + r->data_default, r->config_meta.update_type, + r->config_meta.check_type, r->config_meta.check_expr, r->config_meta.access_type); + } + } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL); + } + break; + + case RECG_PUSH: + RecDebug(DL_Note, "[recv] RECG_PUSH [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start); + if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) { + do { + RecForceInsert(r); + } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL); + } + break; + + case RECG_PULL_ACK: + RecDebug(DL_Note, "[recv] RECG_PULL_ACK [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start); + if (RecMessageUnmarshalFirst(msg, &itr, &r) != REC_ERR_FAIL) { + do { + RecForceInsert(r); + } while (RecMessageUnmarshalNext(msg, &itr, &r) != REC_ERR_FAIL); + } + break; + + case RECG_PULL_REQ: + RecDebug(DL_Note, "[recv] RECG_PULL_REQ [%d bytes]", sizeof(RecMessageHdr) + msg->o_end - msg->o_start); + send_pull_message(RECG_PULL_ACK); + break; + + default: + ink_debug_assert(!"Unexpected RecG type"); + return REC_ERR_FAIL; + + } + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecRegisterStatXXX +//------------------------------------------------------------------------- +#define REC_REGISTER_STAT_XXX(A, B) \ + ink_debug_assert((rec_type == RECT_NODE) || \ + (rec_type == RECT_CLUSTER) || \ + (rec_type == RECT_PROCESS) || \ + (rec_type == RECT_LOCAL) || \ + (rec_type == RECT_PLUGIN)); \ + RecRecord *r; \ + RecData my_data_default; \ + my_data_default.A = data_default; \ + if ((r = RecRegisterStat(rec_type, name, B, my_data_default, \ + persist_type)) != NULL) { \ + if (i_am_the_record_owner(r->rec_type)) { \ + r->sync_required = r->sync_required | REC_PEER_SYNC_REQUIRED; \ + } else { \ + send_register_message(r); \ + } \ + return REC_ERR_OKAY; \ + } else { \ + return REC_ERR_FAIL; \ + } + +int +RecRegisterStatInt(RecT rec_type, const char *name, RecInt data_default, RecPersistT persist_type) +{ + REC_REGISTER_STAT_XXX(rec_int, RECD_INT); +} + +int +RecRegisterStatFloat(RecT rec_type, const char *name, RecFloat data_default, RecPersistT persist_type) +{ + REC_REGISTER_STAT_XXX(rec_float, RECD_FLOAT); +} + +int +RecRegisterStatString(RecT rec_type, const char *name, RecString data_default, RecPersistT persist_type) +{ + REC_REGISTER_STAT_XXX(rec_string, RECD_STRING); +} + +int +RecRegisterStatCounter(RecT rec_type, const char *name, RecCounter data_default, RecPersistT persist_type) +{ + REC_REGISTER_STAT_XXX(rec_counter, RECD_COUNTER); +} + + +//------------------------------------------------------------------------- +// RecRegisterConfigXXX +//------------------------------------------------------------------------- +#define REC_REGISTER_CONFIG_XXX(A, B) \ + RecRecord *r; \ + RecData my_data_default; \ + my_data_default.A = data_default; \ + if ((r = RecRegisterConfig(rec_type, name, B, my_data_default, \ + update_type, check_type, \ + check_regex, access_type)) != NULL) { \ + if (i_am_the_record_owner(r->rec_type)) { \ + r->sync_required = r->sync_required | REC_PEER_SYNC_REQUIRED; \ + } else { \ + send_register_message(r); \ + } \ + return REC_ERR_OKAY; \ + } else { \ + return REC_ERR_FAIL; \ + } + +int +RecRegisterConfigInt(RecT rec_type, const char *name, + RecInt data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type) +{ + ink_debug_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL)); + REC_REGISTER_CONFIG_XXX(rec_int, RECD_INT); +} + +int +RecRegisterConfigFloat(RecT rec_type, const char *name, + RecFloat data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type) +{ + ink_debug_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL)); + REC_REGISTER_CONFIG_XXX(rec_float, RECD_FLOAT); +} + + +int +RecRegisterConfigString(RecT rec_type, const char *name, + const char *data_default_tmp, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type) +{ + RecString data_default = (RecString)data_default_tmp; + ink_debug_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL)); + REC_REGISTER_CONFIG_XXX(rec_string, RECD_STRING); +} + +int +RecRegisterConfigCounter(RecT rec_type, const char *name, + RecCounter data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_regex, RecAccessT access_type) +{ + ink_debug_assert((rec_type == RECT_CONFIG) || (rec_type == RECT_LOCAL)); + REC_REGISTER_CONFIG_XXX(rec_counter, RECD_COUNTER); +} + + +//------------------------------------------------------------------------- +// RecSetRecordXXX +//------------------------------------------------------------------------- +int +RecSetRecord(RecT rec_type, const char *name, RecDataT data_type, RecData *data, RecRawStat *data_raw, bool lock) +{ + int err = REC_ERR_OKAY; + RecRecord *r1; + + // FIXME: Most of the time we set, we don't actually need to wrlock + // since we are not modifying the g_records_ht. + if (lock) { + ink_rwlock_wrlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r1)) { + if (i_am_the_record_owner(r1->rec_type)) { + rec_mutex_acquire(&(r1->lock)); + if ((data_type != RECD_NULL) && (r1->data_type != data_type)) { + err = REC_ERR_FAIL; + } else { + if (data_type == RECD_NULL) { + ink_assert(data->rec_string); + switch (r1->data_type) { + case RECD_INT: + r1->data.rec_int = ink_atoi64(data->rec_string); + data_type = RECD_INT; + break; + case RECD_FLOAT: + r1->data.rec_float = atof(data->rec_string); + data_type = RECD_FLOAT; + break; + case RECD_STRING: + data_type = RECD_STRING; + r1->data.rec_string = data->rec_string; + break; + case RECD_COUNTER: + r1->data.rec_int = ink_atoi64(data->rec_string); + data_type = RECD_COUNTER; + break; + default: + err = REC_ERR_FAIL; + break; + } + } + g_num_update[r1->rec_type]++; + + if (RecDataSet(data_type, &(r1->data), data)) { + r1->sync_required = REC_SYNC_REQUIRED; + if (REC_TYPE_IS_CONFIG(r1->rec_type)) { + r1->config_meta.update_required = REC_UPDATE_REQUIRED; + } + } + if (REC_TYPE_IS_STAT(r1->rec_type) && (data_raw != NULL)) { + r1->stat_meta.data_raw = *data_raw; + } + } + rec_mutex_release(&(r1->lock)); + } else { + // We don't need to xstrdup() here as we will make copies of any + // strings when we marshal them into our RecMessage buffer. + RecRecord r2; + memset(&r2, 0, sizeof(RecRecord)); + r2.rec_type = rec_type; + r2.name = name; + r2.data_type = (data_type != RECD_NULL) ? data_type : r1->data_type; + r2.data = *data; + if (REC_TYPE_IS_STAT(r2.rec_type) && (data_raw != NULL)) { + r2.stat_meta.data_raw = *data_raw; + } + err = send_set_message(&r2); + } + } else { + // Add the record but do not set the 'registered' flag, as this + // record really hasn't been registered yet. Also, in order to + // add the record, we need to have a rec_type, so if the user + // calls RecSetRecord on a record we haven't registered yet, we + // should fail out here. + if ((rec_type == RECT_NULL) || (data_type == RECD_NULL)) { + err = REC_ERR_FAIL; + goto Ldone; + } + r1 = RecAlloc(rec_type, name, data_type); + RecDataSet(data_type, &(r1->data), data); + if (REC_TYPE_IS_STAT(r1->rec_type) && (data_raw != NULL)) { + r1->stat_meta.data_raw = *data_raw; + } + if (i_am_the_record_owner(r1->rec_type)) { + r1->sync_required = r1->sync_required | REC_PEER_SYNC_REQUIRED; + } else { + err = send_set_message(r1); + } + ink_hash_table_insert(g_records_ht, name, (void *) r1); + + } + +Ldone: + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + +int +RecSetRecordConvert(const char *name, const RecString rec_string, bool lock) +{ + RecData data; + data.rec_string = rec_string; + return RecSetRecord(RECT_NULL, name, RECD_NULL, &data, NULL, lock); +} + +int +RecSetRecordInt(const char *name, RecInt rec_int, bool lock) +{ + RecData data; + data.rec_int = rec_int; + return RecSetRecord(RECT_NULL, name, RECD_INT, &data, NULL, lock); +} + +int +RecSetRecordFloat(const char *name, RecFloat rec_float, bool lock) +{ + RecData data; + data.rec_float = rec_float; + return RecSetRecord(RECT_NULL, name, RECD_FLOAT, &data, NULL, lock); +} + +int +RecSetRecordString(const char *name, const RecString rec_string, bool lock) +{ + RecData data; + data.rec_string = rec_string; + return RecSetRecord(RECT_NULL, name, RECD_STRING, &data, NULL, lock); +} + +int +RecSetRecordCounter(const char *name, RecCounter rec_counter, bool lock) +{ + RecData data; + data.rec_counter = rec_counter; + return RecSetRecord(RECT_NULL, name, RECD_COUNTER, &data, NULL, lock); +} + + +//------------------------------------------------------------------------- +// RecReadStatsFile +//------------------------------------------------------------------------- +int +RecReadStatsFile() +{ + RecRecord *r; + RecMessage *m; + RecMessageItr itr; + + // lock our hash table + ink_rwlock_wrlock(&g_records_rwlock); + + if ((m = RecMessageReadFromDisk(g_stats_snap_fpath)) != NULL) { + if (RecMessageUnmarshalFirst(m, &itr, &r) != REC_ERR_FAIL) { + do { + if ((r->name == NULL) || (!strlen(r->name))) + continue; + RecSetRecord(r->rec_type, r->name, r->data_type, &(r->data), &(r->stat_meta.data_raw), false); + } while (RecMessageUnmarshalNext(m, &itr, &r) != REC_ERR_FAIL); + } + } + + ink_rwlock_unlock(&g_records_rwlock); + + if (m) + xfree(m); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecSyncStatsFile +//------------------------------------------------------------------------- +int +RecSyncStatsFile() +{ + RecRecord *r; + RecMessage *m; + int i, num_records; + bool sync_to_disk; + + // g_mode_type is defined in either RecLocal.cc or RecProcess.cc. + // We can access it since we're inlined by on of these two files. + if (g_mode_type == RECM_SERVER || g_mode_type == RECM_STAND_ALONE) { + m = RecMessageAlloc(RECG_NULL); + num_records = g_num_records; + sync_to_disk = false; + for (i = 0; i < num_records; i++) { + r = &(g_records[i]); + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_STAT(r->rec_type)) { + if (r->stat_meta.persist_type != RECP_NON_PERSISTENT) { + m = RecMessageMarshal_Realloc(m, r); + sync_to_disk = true; + } + } + rec_mutex_release(&(r->lock)); + } + if (sync_to_disk) { + RecDebug(DL_Note, "Writing '%s' [%d bytes]", g_stats_snap_fpath, m->o_write - m->o_start + sizeof(RecMessageHdr)); + RecMessageWriteToDisk(m, g_stats_snap_fpath); + } + RecMessageFree(m); + } + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecReadConfigFile +//------------------------------------------------------------------------- +int +RecReadConfigFile() +{ + char *fbuf; + int fsize; + + const char *line; + int line_num; + + char *rec_type_str, *name_str, *data_type_str, *data_str; + RecT rec_type; + RecDataT data_type; + RecData data; + + Tokenizer line_tok("\r\n"); + tok_iter_state line_tok_state; + + RecConfigFileEntry *cfe; + + RecDebug(DL_Note, "Reading '%s'", g_rec_config_fpath); + + // watch out, we're altering our g_rec_config_xxx structures + ink_mutex_acquire(&g_rec_config_lock); + + if (RecFileImport_Xmalloc(g_rec_config_fpath, &fbuf, &fsize) == REC_ERR_FAIL) { + RecLog(DL_Warning, "Could not import '%s'", g_rec_config_fpath); + ink_mutex_release(&g_rec_config_lock); + return REC_ERR_FAIL; + } + // clear our g_rec_config_contents_xxx structures + while (!queue_is_empty(g_rec_config_contents_llq)) { + cfe = (RecConfigFileEntry *) dequeue(g_rec_config_contents_llq); + if (cfe->entry) { + xfree(cfe->entry); + } + xfree(cfe); + } + ink_hash_table_destroy(g_rec_config_contents_ht); + g_rec_config_contents_ht = ink_hash_table_create(InkHashTableKeyType_String); + + // lock our hash table + ink_rwlock_wrlock(&g_records_rwlock); + + memset(&data, 0, sizeof(RecData)); + line_tok.Initialize(fbuf, SHARE_TOKS); + line = line_tok.iterFirst(&line_tok_state); + line_num = 1; + while (line) { + char *lc = xstrdup(line); + char *lt = lc; + char *ln; + + while (isspace(*lt)) + lt++; + rec_type_str = ink_strtok_r(lt, " \t", &ln); + + // check for blank lines and comments + if ((!rec_type_str) || (rec_type_str && (*rec_type_str == '#'))) { + goto L_next_line; + } + + name_str = ink_strtok_r(NULL, " \t", &ln); + data_type_str = ink_strtok_r(NULL, " \t", &ln); + + // extract the string data (a little bit tricker since it can have spaces) + if (ln) { + // 'ln' will point to either the next token or a bunch of spaces + // if the user didn't supply a value (e.g. 'STRING '). First + // scan past all of the spaces. If we hit a '\0', then we we + // know we didn't have a valid value. If not, set 'data_str' to + // the start of the token and scan until we find the end. Once + // the end is found, back-peddle to remove any trailing spaces. + while (isspace(*ln)) + ln++; + if (*ln == '\0') { + data_str = NULL; + } else { + data_str = ln; + while (*ln != '\0') + ln++; + ln--; + while (isspace(*ln) && (ln > data_str)) + ln--; + ln++; + *ln = '\0'; + } + } else { + data_str = NULL; + } + + // check for errors + if (!(rec_type_str && name_str && data_type_str && data_str)) { + RecLog(DL_Warning, "Could not parse line at '%s:%d' -- skipping line: '%s'", g_rec_config_fpath, line_num, line); + goto L_next_line; + } + // record type + rec_type = RECT_NULL; + if (strcmp(rec_type_str, "CONFIG") == 0) { + rec_type = RECT_CONFIG; + } else if (strcmp(rec_type_str, "PROCESS") == 0) { + rec_type = RECT_PROCESS; + } else if (strcmp(rec_type_str, "NODE") == 0) { + rec_type = RECT_NODE; + } else if (strcmp(rec_type_str, "CLUSTER") == 0) { + rec_type = RECT_CLUSTER; + } else if (strcmp(rec_type_str, "LOCAL") == 0) { + rec_type = RECT_LOCAL; + } else { + RecLog(DL_Warning, "Unknown record type '%s' at '%s:%d' -- skipping line", rec_type_str, g_rec_config_fpath, line_num); + goto L_next_line; + } + + // data_type + data_type = RECD_NULL; + if (strcmp(data_type_str, "INT") == 0) { + data_type = RECD_INT; + } else if (strcmp(data_type_str, "FLOAT") == 0) { + data_type = RECD_FLOAT; + } else if (strcmp(data_type_str, "STRING") == 0) { + data_type = RECD_STRING; + } else if (strcmp(data_type_str, "COUNTER") == 0) { + data_type = RECD_COUNTER; + } else { + RecLog(DL_Warning, "Unknown data type '%s' at '%s:%d' -- skipping line", data_type_str, g_rec_config_fpath, line_num); + goto L_next_line; + } + + // set the record + RecDataSetFromString(data_type, &data, data_str); + RecSetRecord(rec_type, name_str, data_type, &data, NULL, false); + RecDataClear(data_type, &data); + + // update our g_rec_config_contents_xxx + cfe = (RecConfigFileEntry *) xmalloc(sizeof(RecConfigFileEntry)); + cfe->entry_type = RECE_RECORD; + cfe->entry = xstrdup(name_str); + enqueue(g_rec_config_contents_llq, (void *) cfe); + ink_hash_table_insert(g_rec_config_contents_ht, name_str, NULL); + goto L_done; + + L_next_line: + // store this line into g_rec_config_contents_llq so that we can + // write it out later + cfe = (RecConfigFileEntry *) xmalloc(sizeof(RecConfigFileEntry)); + cfe->entry_type = RECE_COMMENT; + cfe->entry = xstrdup(line); + enqueue(g_rec_config_contents_llq, (void *) cfe); + + L_done: + line = line_tok.iterNext(&line_tok_state); + line_num++; + xfree(lc); + } + + // release our hash table + ink_rwlock_unlock(&g_records_rwlock); + ink_mutex_release(&g_rec_config_lock); + xfree(fbuf); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecSyncConfigFile +//------------------------------------------------------------------------- +int +RecSyncConfigToTB(textBuffer * tb) +{ + int err = REC_ERR_FAIL; + + // g_mode_type is defined in either RecLocal.cc or RecProcess.cc. + // We can access it since we're inlined by on of these two files. + if (g_mode_type == RECM_SERVER || g_mode_type == RECM_STAND_ALONE) { + RecRecord *r; + int i, num_records; + RecConfigFileEntry *cfe; + bool sync_to_disk; + + ink_mutex_acquire(&g_rec_config_lock); + + num_records = g_num_records; + sync_to_disk = false; + for (i = 0; i < num_records; i++) { + r = &(g_records[i]); + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_CONFIG(r->rec_type)) { + if (r->sync_required & REC_DISK_SYNC_REQUIRED) { + if (!ink_hash_table_isbound(g_rec_config_contents_ht, r->name)) { + cfe = (RecConfigFileEntry *) xmalloc(sizeof(RecConfigFileEntry)); + cfe->entry_type = RECE_RECORD; + cfe->entry = xstrdup(r->name); + enqueue(g_rec_config_contents_llq, (void *) cfe); + ink_hash_table_insert(g_rec_config_contents_ht, r->name, NULL); + } + r->sync_required = r->sync_required & ~REC_DISK_SYNC_REQUIRED; + sync_to_disk = true; + } + } + rec_mutex_release(&(r->lock)); + } + + if (sync_to_disk) { + char b[1024]; + + // okay, we're going to write into our textBuffer + err = REC_ERR_OKAY; + tb->reUse(); + + ink_rwlock_rdlock(&g_records_rwlock); + + LLQrec *llq_rec = g_rec_config_contents_llq->head; + while (llq_rec != NULL) { + cfe = (RecConfigFileEntry *) llq_rec->data; + if (cfe->entry_type == RECE_COMMENT) { + tb->copyFrom(cfe->entry, strlen(cfe->entry)); + tb->copyFrom("\n", 1); + } else { + if (ink_hash_table_lookup(g_records_ht, cfe->entry, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + // rec_type + switch (r->rec_type) { + case RECT_CONFIG: + tb->copyFrom("CONFIG ", 7); + break; + case RECT_PROCESS: + tb->copyFrom("PROCESS ", 8); + break; + case RECT_NODE: + tb->copyFrom("NODE ", 5); + break; + case RECT_CLUSTER: + tb->copyFrom("CLUSTER ", 8); + break; + case RECT_LOCAL: + tb->copyFrom("LOCAL ", 6); + break; + default: + ink_debug_assert(!"Unexpected RecT type"); + break; + } + // name + tb->copyFrom(cfe->entry, strlen(cfe->entry)); + tb->copyFrom(" ", 1); + // data_type and value + switch (r->data_type) { + case RECD_INT: + tb->copyFrom("INT ", 4); + snprintf(b, 1023, "%" PRId64 "", r->data.rec_int); + tb->copyFrom(b, strlen(b)); + break; + case RECD_FLOAT: + tb->copyFrom("FLOAT ", 6); + snprintf(b, 1023, "%f", r->data.rec_float); + tb->copyFrom(b, strlen(b)); + break; + case RECD_STRING: + tb->copyFrom("STRING ", 7); + if (r->data.rec_string) { + tb->copyFrom(r->data.rec_string, strlen(r->data.rec_string)); + } else { + tb->copyFrom("NULL", strlen("NULL")); + } + break; + case RECD_COUNTER: + tb->copyFrom("COUNTER ", 8); + snprintf(b, 1023, "%" PRId64 "", r->data.rec_counter); + tb->copyFrom(b, strlen(b)); + break; + default: + ink_debug_assert(!"Unexpected RecD type"); + break; + } + tb->copyFrom("\n", 1); + rec_mutex_release(&(r->lock)); + } + } + llq_rec = llq_rec->next; + } + ink_rwlock_unlock(&g_records_rwlock); + } + ink_mutex_release(&g_rec_config_lock); + } + + return err; +} + + +//------------------------------------------------------------------------- +// RecExecConifgUpdateCbs +//------------------------------------------------------------------------- +int +RecExecConfigUpdateCbs() +{ + RecRecord *r; + int i, num_records; + unsigned int update_required_type; + +#if defined (REC_LOCAL) + update_required_type = REC_LOCAL_UPDATE_REQUIRED; +#elif defined (REC_PROCESS) + update_required_type = REC_PROCESS_UPDATE_REQUIRED; +#else +#error "Required #define not specificed; expected REC_LOCAL or REC_PROCESS" +#endif + + num_records = g_num_records; + for (i = 0; i < num_records; i++) { + r = &(g_records[i]); + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_CONFIG(r->rec_type)) { + /* -- upgrade to support a list of callback functions + if ((r->config_meta.update_required & update_required_type) && + (r->config_meta.update_cb)) { + (*(r->config_meta.update_cb))(r->name, r->data_type, r->data, + r->config_meta.update_cookie); + r->config_meta.update_required = + r->config_meta.update_required & ~update_required_type; + } + */ + + if ((r->config_meta.update_required & update_required_type) && (r->config_meta.update_cb_list)) { + RecConfigUpdateCbList *cur_callback = NULL; + for (cur_callback = r->config_meta.update_cb_list; cur_callback; cur_callback = cur_callback->next) { + (*(cur_callback->update_cb)) (r->name, r->data_type, r->data, cur_callback->update_cookie); + } + r->config_meta.update_required = r->config_meta.update_required & ~update_required_type; + } + } + rec_mutex_release(&(r->lock)); + } + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------ +// RecResetStatRecord +//------------------------------------------------------------------------ +int +RecResetStatRecord(char *name) +{ + RecRecord *r1 = NULL; + int err = REC_ERR_OKAY; + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r1)) { + if (i_am_the_record_owner(r1->rec_type)) { + rec_mutex_acquire(&(r1->lock)); + RecDataSet(r1->data_type, &(r1->data), &(r1->data_default)); + rec_mutex_release(&(r1->lock)); + err = REC_ERR_OKAY; + } else { + RecRecord r2; + memset(&r2, 0, sizeof(RecRecord)); + r2.rec_type = r1->rec_type; + r2.name = r1->name; + r2.data_type = r1->data_type; + r2.data = r1->data_default; + + err = send_set_message(&r2); + } + } else { + err = REC_ERR_FAIL; + } + + return err; +} + + +//------------------------------------------------------------------------ +// RecResetStatRecord +//------------------------------------------------------------------------ +int +RecResetStatRecord(RecT type, bool all) +{ + int i, num_records; + int err = REC_ERR_OKAY; + + RecDebug(DL_Note, "Reset Statistics Records"); + + num_records = g_num_records; + for (i = 0; i < num_records; i++) { + RecRecord *r1 = &(g_records[i]); + + if (REC_TYPE_IS_STAT(r1->rec_type) && ((type == RECT_NULL) || (r1->rec_type == type)) && + (all || (r1->stat_meta.persist_type != RECP_NON_PERSISTENT)) && + (r1->data_type != RECD_STRING)) { + if (i_am_the_record_owner(r1->rec_type)) { + rec_mutex_acquire(&(r1->lock)); + if (!RecDataSet(r1->data_type, &(r1->data), &(r1->data_default))) { + err = REC_ERR_FAIL; + } + rec_mutex_release(&(r1->lock)); + } else { + RecRecord r2; + memset(&r2, 0, sizeof(RecRecord)); + r2.rec_type = r1->rec_type; + r2.name = r1->name; + r2.data_type = r1->data_type; + r2.data = r1->data_default; + + err = send_set_message(&r2); + } + } + } + return err; +} + + +int +RecSetSyncRequired(char *name, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r1; + + // FIXME: Most of the time we set, we don't actually need to wrlock + // since we are not modifying the g_records_ht. + if (lock) { + ink_rwlock_wrlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r1)) { + if (i_am_the_record_owner(r1->rec_type)) { + rec_mutex_acquire(&(r1->lock)); + r1->sync_required = REC_SYNC_REQUIRED; + if (REC_TYPE_IS_CONFIG(r1->rec_type)) { + r1->config_meta.update_required = REC_UPDATE_REQUIRED; + } + rec_mutex_release(&(r1->lock)); + err = REC_ERR_OKAY; + } else { + // No point of doing the following because our peer will + // set the value with RecDataSet. However, since + // r2.name == r1->name, the sync_required bit will not be + // set. + + /* + RecRecord r2; + memset(&r2, 0, sizeof(RecRecord)); + r2.rec_type = r1->rec_type; + r2.name = r1->name; + r2.data_type = r1->data_type; + r2.data = r1->data_default; + + err = send_set_message(&r2); + */ + } + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} diff --git a/lib/records/P_RecDefs.h b/lib/records/P_RecDefs.h new file mode 100644 index 00000000..1592107b --- /dev/null +++ b/lib/records/P_RecDefs.h @@ -0,0 +1,178 @@ +/** @file + + Private record declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_DEFS_H_ +#define _P_REC_DEFS_H_ + +#include "ink_bool.h" + +#include "I_RecDefs.h" + +#define REC_CONFIG_FILE "records.config" +#define REC_SHADOW_EXT ".shadow" +#define REC_RAW_STATS_FILE "records.snap" +#define REC_PIPE_NAME "librecords_pipe" + +#define REC_MESSAGE_ELE_MAGIC 0xF00DF00D + +// This is for the internal stats and configs, as well as API stats. We currently use +// about 1600 stats + configs for the core, but we're allocating 2000 for some growth. +// TODO: if/when we switch to a new config system, we should make this run-time dynamic. +#define REC_MAX_RECORDS (2000 + TS_MAX_API_STATS) + +#define REC_CONFIG_UPDATE_INTERVAL_SEC 3 +#define REC_REMOTE_SYNC_INTERVAL_SEC 5 + +#define REC_RAW_STAT_SYNC_INTERVAL_SEC 5 +#define REC_STAT_UPDATE_INTERVAL_SEC 10 + +//------------------------------------------------------------------------- +// Record Items +//------------------------------------------------------------------------- + +#define REC_LOCAL_UPDATE_REQUIRED 1 +#define REC_PROCESS_UPDATE_REQUIRED (REC_LOCAL_UPDATE_REQUIRED << 1) +#define REC_UPDATE_REQUIRED (REC_LOCAL_UPDATE_REQUIRED | REC_PROCESS_UPDATE_REQUIRED) + +#define REC_DISK_SYNC_REQUIRED 1 +#define REC_PEER_SYNC_REQUIRED (REC_DISK_SYNC_REQUIRED << 1) +#define REC_SYNC_REQUIRED (REC_DISK_SYNC_REQUIRED | REC_PEER_SYNC_REQUIRED) + +enum RecEntryT +{ + RECE_NULL, + RECE_COMMENT, + RECE_RECORD +}; + +struct RecConfigFileEntry +{ + RecEntryT entry_type; + char *entry; +}; + +typedef struct RecConfigCbList_t +{ + RecConfigUpdateCb update_cb; + void *update_cookie; + struct RecConfigCbList_t *next; +} RecConfigUpdateCbList; + +typedef struct RecStatUpdateFuncList_t +{ + RecRawStatBlock *rsb; + int id; + RecStatUpdateFunc update_func; + void *update_cookie; + struct RecStatUpdateFuncList_t *next; +} RecStatUpdateFuncList; + +struct RecStatMeta +{ + RecRawStat data_raw; + RecRawStatSyncCb sync_cb; + RecRawStatBlock *sync_rsb; + int sync_id; + RecPersistT persist_type; +}; + +struct RecConfigMeta +{ + unsigned char update_required; + RecConfigUpdateCbList *update_cb_list; + void *update_cookie; + RecUpdateT update_type; + RecCheckT check_type; + char *check_expr; + RecAccessT access_type; +}; + +struct RecRecord +{ + RecT rec_type; + const char *name; + RecDataT data_type; + RecData data; + RecData data_default; + RecMutex lock; + unsigned char sync_required; + bool registered; + union + { + RecStatMeta stat_meta; + RecConfigMeta config_meta; + }; + int order; + int rsb_id; +}; + +// Used for cluster. TODO: Do we still need this? +struct RecRecords +{ + int num_recs; + RecRecord *recs; +}; + +//------------------------------------------------------------------------- +// Message Items +//------------------------------------------------------------------------- + +enum RecMessageT +{ + RECG_NULL, + RECG_SET, + RECG_REGISTER, + RECG_PUSH, + RECG_PULL_REQ, + RECG_PULL_ACK +}; + +struct RecMessageHdr +{ + RecMessageT msg_type; + int o_start; + int o_write; + int o_end; + int entries; + int alignment; //needs to be 8 byte aligned +}; + +struct RecMessageEleHdr +{ + unsigned int magic; + int o_next; +}; + +struct RecMessageItr +{ + RecMessageEleHdr *ele_hdr; + int next; +}; + +typedef RecMessageHdr RecMessage; + +typedef void (*RecDumpEntryCb) (RecT rec_type, void *edata, int registered, const char *name, int data_type, RecData *datum); + +typedef int (*RecMessageRecvCb) (RecMessage * msg, RecMessageT msg_type, void *cookie); + +#endif diff --git a/lib/records/P_RecLocal.h b/lib/records/P_RecLocal.h new file mode 100644 index 00000000..5a9c1bf5 --- /dev/null +++ b/lib/records/P_RecLocal.h @@ -0,0 +1,29 @@ +/** @file + + Nothing much + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_LOCAL_H_ +#define _P_REC_LOCAL_H_ + +#include "I_RecLocal.h" + +#endif diff --git a/lib/records/P_RecMessage.h b/lib/records/P_RecMessage.h new file mode 100644 index 00000000..713d8861 --- /dev/null +++ b/lib/records/P_RecMessage.h @@ -0,0 +1,53 @@ +/** @file + + Private RecMessage declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_MESSAGE_H_ +#define _P_REC_MESSAGE_H_ + +#include "P_RecDefs.h" + +//------------------------------------------------------------------------- +// Initialization +//------------------------------------------------------------------------- + +int RecMessageInit(RecModeT mode); + +//------------------------------------------------------------------------- +// Message Operations +//------------------------------------------------------------------------- + +RecMessage *RecMessageAlloc(RecMessageT msg_type, int initial_size = 256); +int RecMessageFree(RecMessage * msg); + +RecMessage *RecMessageMarshal_Realloc(RecMessage * msg, const RecRecord * record); +int RecMessageUnmarshalFirst(RecMessage * msg, RecMessageItr * itr, RecRecord ** record); +int RecMessageUnmarshalNext(RecMessage * msg, RecMessageItr * itr, RecRecord ** record); + +int RecMessageSend(RecMessage * msg); +int RecMessageRegisterRecvCb(RecMessageRecvCb recv_cb, void *cookie); +void *RecMessageRecvThis(void *cookie, char *data_raw, int data_len); + +RecMessage *RecMessageReadFromDisk(const char *fpath); +int RecMessageWriteToDisk(RecMessage *msg, const char *fpath); + +#endif diff --git a/lib/records/P_RecProcess.h b/lib/records/P_RecProcess.h new file mode 100644 index 00000000..4ebf774e --- /dev/null +++ b/lib/records/P_RecProcess.h @@ -0,0 +1,44 @@ +/** @file + + Private record process declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_PROCESS_H_ +#define _P_REC_PROCESS_H_ + +// Must include 'P_EventSystem.h' before 'I_EventSystem.h' (which is +// included in 'I_RecProcess.h') to prevent multiple-symbol-definition +// complaints if the caller uses both 'P_EventSystem.h' and this 'P_' +// file. +#include "P_EventSystem.h" + +#include "I_RecProcess.h" +#include "P_RecDefs.h" + +//------------------------------------------------------------------------- +// Protected Interface +//------------------------------------------------------------------------- + +int RecRegisterRawStatSyncCb(const char *name, RecRawStatSyncCb sync_cb, RecRawStatBlock * rsb, int id); + +int RecExecRawStatSyncCbs(); + +#endif diff --git a/lib/records/P_RecTree.h b/lib/records/P_RecTree.h new file mode 100644 index 00000000..ee30ecf8 --- /dev/null +++ b/lib/records/P_RecTree.h @@ -0,0 +1,93 @@ +/** @file + + Private RecTree and RecTreeNode declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_TREE_H_ +#define _P_REC_TREE_H_ + +#include "P_RecDefs.h" +#include "P_RecUtils.h" +#include "List.h" + +class RecTree; + +/************************************************************************* + * + * RecTreeNode + * + *************************************************************************/ +class RecTreeNode +{ +public: + RecTreeNode(const char *name = NULL); + ~RecTreeNode(); + + RecRecord *record_ptr; + RecTree *subtree_ptr; + char *node_name; + const char *var_name_ptr; + int num_leaf; + LINK(RecTreeNode, link); + + void print(); +}; + + +/************************************************************************* + * + * RecTree + * + *************************************************************************/ +class RecTree +{ +public: + RecTree(RecTreeNode *); + ~RecTree(); + + inline RecTreeNode *first() + { + return m_root.head; + }; + + inline RecTreeNode *last() + { + return m_root.tail; + }; + + inline RecTreeNode *next(RecTreeNode * current) + { + return (current->link).next; + }; + + void rec_tree_insert(const char *, const char *full_name = NULL); + RecTree *rec_tree_get(char *); + void rec_tree_get_list(char *, char ***, int *); + + void print(); + RecTreeNode *this_node; + +private: + void p_rec_tree_get_list(char *, char ***, int *); + Queue m_root; +}; + +#endif diff --git a/lib/records/P_RecUtils.h b/lib/records/P_RecUtils.h new file mode 100644 index 00000000..af46549b --- /dev/null +++ b/lib/records/P_RecUtils.h @@ -0,0 +1,68 @@ +/** @file + + Private record util declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _P_REC_UTILS_H_ +#define _P_REC_UTILS_H_ + +#include "Diags.h" +#include "ink_atomic.h" +#include "ink_defs.h" + +#include "P_RecDefs.h" + +//------------------------------------------------------------------------- +// Macros +//------------------------------------------------------------------------- + +#define REC_TYPE_IS_STAT(rec_type) \ + (((rec_type) == RECT_PROCESS) || \ + ((rec_type) == RECT_PLUGIN) || \ + ((rec_type) == RECT_NODE) || \ + ((rec_type) == RECT_CLUSTER)) + +#define REC_TYPE_IS_CONFIG(rec_type) \ + (((rec_type) == RECT_CONFIG) || \ + ((rec_type) == RECT_LOCAL)) + +#define REC_NOWARN_UNUSED(a) NOWARN_UNUSED(a) + +//------------------------------------------------------------------------- +// RecData Utils +//------------------------------------------------------------------------- + +RecRecord *RecAlloc(RecT rec_type, const char *name, RecDataT data_type); +void RecDataClear(RecDataT data_type, RecData * data); +bool RecDataSet(RecDataT data_type, RecData * data_dst, RecData * data_src); +bool RecDataSetFromInk64(RecDataT data_type, RecData * data_dst, int64_t data_int64); +bool RecDataSetFromFloat(RecDataT data_type, RecData * data_dst, float data_float); +bool RecDataSetFromString(RecDataT data_type, RecData * data_dst, char *data_string); + +//------------------------------------------------------------------------- +// Logging +//------------------------------------------------------------------------- + +void RecLog(DiagsLevel dl, const char *format_string, ...); +void RecDebug(DiagsLevel dl, const char *format_string, ...); +void RecDebugOff(); + +#endif diff --git a/lib/records/RecCompatibility.cc b/lib/records/RecCompatibility.cc new file mode 100644 index 00000000..e2b0f60d --- /dev/null +++ b/lib/records/RecCompatibility.cc @@ -0,0 +1,329 @@ +/** @file + + Record compatibility definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "P_RecCompatibility.h" +#include "P_RecDefs.h" +#include "P_RecUtils.h" + +//------------------------------------------------------------------------- +// RecFileOpenR +//------------------------------------------------------------------------- + +RecHandle +RecFileOpenR(const char *file) +{ + RecHandle h_file; + return ((h_file =::open(file, O_RDONLY)) <= 0) ? REC_HANDLE_INVALID : h_file; +} + +//------------------------------------------------------------------------- +// RecFileOpenW +//------------------------------------------------------------------------- + +RecHandle +RecFileOpenW(const char *file) +{ + RecHandle h_file; + + if ((h_file =::open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) { + return REC_HANDLE_INVALID; + } + fcntl(h_file, F_SETFD, 1); + return h_file; +} + +//------------------------------------------------------------------------- +// RecFileClose +//------------------------------------------------------------------------- + +void +RecFileClose(RecHandle h_file) +{ + close(h_file); +} + +//------------------------------------------------------------------------- +// RecFileRead +//------------------------------------------------------------------------- + +int +RecFileRead(RecHandle h_file, char *buf, int size, int *bytes_read) +{ + if ((*bytes_read =::read(h_file, buf, size)) <= 0) { + *bytes_read = 0; + return REC_ERR_FAIL; + } + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecFileWrite +//------------------------------------------------------------------------- + +int +RecFileWrite(RecHandle h_file, char *buf, int size, int *bytes_written) +{ + if ((*bytes_written =::write(h_file, buf, size)) < 0) { + *bytes_written = 0; + return REC_ERR_FAIL; + } + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecFileImport_Xmalloc +//------------------------------------------------------------------------- + +int +RecFileImport_Xmalloc(const char *file, char **file_buf, int *file_size) +{ + int err = REC_ERR_FAIL; + RecHandle h_file; + int bytes_read; + + if (file && file_buf && file_size) { + *file_buf = 0; + *file_size = 0; + if ((h_file = RecFileOpenR(file)) != REC_HANDLE_INVALID) { + *file_size = RecFileGetSize(h_file); + *file_buf = (char *) xmalloc(*file_size + 1); + if (RecFileRead(h_file, *file_buf, *file_size, &bytes_read) != REC_ERR_FAIL && bytes_read == *file_size) { + (*file_buf)[*file_size] = '\0'; + err = REC_ERR_OKAY; + } else { + xfree(*file_buf); + *file_buf = 0; + *file_size = 0; + } + RecFileClose(h_file); + } + } + + return err; +} + +//------------------------------------------------------------------------- +// RecFileGetSize +//------------------------------------------------------------------------- + +int +RecFileGetSize(RecHandle h_file) +{ + struct stat fileStats; + fstat(h_file, &fileStats); + return (int) fileStats.st_size; +} + +//------------------------------------------------------------------------- +// RecFileExists +//------------------------------------------------------------------------- + +int +RecFileExists(const char *file) +{ + RecHandle h_file; + if ((h_file = RecFileOpenR(file)) == REC_HANDLE_INVALID) { + return REC_ERR_FAIL; + } + RecFileClose(h_file); + return REC_ERR_OKAY; + +} + +//------------------------------------------------------------------------- +// RecPipeCreate +//------------------------------------------------------------------------- + +RecHandle +RecPipeCreate(const char *base_path, const char *name) +{ + + RecHandle listenfd; + RecHandle acceptfd; + struct sockaddr_un servaddr; + struct sockaddr_un cliaddr; + int servaddr_len; + socklen_t cliaddr_len; + + // first, let's disable SIGPIPE (move out later!) + struct sigaction act, oact; + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_flags |= SA_RESTART; + sigaction(SIGPIPE, &act, &oact); + + // construct a path/filename for the pipe +#define SEPERATOR "/" + char path[PATH_NAME_MAX]; + snprintf(path, sizeof(path), "%s%s%s", base_path, SEPERATOR, name); +#undef SEPERATOR + if (strlen(path) > (sizeof(servaddr.sun_path) - 1)) { + RecLog(DL_Warning, "[RecPipeCreate] Path name too long; exiting\n"); + return REC_HANDLE_INVALID; + } + + unlink(path); + + if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + RecLog(DL_Warning, "[RecPipeCreate] socket error\n"); + return REC_HANDLE_INVALID; + } + // set so that child process doesn't inherit our fd + if (fcntl(listenfd, F_SETFD, 1) < 0) { + RecLog(DL_Warning, "[RecPipeCreate] fcntl error\n"); + return REC_HANDLE_INVALID; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + ink_strncpy(servaddr.sun_path, path, sizeof(servaddr.sun_path)); + + int optval = 1; + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &optval, sizeof(int)) < 0) { + RecLog(DL_Warning, "[RecPipeCreate] setsockopt error\n"); + return REC_HANDLE_INVALID; + } + + servaddr_len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + if ((bind(listenfd, (struct sockaddr *) &servaddr, servaddr_len)) < 0) { + RecLog(DL_Warning, "[RecPipeCreate] bind error\n"); + return REC_HANDLE_INVALID; + } + // listen, backlog of 1 (expecting only one client) + if ((listen(listenfd, 1)) < 0) { + RecLog(DL_Warning, "[RecPipeCreate] listen error\n"); + return REC_HANDLE_INVALID; + } + // block until we get a connection from the other side + cliaddr_len = sizeof(cliaddr); + if ((acceptfd = accept(listenfd, (struct sockaddr *) &cliaddr, + &cliaddr_len)) < 0) { + return REC_HANDLE_INVALID; + } + + close(listenfd); + + return acceptfd; +} + +//------------------------------------------------------------------------- +// RecPipeConnect +//------------------------------------------------------------------------- + +RecHandle +RecPipeConnect(const char *base_path, const char *name) +{ + + RecHandle sockfd; + struct sockaddr_un servaddr; + int servaddr_len; + + // construct a path/filename for the pipe +#define SEPERATOR "/" + char path[PATH_NAME_MAX]; + snprintf(path, sizeof(path), "%s%s%s", base_path, SEPERATOR, name); +#undef SEPERATOR + if (strlen(path) > (sizeof(servaddr.sun_path) - 1)) { + RecLog(DL_Warning, "[RecPipeConnect] Path name too long\n"); + return REC_HANDLE_INVALID; + } + // Setup Connection to LocalManager */ + memset((char *) &servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + ink_strncpy(servaddr.sun_path, path, sizeof(servaddr.sun_path)); + servaddr_len = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path); + + if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + RecLog(DL_Warning, "[RecPipeConnect] socket error\n"); + return REC_HANDLE_INVALID; + } + // set so that child process doesn't inherit our fd + if (fcntl(sockfd, F_SETFD, 1) < 0) { + RecLog(DL_Warning, "[RecPipeConnect] fcntl error\n"); + return REC_HANDLE_INVALID; + } + // blocking connect + if ((connect(sockfd, (struct sockaddr *) &servaddr, servaddr_len)) < 0) { + RecLog(DL_Warning, "[RecPipeConnect] connect error\n"); + return REC_HANDLE_INVALID; + } + + return sockfd; +} + +//------------------------------------------------------------------------- +// RecPipeRead +//------------------------------------------------------------------------- + +int +RecPipeRead(RecHandle h_pipe, char *buf, int size) +{ + int bytes_read = 0; + int bytes_wanted = size; + char *p = buf; + while (bytes_wanted > 0) { + bytes_read = read(h_pipe, p, bytes_wanted); + if (bytes_read < 0) { + // FIXME: something more intelligent please! + return REC_ERR_FAIL; + } + bytes_wanted -= bytes_read; + p += bytes_read; + } + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecPipeWrite +//------------------------------------------------------------------------- + +int +RecPipeWrite(RecHandle h_pipe, char *buf, int size) +{ + int bytes_written = 0; + int bytes_to_write = size; + char *p = buf; + while (bytes_to_write > 0) { + bytes_written = write(h_pipe, p, bytes_to_write); + if (bytes_written < 0) { + // FIXME: something more intelligent please! + return REC_ERR_FAIL; + } + bytes_to_write -= bytes_written; + p += bytes_written; + } + + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecPipeClose +//------------------------------------------------------------------------- + +int +RecPipeClose(RecHandle h_pipe) +{ + return (close(h_pipe) == 0) ? REC_ERR_OKAY : REC_ERR_FAIL; +} diff --git a/lib/records/RecCore.cc b/lib/records/RecCore.cc new file mode 100644 index 00000000..15fd3a3d --- /dev/null +++ b/lib/records/RecCore.cc @@ -0,0 +1,1136 @@ +/** @file + + Record core definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#include "P_RecCompatibility.h" +#include "P_RecCore.h" +#include "P_RecUtils.h" +#include "P_RecTree.h" +#include "I_Layout.h" + +static bool g_initialized = false; + +Diags *g_diags = NULL; + +RecRecord *g_records = NULL; +InkHashTable *g_records_ht = NULL; +ink_rwlock g_records_rwlock; +int g_num_records = 0; + +const char *g_rec_config_fpath = NULL; +LLQ *g_rec_config_contents_llq = NULL; +InkHashTable *g_rec_config_contents_ht = NULL; +ink_mutex g_rec_config_lock; + +const char *g_stats_snap_fpath = NULL; +int g_num_update[RECT_MAX]; + +RecTree *g_records_tree = NULL; + +//------------------------------------------------------------------------- +// register_record +//------------------------------------------------------------------------- +static RecRecord * +register_record(RecT rec_type, const char *name, RecDataT data_type, RecData data_default, bool release_record_lock) +{ + RecRecord *r = NULL; + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + if (release_record_lock) { + rec_mutex_acquire(&(r->lock)); + } + ink_release_assert(r->rec_type == rec_type); + ink_release_assert(r->data_type == data_type); + // Note: do not set r->data as we want to keep the previous value + RecDataSet(r->data_type, &(r->data_default), &(data_default)); + } else { + if ((r = RecAlloc(rec_type, name, data_type)) == NULL) { + return NULL; + } + if (release_record_lock) { + rec_mutex_acquire(&(r->lock)); + } + // Set the r->data to its default value as this is a new record + RecDataSet(r->data_type, &(r->data), &(data_default)); + RecDataSet(r->data_type, &(r->data_default), &(data_default)); + ink_hash_table_insert(g_records_ht, name, (void *) r); + } + + // we're now registered + r->registered = true; + + if (release_record_lock) { + rec_mutex_release(&(r->lock)); + } + + return r; +} + + +//------------------------------------------------------------------------- +// link_XXX +//------------------------------------------------------------------------- +static int +link_int(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + RecInt *rec_int = (RecInt *) cookie; + ink_atomic_swap64(rec_int, data.rec_int); + return REC_ERR_OKAY; +} + +static int +link_int32(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + *((int32_t *) cookie) = (int32_t) data.rec_int; + return REC_ERR_OKAY; +} + +static int +link_uint32(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + *((uint32_t *) cookie) = (uint32_t) data.rec_int; + return REC_ERR_OKAY; +} + +static int +link_float(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + *((RecFloat *) cookie) = data.rec_float; + return REC_ERR_OKAY; +} + +static int +link_counter(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + RecCounter *rec_counter = (RecCounter *) cookie; + ink_atomic_swap64(rec_counter, data.rec_counter); + return REC_ERR_OKAY; +} + +// This is a convenience wrapper, to allow us to treat the RecInt's as a +// 1-byte entity internally. +static int +link_byte(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + RecByte *rec_byte = (RecByte *) cookie; + RecByte byte = static_cast(data.rec_int); + + ink_atomic_swap8(rec_byte, byte); + return REC_ERR_OKAY; +} + +// mimic Config.cc::config_string_alloc_cb +static int +link_string_alloc(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + REC_NOWARN_UNUSED(name); + REC_NOWARN_UNUSED(data_type); + + RecString _ss = (RecString) cookie; + RecString _new_value = 0; + + int len = -1; + if (_ss) { + len = strlen(_ss); + _new_value = (RecString) xmalloc(len + 1); + memcpy(_new_value, _ss, len + 1); + } + + RecString _temp2 = data.rec_string; + data.rec_string = _new_value; + + if (_temp2 != 0) { + xfree(_temp2); + } + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecCoreInit +//------------------------------------------------------------------------- +int +RecCoreInit(RecModeT mode_type, Diags *_diags) +{ + if (g_initialized) { + return REC_ERR_OKAY; + } + + // set our diags + ink_atomic_swap_ptr(&g_diags, _diags); + + g_records_tree = new RecTree(NULL); + g_num_records = 0; + + // initialize record array for our internal stats (this can be reallocated later) + g_records = (RecRecord *) xmalloc(REC_MAX_RECORDS * sizeof(RecRecord)); + memset(g_records, 0, REC_MAX_RECORDS * sizeof(RecRecord)); + + // initialize record hash index + g_records_ht = ink_hash_table_create(InkHashTableKeyType_String); + ink_rwlock_init(&g_records_rwlock); + if (!g_records_ht) { + return REC_ERR_FAIL; + } + // read stats + if ((mode_type == RECM_SERVER) || (mode_type == RECM_STAND_ALONE)) { + g_stats_snap_fpath = Layout::relative_to(Layout::get()->runtimedir, REC_RAW_STATS_FILE); + RecReadStatsFile(); + } + // read configs + if ((mode_type == RECM_SERVER) || (mode_type == RECM_STAND_ALONE)) { + ink_mutex_init(&g_rec_config_lock, NULL); + g_rec_config_contents_llq = create_queue(); + g_rec_config_contents_ht = ink_hash_table_create(InkHashTableKeyType_String); + // Import the file into memory; try the following in this order: + // ./etc/trafficserver/records.config.shadow + // ./records.config.shadow + // ./etc/trafficserver/records.config + // ./records.config + bool file_exists = true; + g_rec_config_fpath = Layout::relative_to(Layout::get()->sysconfdir, REC_CONFIG_FILE REC_SHADOW_EXT); + if (RecFileExists(g_rec_config_fpath) == REC_ERR_FAIL) { + xfree((char *)g_rec_config_fpath); + g_rec_config_fpath = Layout::relative_to(Layout::get()->sysconfdir, REC_CONFIG_FILE); + if (RecFileExists(g_rec_config_fpath) == REC_ERR_FAIL) { + RecLog(DL_Warning, "Could not find '%s', system will run with defaults\n", REC_CONFIG_FILE); + file_exists = false; + } + } + if (file_exists) { + RecReadConfigFile(); + } + } + + for (int i = 0; i < RECT_MAX; i++) { + g_num_update[i] = 0; + } + + g_initialized = true; + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecSetDiags +//------------------------------------------------------------------------- +int +RecSetDiags(Diags * _diags) +{ + // Warning! It's very dangerous to change diags on the fly! This + // function only exists so that we can boot-strap TM on startup. + ink_atomic_swap_ptr(&g_diags, _diags); + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecLinkCnfigXXX +//------------------------------------------------------------------------- +int +RecLinkConfigInt(const char *name, RecInt * rec_int) +{ + if (RecGetRecordInt(name, rec_int) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + return RecRegisterConfigUpdateCb(name, link_int, (void *) rec_int); +} + +int +RecLinkConfigInk32(const char *name, int32_t * p_int32) +{ + return RecRegisterConfigUpdateCb(name, link_int32, (void *) p_int32); +} + +int +RecLinkConfigInkU32(const char *name, uint32_t * p_uint32) +{ + return RecRegisterConfigUpdateCb(name, link_uint32, (void *) p_uint32); +} + +int +RecLinkConfigFloat(const char *name, RecFloat * rec_float) +{ + if (RecGetRecordFloat(name, rec_float) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + return RecRegisterConfigUpdateCb(name, link_float, (void *) rec_float); +} + +int +RecLinkConfigCounter(const char *name, RecCounter * rec_counter) +{ + if (RecGetRecordCounter(name, rec_counter) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + return RecRegisterConfigUpdateCb(name, link_counter, (void *) rec_counter); +} + +int +RecLinkConfigString(const char *name, RecString * rec_string) +{ + if (RecGetRecordString_Xmalloc(name, rec_string) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + return RecRegisterConfigUpdateCb(name, link_string_alloc, (void *) rec_string); +} + +int +RecLinkConfigByte(const char *name, RecByte * rec_byte) +{ + if (RecGetRecordByte(name, rec_byte) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + return RecRegisterConfigUpdateCb(name, link_byte, (void *) rec_byte); +} + + +//------------------------------------------------------------------------- +// RecRegisterConfigUpdateCb +//------------------------------------------------------------------------- +int +RecRegisterConfigUpdateCb(const char *name, RecConfigUpdateCb update_cb, void *cookie) +{ + int err = REC_ERR_FAIL; + RecRecord *r; + + ink_rwlock_rdlock(&g_records_rwlock); + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_CONFIG(r->rec_type)) { + /* -- upgrade to support a list of callback functions + if (!(r->config_meta.update_cb)) { + r->config_meta.update_cb = update_cb; + r->config_meta.update_cookie = cookie; + err = REC_ERR_OKAY; + } + */ + + RecConfigUpdateCbList *new_callback = (RecConfigUpdateCbList *) xmalloc(sizeof(RecConfigUpdateCbList)); + memset(new_callback, 0, sizeof(RecConfigUpdateCbList)); + new_callback->update_cb = update_cb; + new_callback->update_cookie = cookie; + + new_callback->next = NULL; + + ink_debug_assert(new_callback); + if (!r->config_meta.update_cb_list) { + r->config_meta.update_cb_list = new_callback; + } else { + RecConfigUpdateCbList *cur_callback = NULL; + RecConfigUpdateCbList *prev_callback = NULL; + for (cur_callback = r->config_meta.update_cb_list; cur_callback; cur_callback = cur_callback->next) { + prev_callback = cur_callback; + } + ink_debug_assert(prev_callback); + ink_debug_assert(!prev_callback->next); + prev_callback->next = new_callback; + } + err = REC_ERR_OKAY; + } + + rec_mutex_release(&(r->lock)); + } + + ink_rwlock_unlock(&g_records_rwlock); + + return err; +} + + +//------------------------------------------------------------------------- +// RecGetRecordXXX +//------------------------------------------------------------------------- +int +RecGetRecordInt(const char *name, RecInt *rec_int, bool lock) +{ + int err; + RecData data; + if ((err = RecGetRecord_Xmalloc(name, RECD_INT, &data, lock)) == REC_ERR_OKAY) + *rec_int = data.rec_int; + return err; +} + +int +RecGetRecordFloat(const char *name, RecFloat * rec_float, bool lock) +{ + int err; + RecData data; + if ((err = RecGetRecord_Xmalloc(name, RECD_FLOAT, &data, lock)) == REC_ERR_OKAY) + *rec_float = data.rec_float; + return err; +} + +int +RecGetRecordString(const char *name, char *buf, int buf_len, bool lock) +{ + int err = REC_ERR_OKAY; + RecRecord *r; + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (!r->registered || (r->data_type != RECD_STRING)) { + err = REC_ERR_FAIL; + } else { + if (r->data.rec_string == NULL) { + buf[0] = '\0'; + } else { + strncpy(buf, r->data.rec_string, buf_len - 1); + buf[buf_len - 1] = '\0'; + } + } + rec_mutex_release(&(r->lock)); + } else { + err = REC_ERR_FAIL; + } + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + return err; +} + +int +RecGetRecordString_Xmalloc(const char *name, RecString * rec_string, bool lock) +{ + int err; + RecData data; + if ((err = RecGetRecord_Xmalloc(name, RECD_STRING, &data, lock)) == REC_ERR_OKAY) + *rec_string = data.rec_string; + return err; +} + +int +RecGetRecordCounter(const char *name, RecCounter * rec_counter, bool lock) +{ + int err; + RecData data; + if ((err = RecGetRecord_Xmalloc(name, RECD_COUNTER, &data, lock)) == REC_ERR_OKAY) + *rec_counter = data.rec_counter; + return err; +} + +int +RecGetRecordByte(const char *name, RecByte *rec_byte, bool lock) +{ + int err; + RecData data; + if ((err = RecGetRecord_Xmalloc(name, RECD_INT, &data, lock)) == REC_ERR_OKAY) + *rec_byte = data.rec_int; + return err; +} + + +//------------------------------------------------------------------------- +// RecGetRec Attributes +//------------------------------------------------------------------------- +int +RecGetRecordType(const char *name, RecT * rec_type, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + *rec_type = r->rec_type; + err = REC_ERR_OKAY; + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +int +RecGetRecordDataType(const char *name, RecDataT * data_type, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (!r->registered) { + err = REC_ERR_FAIL; + } else { + *data_type = r->data_type; + err = REC_ERR_OKAY; + } + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + +int +RecGetRecordUpdateCount(RecT data_type) +{ + return g_num_update[data_type]; +} + +int +RecGetRecordOrderAndId(const char *name, int* order, int* id, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (order) + *order = r->order; + if (id) + *id = r->rsb_id; + err = REC_ERR_OKAY; + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + +int +RecGetRecordUpdateType(const char *name, RecUpdateT *update_type, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_CONFIG(r->rec_type)) { + *update_type = r->config_meta.update_type; + err = REC_ERR_OKAY; + } else { + ink_debug_assert(!"rec_type is not CONFIG"); + } + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +int +RecGetRecordCheckType(const char *name, RecCheckT *check_type, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_CONFIG(r->rec_type)) { + *check_type = r->config_meta.check_type; + err = REC_ERR_OKAY; + } else { + ink_debug_assert(!"rec_type is not CONFIG"); + } + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +int +RecGetRecordCheckExpr(const char *name, char **check_expr, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_CONFIG(r->rec_type)) { + *check_expr = r->config_meta.check_expr; + err = REC_ERR_OKAY; + } else { + ink_debug_assert(!"rec_type is not CONFIG"); + } + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +int +RecGetRecordDefaultDataString_Xmalloc(char *name, char **buf, bool lock) +{ + REC_NOWARN_UNUSED(lock); + int err; + RecRecord *r = NULL; + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + *buf = (char *) xmalloc(sizeof(char) * 1024); + memset(*buf, 0, 1024); + err = REC_ERR_OKAY; + + switch (r->data_type) { + case RECD_INT: + snprintf(*buf, 1023, "%" PRId64 "", r->data_default.rec_int); + break; + case RECD_FLOAT: + snprintf(*buf, 1023, "%f", r->data_default.rec_float); + break; + case RECD_STRING: + if (r->data_default.rec_string) { + strncpy(*buf, r->data_default.rec_string, 1023); + buf[1023] = '\0'; + } else { + xfree(*buf); + *buf = NULL; + } + break; + case RECD_COUNTER: + snprintf(*buf, 1023, "%" PRId64 "", r->data_default.rec_counter); + break; + default: + ink_debug_assert(!"Unexpected RecD type"); + xfree(*buf); + *buf = NULL; + break; + } + } else { + err = REC_ERR_FAIL; + } + + return err; +} + + +int +RecGetRecordAccessType(const char *name, RecAccessT *access, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + *access = r->config_meta.access_type; + err = REC_ERR_OKAY; + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +int +RecSetRecordAccessType(const char *name, RecAccessT access, bool lock) +{ + int err = REC_ERR_FAIL; + RecRecord *r = NULL; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + r->config_meta.access_type = access; + err = REC_ERR_OKAY; + rec_mutex_release(&(r->lock)); + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +//------------------------------------------------------------------------- +// RecRegisterStat +//------------------------------------------------------------------------- +RecRecord * +RecRegisterStat(RecT rec_type, const char *name, RecDataT data_type, RecData data_default, RecPersistT persist_type) +{ + RecRecord *r = NULL; + + ink_rwlock_wrlock(&g_records_rwlock); + if ((r = register_record(rec_type, name, data_type, data_default, false)) != NULL) { + r->stat_meta.persist_type = persist_type; + rec_mutex_release(&(r->lock)); + } else { + ink_debug_assert(!"Can't register record!"); + } + ink_rwlock_unlock(&g_records_rwlock); + + return r; +} + + +//------------------------------------------------------------------------- +// RecRegisterConfig +//------------------------------------------------------------------------- +RecRecord * +RecRegisterConfig(RecT rec_type, const char *name, RecDataT data_type, + RecData data_default, RecUpdateT update_type, + RecCheckT check_type, const char *check_expr, RecAccessT access_type) +{ + RecRecord *r; + ink_rwlock_wrlock(&g_records_rwlock); + if ((r = register_record(rec_type, name, data_type, data_default, false)) != NULL) { + // Note: do not modify 'record->config_meta.update_required' + r->config_meta.update_type = update_type; + r->config_meta.check_type = check_type; + if (r->config_meta.check_expr) { + xfree(r->config_meta.check_expr); + } + r->config_meta.check_expr = xstrdup(check_expr); + r->config_meta.update_cb_list = NULL; + r->config_meta.access_type = access_type; + rec_mutex_release(&(r->lock)); + } + ink_rwlock_unlock(&g_records_rwlock); + + return r; +} + + +//------------------------------------------------------------------------- +// RecGetRecord_Xmalloc +//------------------------------------------------------------------------- +int +RecGetRecord_Xmalloc(const char *name, RecDataT data_type, RecData *data, bool lock) +{ + int err = REC_ERR_OKAY; + RecRecord *r; + + if (lock) { + ink_rwlock_rdlock(&g_records_rwlock); + } + + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (!r->registered || (r->data_type != data_type)) { + err = REC_ERR_FAIL; + } else { + // Clear the caller's record just in case it has trash in it. + // Passing trashy records to RecDataSet will cause confusion. + memset(data, 0, sizeof(RecData)); + RecDataSet(data_type, data, &(r->data)); + } + rec_mutex_release(&(r->lock)); + } else { + err = REC_ERR_FAIL; + } + + if (lock) { + ink_rwlock_unlock(&g_records_rwlock); + } + + return err; +} + + +//------------------------------------------------------------------------- +// RecForceInsert +//------------------------------------------------------------------------- +RecRecord * +RecForceInsert(RecRecord * record) +{ + RecRecord *r = NULL; + bool r_is_a_new_record; + + ink_rwlock_wrlock(&g_records_rwlock); + + if (ink_hash_table_lookup(g_records_ht, record->name, (void **) &r)) { + r_is_a_new_record = false; + rec_mutex_acquire(&(r->lock)); + r->rec_type = record->rec_type; + r->data_type = record->data_type; + } else { + r_is_a_new_record = true; + if ((r = RecAlloc(record->rec_type, record->name, record->data_type)) == NULL) { + ink_rwlock_unlock(&g_records_rwlock); + return NULL; + } + } + + // set the record value + RecDataSet(r->data_type, &(r->data), &(record->data)); + RecDataSet(r->data_type, &(r->data_default), &(record->data_default)); + r->registered = record->registered; + if (REC_TYPE_IS_STAT(r->rec_type)) { + r->stat_meta.persist_type = record->stat_meta.persist_type; + r->stat_meta.data_raw = record->stat_meta.data_raw; + } else if (REC_TYPE_IS_CONFIG(r->rec_type)) { + r->config_meta.update_required = record->config_meta.update_required; + r->config_meta.update_type = record->config_meta.update_type; + r->config_meta.check_type = record->config_meta.check_type; + if (r->config_meta.check_expr) { + xfree(r->config_meta.check_expr); + } + r->config_meta.check_expr = xstrdup(record->config_meta.check_expr); + r->config_meta.access_type = record->config_meta.access_type; + } + + if (r_is_a_new_record) { + ink_hash_table_insert(g_records_ht, r->name, (void *) r); + } else { + rec_mutex_release(&(r->lock)); + } + + ink_rwlock_unlock(&g_records_rwlock); + + return r; +} + + +//------------------------------------------------------------------------- +// RecDumpRecordsHt +//------------------------------------------------------------------------- + +static void +debug_record_callback(RecT rec_type, void *edata, int registered, const char *name, int data_type, RecData *datum) +{ + NOWARN_UNUSED(edata); + NOWARN_UNUSED(rec_type); + + switch(data_type) { + case RECD_INT: + RecDebug(DL_Note, " ([%d] '%s', '%" PRId64 "')", registered, name, datum->rec_int); + break; + case RECD_FLOAT: + RecDebug(DL_Note, " ([%d] '%s', '%f')", registered, name, datum->rec_float); + break; + case RECD_STRING: + RecDebug(DL_Note, " ([%d] '%s', '%s')", + registered, name, datum->rec_string ? datum->rec_string : "NULL"); + break; + case RECD_COUNTER: + RecDebug(DL_Note, " ([%d] '%s', '%" PRId64 "')", registered, name, datum->rec_counter); + break; + default: + RecDebug(DL_Note, " ([%d] '%s', )", registered, name); + break; + } +} +void +RecDumpRecords(RecT rec_type, RecDumpEntryCb callback, void *edata) +{ + int i, num_records; + + num_records = g_num_records; + for (i = 0; i < num_records; i++) { + RecRecord *r = &(g_records[i]); + if ((rec_type == RECT_NULL) || (rec_type == r->rec_type)) { + rec_mutex_acquire(&(r->lock)); + callback(rec_type, edata, r->registered, r->name, r->data_type, &r->data); + rec_mutex_release(&(r->lock)); + } + } +} + +void +RecDumpRecordsHt(RecT rec_type) { + RecDebug(DL_Note, "Dumping Records:"); + RecDumpRecords(rec_type, debug_record_callback, NULL); +} + +void +RecGetRecordTree(char *subtree) +{ + RecTree *tree = g_records_tree; + if (subtree) { + tree = tree->rec_tree_get(subtree); + } + tree->print(); +} + +void +RecGetRecordList(char *var, char ***buffer, int *count) +{ + g_records_tree->rec_tree_get_list(&(*var), &(*buffer), &(*count)); +} + + +//------------------------------------------------------------------------- +// RecGetRecordPrefix_Xmalloc +// +// mimics/replaces proxy/StatSystem.cc::stat_callback(). +// returns the number of variables name match the prefix. +//------------------------------------------------------------------------- +int +RecGetRecordPrefix_Xmalloc(char *prefix, char **buf, int *buf_len) +{ + int num_records = g_num_records; + int result_size = num_records * 128; /* estimate buffer size */ + int num_matched = 0; + char *result = NULL; + + result = (char *) xmalloc(result_size * sizeof(char)); + memset(result, 0, result_size * sizeof(char)); + + int i; + for (i = 0; i < num_records; i++) { + RecRecord *r = &(g_records[i]); + if (strncmp(prefix, r->name, strlen(prefix)) == 0) { + rec_mutex_acquire(&(r->lock)); + switch (r->data_type) { + case RECD_INT: + num_matched++; + sprintf(&result[strlen(result)], "%s=%" PRId64 "\r\n", r->name, r->data.rec_int); + break; + case RECD_FLOAT: + num_matched++; + sprintf(&result[strlen(result)], "%s=%f\r\n", r->name, r->data.rec_float); + break; + case RECD_STRING: + num_matched++; + sprintf(&result[strlen(result)], "%s=%s\r\n", r->name, r->data.rec_string ? r->data.rec_string : "NULL"); + break; + case RECD_COUNTER: + num_matched++; + sprintf(&result[strlen(result)], "%s=%" PRId64 "\r\n", r->name, r->data.rec_int); + break; + default: + break; + } + rec_mutex_release(&(r->lock)); + } + } + + *buf = result; + *buf_len = strlen(result); + + return num_matched; +} + + +//------------------------------------------------------------------------- +// Backwards compatibility ... TODO: Should eliminate these +//------------------------------------------------------------------------- +RecInt +REC_ConfigReadInteger(const char *name) +{ + RecInt t = 0; + RecGetRecordInt(name, &t); + return t; +} + +char * +REC_ConfigReadString(const char *name) +{ + char *t = 0; + RecGetRecordString_Xmalloc(name, (RecString *) & t); + return t; +} + +RecFloat +REC_ConfigReadFloat(const char *name) +{ + RecFloat t = 0; + RecGetRecordFloat(name, (RecFloat *) & t); + return t; +} + +RecCounter +REC_ConfigReadCounter(const char *name) +{ + RecCounter t = 0; + RecGetRecordCounter(name, (RecCounter *) & t); + return t; +} + + +//------------------------------------------------------------------------- +// Backwards compatibility. TODO: Should remove these. +//------------------------------------------------------------------------- +RecInt +REC_readInteger(const char *name, bool * found, bool lock) +{ + ink_debug_assert(name); + RecInt _tmp = 0; + bool _found; + _found = (RecGetRecordInt(name, &_tmp, lock) == REC_ERR_OKAY); + if (found) + *found = _found; + return _tmp; +} + +RecFloat +REC_readFloat(char *name, bool * found, bool lock) +{ + ink_debug_assert(name); + RecFloat _tmp = 0.0; + bool _found; + _found = (RecGetRecordFloat(name, &_tmp, lock) == REC_ERR_OKAY); + if (found) + *found = _found; + return _tmp; +} + +RecCounter +REC_readCounter(char *name, bool * found, bool lock) +{ + ink_debug_assert(name); + RecCounter _tmp = 0; + bool _found; + _found = (RecGetRecordCounter(name, &_tmp, lock) == REC_ERR_OKAY); + if (found) + *found = _found; + return _tmp; +} + +RecString +REC_readString(const char *name, bool * found, bool lock) +{ + ink_debug_assert(name); + RecString _tmp = NULL; + bool _found; + _found = (RecGetRecordString_Xmalloc(name, &_tmp, lock) == REC_ERR_OKAY); + if (found) + *found = _found; + return _tmp; +} + + +//------------------------------------------------------------------------- +// REC_SignalManager (TS) +//------------------------------------------------------------------------- +#if defined (REC_BUILD_MGMT) + +#if defined(LOCAL_MANAGER) + +#include "LocalManager.h" + +void +RecSignalManager(int id, const char *msg) +{ + REC_NOWARN_UNUSED(id); + REC_NOWARN_UNUSED(msg); +} + +int +RecRegisterManagerCb(int _signal, RecManagerCb _fn, void *_data) +{ + return lmgmt->registerMgmtCallback(_signal, _fn, _data); +} + +#elif defined(PROCESS_MANAGER) + +#include "ProcessManager.h" + +void +RecSignalManager(int id, const char *msg) +{ + ink_debug_assert(pmgmt); + pmgmt->signalManager(id, msg); +} + +int +RecRegisterManagerCb(int _signal, RecManagerCb _fn, void *_data) +{ + return pmgmt->registerMgmtCallback(_signal, _fn, _data); +} + +#endif // LOCAL_MANAGER + +#else + +void +RecSignalManager(int id, const char *msg) +{ + REC_NOWARN_UNUSED(id); + RecLog(DL_Warning, msg); +} + +int +RecRegisterManagerCb(int _signal, RecManagerCb _fn, void *_data) +{ + return -1; +} + +#endif // REC_BUILD_MGMT diff --git a/lib/records/RecLocal.cc b/lib/records/RecLocal.cc new file mode 100644 index 00000000..e0ab203f --- /dev/null +++ b/lib/records/RecLocal.cc @@ -0,0 +1,196 @@ +/** @file + + Record local definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "ParseRules.h" +#include "P_RecCore.h" +#include "P_RecLocal.h" +#include "P_RecMessage.h" +#include "P_RecUtils.h" + +static bool g_initialized = false; +static bool g_message_initialized = false; +static RecModeT g_mode_type = RECM_NULL; + +#define REC_LOCAL +#include "P_RecCore.i" +#undef REC_LOCAL + +//------------------------------------------------------------------------- +// +// REC_BUILD_STAND_ALONE IMPLEMENTATION +// +//------------------------------------------------------------------------- +#if defined (REC_BUILD_STAND_ALONE) + + +//------------------------------------------------------------------------- +// sync_thr +//------------------------------------------------------------------------- +static void * +sync_thr(void *data) +{ + REC_NOWARN_UNUSED(data); + textBuffer tb(65536); + while (1) { + send_push_message(); + RecSyncStatsFile(); + if (RecSyncConfigToTB(&tb) == REC_ERR_OKAY) { + int nbytes; + RecDebug(DL_Note, "Writing '%s'", g_rec_config_fpath); + RecHandle h_file = RecFileOpenW(g_rec_config_fpath); + RecFileWrite(h_file, tb.bufPtr(), tb.spaceUsed(), &nbytes); + RecFileClose(h_file); + } + sleep(REC_REMOTE_SYNC_INTERVAL_SEC); + } + return NULL; +} + + +//------------------------------------------------------------------------- +// +// REC_BUILD_MGMT IMPLEMENTATION +// +//------------------------------------------------------------------------- +#elif defined (REC_BUILD_MGMT) + +#include "Main.h" + + +//------------------------------------------------------------------------- +// sync_thr +//------------------------------------------------------------------------- +static void * +sync_thr(void *data) +{ + REC_NOWARN_UNUSED(data); + textBuffer *tb = NEW(new textBuffer(65536)); + Rollback *rb; + + while (1) { + send_push_message(); + RecSyncStatsFile(); + if (RecSyncConfigToTB(tb) == REC_ERR_OKAY) { + if (configFiles->getRollbackObj(REC_CONFIG_FILE, &rb)) { + RecDebug(DL_Note, "Rollback: '%s'", REC_CONFIG_FILE); + version_t ver = rb->getCurrentVersion(); + if ((rb->updateVersion(tb, ver, -1, false)) != OK_ROLLBACK) { + RecDebug(DL_Note, "Rollback failed: '%s'", REC_CONFIG_FILE); + } + } else { + int nbytes; + RecDebug(DL_Note, "Writing '%s'", g_rec_config_fpath); + RecHandle h_file = RecFileOpenW(g_rec_config_fpath); + RecFileWrite(h_file, tb->bufPtr(), tb->spaceUsed(), &nbytes); + RecFileClose(h_file); + } + } + sleep(REC_REMOTE_SYNC_INTERVAL_SEC); + } + return NULL; +} + +#endif + + +//------------------------------------------------------------------------- +// config_update_thr +//------------------------------------------------------------------------- +static void * +config_update_thr(void *data) +{ + REC_NOWARN_UNUSED(data); + while (true) { + RecExecConfigUpdateCbs(); + sleep(REC_CONFIG_UPDATE_INTERVAL_SEC); + } + return NULL; +} + + +//------------------------------------------------------------------------- +// RecLocalInit +//------------------------------------------------------------------------- +int +RecLocalInit(Diags * _diags) +{ + if (g_initialized) { + return REC_ERR_OKAY; + } + + g_mode_type = RECM_SERVER; + + if (RecCoreInit(RECM_SERVER, _diags) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + + /* -- defer RecMessageInit() until LocalManager is initialized + if (RecMessageInit(RECM_SERVER) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + + if (RecMessageRegisterRecvCb(recv_message_cb, NULL)) { + return REC_ERR_FAIL; + } + */ + g_initialized = true; + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecLocalInitMessage +//------------------------------------------------------------------------- +int +RecLocalInitMessage() +{ + if (g_message_initialized) { + return REC_ERR_OKAY; + } + + if (RecMessageInit(RECM_SERVER) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + + if (RecMessageRegisterRecvCb(recv_message_cb, NULL)) { + return REC_ERR_FAIL; + } + + g_message_initialized = true; + + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecLocalStart +//------------------------------------------------------------------------- +int +RecLocalStart() +{ + ink_thread_create(sync_thr, NULL); + ink_thread_create(config_update_thr, NULL); + + return REC_ERR_OKAY; +} diff --git a/lib/records/RecMessage.cc b/lib/records/RecMessage.cc new file mode 100644 index 00000000..4a0daceb --- /dev/null +++ b/lib/records/RecMessage.cc @@ -0,0 +1,572 @@ +/** @file + + Record message definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#include "P_RecCompatibility.h" +#include "P_RecMessage.h" +#include "P_RecUtils.h" +#include "I_Layout.h" + +static bool g_message_initialized = false; +static RecMessageRecvCb g_recv_cb = NULL; +static void *g_recv_cookie = NULL; +static RecModeT g_mode_type; + +//------------------------------------------------------------------------- +// +// REC_BUILD_STAND_ALONE IMPLEMENTATION +// +//------------------------------------------------------------------------- +#if defined (REC_BUILD_STAND_ALONE) + +static LLQ *g_send_llq = NULL; +static LLQ *g_recv_llq = NULL; + +//------------------------------------------------------------------------- +// send_thr +//------------------------------------------------------------------------- + +static void * +send_thr(void *data) +{ + int msg_size; + RecMessageHdr *msg_hdr; + RecHandle h_pipe = (RecHandle)(intptr_t)data; + while (true) { + // dequeue will block if there's nothing in the queue + msg_hdr = (RecMessageHdr *) dequeue(g_send_llq); + msg_size = (msg_hdr->o_end - msg_hdr->o_start) + sizeof(RecMessageHdr); + if (RecPipeWrite(h_pipe, (char *) msg_hdr, msg_size) == REC_ERR_FAIL) { + ink_release_assert("Pipe write failed, message lost"); + } + xfree(msg_hdr); + } + return NULL; +} + +//------------------------------------------------------------------------- +// recv_thr +//------------------------------------------------------------------------- + +static void * +recv_thr(void *data) +{ + int msg_size; + RecMessageHdr msg_hdr; + RecMessage *msg; + RecHandle h_pipe = (RecHandle)(intptr_t)data; + while (true) { + if (RecPipeRead(h_pipe, (char *) (&msg_hdr), sizeof(RecMessageHdr)) == REC_ERR_FAIL) { + ink_release_assert("Pipe read failed"); + } + msg = (RecMessage *) xmalloc((msg_hdr.o_end - msg_hdr.o_start) + sizeof(RecMessageHdr)); + memcpy(msg, &msg_hdr, sizeof(RecMessageHdr)); + if (RecPipeRead(h_pipe, (char *) (msg) + msg_hdr.o_start, msg_hdr.o_end - msg_hdr.o_start) == REC_ERR_FAIL) { + ink_release_assert("Pipe read failed"); + } + msg_size = msg_hdr.o_end - msg_hdr.o_start + sizeof(RecMessageHdr); + enqueue(g_recv_llq, msg); + } + return NULL; +} + +//------------------------------------------------------------------------- +// accept_thr +//------------------------------------------------------------------------- + +static void * +accept_thr(void *data) +{ + REC_NOWARN_UNUSED(data); + RecHandle h_pipe; + h_pipe = RecPipeCreate(Layout::get()->runtimedir, REC_PIPE_NAME); + ink_thread_create(send_thr, (void *) h_pipe); + ink_thread_create(recv_thr, (void *) h_pipe); + return NULL; +} + +//------------------------------------------------------------------------- +// recv_cb_thr +//------------------------------------------------------------------------- + +static void * +recv_cb_thr(void *data) +{ + REC_NOWARN_UNUSED(data); + RecMessage *msg; + while (true) { + if (g_recv_cb) { + msg = (RecMessage *) dequeue(g_recv_llq); + RecMessageRecvThis(0, (char *) msg, 0); + xfree(msg); + } + } + return NULL; +} + +//------------------------------------------------------------------------- +// RecMessageInit +//------------------------------------------------------------------------- + +int +RecMessageInit(RecModeT mode_type) +{ + + RecHandle h_pipe; + + if (g_message_initialized) { + return REC_ERR_OKAY; + } + + g_mode_type = mode_type; + + g_send_llq = create_queue(); + g_recv_llq = create_queue(); + + switch (mode_type) { + case RECM_CLIENT: + h_pipe = RecPipeConnect(Layout::get()->runtimedir, REC_PIPE_NAME); + if (h_pipe == REC_HANDLE_INVALID) { + return REC_ERR_FAIL; + } + ink_thread_create(send_thr, (void *) h_pipe); + ink_thread_create(recv_thr, (void *) h_pipe); + break; + case RECM_SERVER: + ink_thread_create(accept_thr, NULL); + break; + case RECM_NULL: + case RECM_STAND_ALONE: + default: + ink_debug_assert(!"Unexpected RecModeT type"); + break; + } + + ink_thread_create(recv_cb_thr, NULL); + + g_message_initialized = true; + + return REC_ERR_OKAY; + +} + +//------------------------------------------------------------------------- +// RecMessageSend +//------------------------------------------------------------------------- + +int +RecMessageSend(RecMessage * msg) +{ + + RecMessage *msg_cpy; + int msg_cpy_size; + + // Make a copy of the record, but truncate it to the size actually used + if (g_mode_type == RECM_CLIENT || g_mode_type == RECM_SERVER) { + msg_cpy_size = sizeof(RecMessageHdr) + (msg->o_write - msg->o_start); + msg_cpy = (RecMessage *) xmalloc(msg_cpy_size); + memcpy(msg_cpy, msg, msg_cpy_size); + msg_cpy->o_end = msg_cpy->o_write; + enqueue(g_send_llq, (void *) msg_cpy); + } + + return REC_ERR_OKAY; + +} + +//------------------------------------------------------------------------- +// +// REC_BUILD_MGMT IMPLEMENTATION +// +//------------------------------------------------------------------------- +#elif defined (REC_BUILD_MGMT) + +#if defined(LOCAL_MANAGER) +#include "LocalManager.h" +#elif defined(PROCESS_MANAGER) +#include "ProcessManager.h" +#else +#error "Required #define not specificed; expected LOCAL_MANAGER or PROCESS_MANAGER" +#endif + +//------------------------------------------------------------------------- +// RecMessageInit +//------------------------------------------------------------------------- + +int +RecMessageInit(RecModeT mode_type) +{ + if (g_message_initialized) { + return REC_ERR_OKAY; + } + g_mode_type = mode_type; +#if defined (LOCAL_MANAGER) + lmgmt->registerMgmtCallback(MGMT_SIGNAL_LIBRECORDS, RecMessageRecvThis, NULL); +#elif defined(PROCESS_MANAGER) + pmgmt->registerMgmtCallback(MGMT_EVENT_LIBRECORDS, RecMessageRecvThis, NULL); +#endif + + g_message_initialized = true; + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecMessageSend +//------------------------------------------------------------------------- + +int +RecMessageSend(RecMessage * msg) +{ + int msg_size; + + // Make a copy of the record, but truncate it to the size actually used + if (g_mode_type == RECM_CLIENT || g_mode_type == RECM_SERVER) { + msg->o_end = msg->o_write; + msg_size = sizeof(RecMessageHdr) + (msg->o_write - msg->o_start); +#if defined (LOCAL_MANAGER) + lmgmt->signalEvent(MGMT_EVENT_LIBRECORDS, (char *) msg, msg_size); +#elif defined(PROCESS_MANAGER) + pmgmt->signalManager(MGMT_SIGNAL_LIBRECORDS, (char *) msg, msg_size); +#endif + } + + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// +// STUB IMPLEMENTATION +// +//------------------------------------------------------------------------- +#elif defined (REC_BUILD_STUB) +#else +#error "Required #define not specificed; expected REC_BUILD_STAND_ALONE, REC_BUILD_MGMT, or REC_BUILD_STUB" +#endif + +//------------------------------------------------------------------------- +// RecMessageAlloc +//------------------------------------------------------------------------- +RecMessage * +RecMessageAlloc(RecMessageT msg_type, int initial_size) +{ + RecMessage *msg; + + msg = (RecMessage *) xmalloc(sizeof(RecMessageHdr) + initial_size); + memset(msg, 0, sizeof(RecMessageHdr) + initial_size); + msg->msg_type = msg_type; + msg->o_start = sizeof(RecMessageHdr); + msg->o_write = sizeof(RecMessageHdr); + msg->o_end = sizeof(RecMessageHdr) + initial_size; + msg->entries = 0; + + return msg; +} + +//------------------------------------------------------------------------- +// RecMessageFree +//------------------------------------------------------------------------- + +int +RecMessageFree(RecMessage * msg) +{ + xfree(msg); + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecMessageMarshal_Realloc +//------------------------------------------------------------------------- +RecMessage * +RecMessageMarshal_Realloc(RecMessage * msg, const RecRecord * record) +{ + int msg_ele_size; + int rec_name_len = -1; + int rec_data_str_len = -1; + int rec_data_def_str_len = -1; + int rec_cfg_chk_len = -1; + RecMessageEleHdr *ele_hdr; + RecRecord *r; + char *p; + + // find out how much space we need + msg_ele_size = sizeof(RecMessageEleHdr) + sizeof(RecRecord); + if (record->name) { + rec_name_len = strlen(record->name) + 1; + msg_ele_size += rec_name_len; + } + if (record->data_type == RECD_STRING) { + if (record->data.rec_string) { + rec_data_str_len = strlen(record->data.rec_string) + 1; + msg_ele_size += rec_data_str_len; + } + if (record->data_default.rec_string) { + rec_data_def_str_len = strlen(record->data_default.rec_string) + 1; + msg_ele_size += rec_data_def_str_len; + } + } + if (REC_TYPE_IS_CONFIG(record->rec_type) && (record->config_meta.check_expr)) { + rec_cfg_chk_len = strlen(record->config_meta.check_expr) + 1; + msg_ele_size += rec_cfg_chk_len; + } + // XXX: this is NOT 8 byte alignment + // msg_ele_size = 5; + // (msg_ele_size + 7) & ~7 == 5 !!! + // msg_ele_size = (msg_ele_size + 7) & ~7; // 8 byte alignmenet + + msg_ele_size = INK_ALIGN_DEFAULT(msg_ele_size); // 8 byte alignmenet + // get some space in our buffer + while (msg->o_end - msg->o_write < msg_ele_size) { + int realloc_size = (msg->o_end - msg->o_start) * 2; + msg = (RecMessage *) xrealloc(msg, sizeof(RecMessageHdr) + realloc_size); + msg->o_end = msg->o_start + realloc_size; + } + ele_hdr = (RecMessageEleHdr *) ((char *) msg + msg->o_write); + // The following memset() is pretty CPU intensive, replacing it with something + // like the below would reduce CPU usage a fair amount. /leif. + // *((char*)msg + msg->o_write) = 0; + memset((char *) msg + msg->o_write, 0, msg->o_end - msg->o_write); + msg->o_write += msg_ele_size; + + // store the record + ele_hdr->magic = REC_MESSAGE_ELE_MAGIC; + ele_hdr->o_next = msg->o_write; + p = (char *) ele_hdr + sizeof(RecMessageEleHdr); + memcpy(p, record, sizeof(RecRecord)); + r = (RecRecord *) p; + p += sizeof(RecRecord); + if (rec_name_len != -1) { + ink_assert((msg->o_end - ((uintptr_t) p - (uintptr_t) msg)) >= (uintptr_t) rec_name_len); + memcpy(p, record->name, rec_name_len); + r->name = (char *) ((uintptr_t) p - (uintptr_t) r); + p += rec_name_len; + } + if (rec_data_str_len != -1) { + ink_assert((msg->o_end - ((uintptr_t) p - (uintptr_t) msg)) >= (uintptr_t) rec_data_str_len); + memcpy(p, record->data.rec_string, rec_data_str_len); + r->data.rec_string = (char *) ((uintptr_t) p - (uintptr_t) r); + p += rec_data_str_len; + } + if (rec_data_def_str_len != -1) { + ink_assert((msg->o_end - ((uintptr_t) p - (uintptr_t) msg)) >= (uintptr_t) rec_data_def_str_len); + memcpy(p, record->data_default.rec_string, rec_data_def_str_len); + r->data_default.rec_string = (char *) ((uintptr_t) p - (uintptr_t) r); + p += rec_data_def_str_len; + } + if (rec_cfg_chk_len != -1) { + ink_assert((msg->o_end - ((uintptr_t) p - (uintptr_t) msg)) >= (uintptr_t) rec_cfg_chk_len); + memcpy(p, record->config_meta.check_expr, rec_cfg_chk_len); + r->config_meta.check_expr = (char *) ((uintptr_t) p - (uintptr_t) r); + p += rec_cfg_chk_len; + } + + msg->entries += 1; + + return msg; +} + +//------------------------------------------------------------------------- +// RecMessageUnmarshalFirst +//------------------------------------------------------------------------- + +int +RecMessageUnmarshalFirst(RecMessage * msg, RecMessageItr * itr, RecRecord ** record) +{ + itr->ele_hdr = (RecMessageEleHdr *) ((char *) msg + msg->o_start); + itr->next = 1; + + return RecMessageUnmarshalNext(msg, NULL, record); +} + +//------------------------------------------------------------------------- +// RecMessageUnmarshalNext +//------------------------------------------------------------------------- + +int +RecMessageUnmarshalNext(RecMessage * msg, RecMessageItr * itr, RecRecord ** record) +{ + RecMessageEleHdr *eh; + RecRecord *r; + + if (itr == NULL) { + if (msg->entries == 0) { + return REC_ERR_FAIL; + } else { + eh = (RecMessageEleHdr *) ((char *) msg + msg->o_start); + } + } else { + if (itr->next >= msg->entries) { + return REC_ERR_FAIL; + } + itr->ele_hdr = (RecMessageEleHdr *) ((char *) (msg) + itr->ele_hdr->o_next); + itr->next += 1; + eh = itr->ele_hdr; + } + + ink_debug_assert(eh->magic == REC_MESSAGE_ELE_MAGIC); + + // If the file is corrupt, ignore the the rest of the file. + if (eh->magic != REC_MESSAGE_ELE_MAGIC) { + Warning("Persistent statistics file records.stat is corrupted. Ignoring the rest of the file\n"); + return REC_ERR_FAIL; + } + + r = (RecRecord *) ((char *) eh + sizeof(RecMessageEleHdr)); + + if (r->name) { + r->name = (char *) r + (intptr_t) (r->name); + } + if (r->data_type == RECD_STRING) { + if (r->data.rec_string) { + r->data.rec_string = (char *) r + (intptr_t) (r->data.rec_string); + } + if (r->data_default.rec_string) { + r->data_default.rec_string = (char *) r + (intptr_t) (r->data_default.rec_string); + } + } + if (REC_TYPE_IS_CONFIG(r->rec_type) && (r->config_meta.check_expr)) { + r->config_meta.check_expr = (char *) r + (intptr_t) (r->config_meta.check_expr); + } + + *record = r; + + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecMessageRegisterRecvCb +//------------------------------------------------------------------------- + +int +RecMessageRegisterRecvCb(RecMessageRecvCb recv_cb, void *cookie) +{ + if (g_recv_cb) { + return REC_ERR_FAIL; + } + g_recv_cookie = cookie; + g_recv_cb = recv_cb; + + return REC_ERR_OKAY; +} + +//------------------------------------------------------------------------- +// RecMessageRecvThis +//------------------------------------------------------------------------- + +void * +RecMessageRecvThis(void *cookie, char *data_raw, int data_len) +{ + REC_NOWARN_UNUSED(cookie); + REC_NOWARN_UNUSED(data_len); + RecMessage *msg = (RecMessage *) data_raw; + g_recv_cb(msg, msg->msg_type, g_recv_cookie); + return NULL; +} + +//------------------------------------------------------------------------- +// RecMessageReadFromDisk +//------------------------------------------------------------------------- + +RecMessage * +RecMessageReadFromDisk(const char *fpath) +{ + RecMessageHdr msg_hdr; + RecMessage *msg = NULL; + RecHandle h_file; + int bytes_read; + + if ((h_file = RecFileOpenR(fpath)) == REC_HANDLE_INVALID) { + goto Lerror; + } + if (RecFileRead(h_file, (char *) (&msg_hdr), sizeof(RecMessageHdr), &bytes_read) == REC_ERR_FAIL) { + goto Lerror; + } + msg = (RecMessage *) xmalloc((msg_hdr.o_end - msg_hdr.o_start) + sizeof(RecMessageHdr)); + memcpy(msg, &msg_hdr, sizeof(RecMessageHdr)); + if (RecFileRead(h_file, (char *) (msg) + msg_hdr.o_start, + msg_hdr.o_end - msg_hdr.o_start, &bytes_read) == REC_ERR_FAIL) { + goto Lerror; + } + + goto Ldone; + +Lerror: + if (msg != NULL) { + xfree(msg); + msg = NULL; + } + +Ldone: + if (h_file != REC_HANDLE_INVALID) { + RecFileClose(h_file); + } + + return msg; +} + +//------------------------------------------------------------------------- +// RecMessageWriteToDisk +//------------------------------------------------------------------------- + +int +RecMessageWriteToDisk(RecMessage *msg, const char *fpath) +{ + int msg_size; + RecHandle h_file; + int bytes_written; + + // Cap the message (e.g. when we read it, o_end should reflect the + // size of the new buffer that we write to disk, not the size of the + // buffer in memory). + msg->o_end = msg->o_write; + + msg_size = sizeof(RecMessageHdr) + (msg->o_write - msg->o_start); + if ((h_file = RecFileOpenW(fpath)) != REC_HANDLE_INVALID) { + if (RecFileWrite(h_file, (char *) msg, msg_size, &bytes_written) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + RecFileClose(h_file); + } + + return REC_ERR_OKAY; +} + +// +// [hack for tsunami, bevans] -- I need this exported to the ACC module somehow, +// the acc module can't include stuff out put proxy/ or mgmt/ +// +int +RecAlarmSignal(int code, const char *msg, int msg_size) +{ +#if defined (LOCAL_MANAGER) + lmgmt->signalEvent(code, (char *) msg, msg_size); +#elif defined(PROCESS_MANAGER) + pmgmt->signalManager(code, (char *) msg, msg_size); +#else + REC_NOWARN_UNUSED(code); + REC_NOWARN_UNUSED(msg); + REC_NOWARN_UNUSED(msg_size); +#endif + + return REC_ERR_OKAY; +} diff --git a/lib/records/RecMutex.cc b/lib/records/RecMutex.cc new file mode 100644 index 00000000..888c96c8 --- /dev/null +++ b/lib/records/RecMutex.cc @@ -0,0 +1,65 @@ +/** @file + + RecMutex definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_config.h" +#include "I_RecMutex.h" + +int +rec_mutex_init(RecMutex * m, const char *name) +{ + m->nthread_holding = 0; + m->thread_holding = 0; + return ink_mutex_init(&(m->the_mutex), name); +} + +int +rec_mutex_acquire(RecMutex * m) +{ + + ink_thread this_thread = ink_thread_self(); + + if (m->thread_holding != this_thread) { + ink_mutex_acquire(&(m->the_mutex)); + m->thread_holding = this_thread; + } + + m->nthread_holding++; + return 0; + +} + +int +rec_mutex_release(RecMutex * m) +{ + + if (m->nthread_holding != 0) { + m->nthread_holding--; + if (m->nthread_holding == 0) { + m->thread_holding = 0; + ink_mutex_release(&(m->the_mutex)); + } + } + + return 0; + +} diff --git a/lib/records/RecProcess.cc b/lib/records/RecProcess.cc new file mode 100644 index 00000000..43910a0d --- /dev/null +++ b/lib/records/RecProcess.cc @@ -0,0 +1,771 @@ +/** @file + + Record process definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#include "P_EventSystem.h" +#include "P_RecCore.h" +#include "P_RecProcess.h" +#include "P_RecMessage.h" +#include "P_RecUtils.h" + +static bool g_initialized = false; +static bool g_message_initialized = false; +static bool g_started = false; +static ink_cond g_force_req_cond; +static ink_mutex g_force_req_mutex; +static RecModeT g_mode_type = RECM_NULL; + +#define REC_PROCESS +#include "P_RecCore.i" +#undef REC_PROCESS + + +//------------------------------------------------------------------------- +// raw_stat_get_total +//------------------------------------------------------------------------- +static int +raw_stat_get_total(RecRawStatBlock *rsb, int id, RecRawStat *total) +{ + int i; + RecRawStat *tlp; + + total->sum = 0; + total->count = 0; + + // get global values + total->sum = rsb->global[id]->sum; + total->count = rsb->global[id]->count; + + // get thread local values + for (i = 0; i < eventProcessor.n_ethreads; i++) { + tlp = ((RecRawStat *) ((char *) (eventProcessor.all_ethreads[i]) + rsb->ethr_stat_offset)) + id; + total->sum += tlp->sum; + total->count += tlp->count; + } + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// raw_stat_sync_to_global +//------------------------------------------------------------------------- +static int +raw_stat_sync_to_global(RecRawStatBlock *rsb, int id) +{ + int i; + RecRawStat *tlp; + RecRawStat total; + + total.sum = 0; + total.count = 0; + + // sum the thread local values + for (i = 0; i < eventProcessor.n_ethreads; i++) { + tlp = ((RecRawStat *) ((char *) (eventProcessor.all_ethreads[i]) + rsb->ethr_stat_offset)) + id; + total.sum += tlp->sum; + total.count += tlp->count; + } + + // lock so the setting of the globals and last values are atomic + ink_mutex_acquire(&(rsb->mutex)); + + // get the delta from the last sync + RecRawStat delta; + delta.sum = total.sum - rsb->global[id]->last_sum; + delta.count = total.count - rsb->global[id]->last_count; + + // This is too verbose now, so leaving it out / leif + //Debug("stats", "raw_stat_sync_to_global(): rsb pointer:%p id:%d delta:%" PRId64 " total:%" PRId64 " last:%" PRId64 " global:%" PRId64 "\n", + //rsb, id, delta.sum, total.sum, rsb->global[id]->last_sum, rsb->global[id]->sum); + + // increment the global values by the delta + ink_atomic_increment64(&(rsb->global[id]->sum), delta.sum); + ink_atomic_increment64(&(rsb->global[id]->count), delta.count); + + // set the new totals as the last values seen + ink_atomic_swap64(&(rsb->global[id]->last_sum), total.sum); + ink_atomic_swap64(&(rsb->global[id]->last_count), total.count); + + ink_mutex_release(&(rsb->mutex)); + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// raw_stat_clear_sum +//------------------------------------------------------------------------- +static int +raw_stat_clear_sum(RecRawStatBlock *rsb, int id) +{ + Debug("stats", "raw_stat_clear_sum(): rsb pointer:%p id:%d\n", rsb, id); + + // the globals need to be reset too + // lock so the setting of the globals and last values are atomic + ink_mutex_acquire(&(rsb->mutex)); + ink_atomic_swap64(&(rsb->global[id]->sum), 0); + ink_atomic_swap64(&(rsb->global[id]->last_sum), 0); + ink_mutex_release(&(rsb->mutex)); + + // reset the local stats + RecRawStat *tlp; + for (int i = 0; i < eventProcessor.n_ethreads; i++) { + tlp = ((RecRawStat *) ((char *) (eventProcessor.all_ethreads[i]) + rsb->ethr_stat_offset)) + id; + ink_atomic_swap64(&(tlp->sum), 0); + } + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// raw_stat_clear_count +//------------------------------------------------------------------------- +static int +raw_stat_clear_count(RecRawStatBlock *rsb, int id) +{ + Debug("stats", "raw_stat_clear_count(): rsb pointer:%p id:%d\n", rsb, id); + + // the globals need to be reset too + // lock so the setting of the globals and last values are atomic + ink_mutex_acquire(&(rsb->mutex)); + ink_atomic_swap64(&(rsb->global[id]->count), 0); + ink_atomic_swap64(&(rsb->global[id]->last_count), 0); + ink_mutex_release(&(rsb->mutex)); + + // reset the local stats + RecRawStat *tlp; + for (int i = 0; i < eventProcessor.n_ethreads; i++) { + tlp = ((RecRawStat *) ((char *) (eventProcessor.all_ethreads[i]) + rsb->ethr_stat_offset)) + id; + ink_atomic_swap64(&(tlp->count), 0); + } + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// recv_message_cb__process +//------------------------------------------------------------------------- +static int +recv_message_cb__process(RecMessage *msg, RecMessageT msg_type, void *cookie) +{ + int err; + + if ((err = recv_message_cb(msg, msg_type, cookie)) == REC_ERR_OKAY) { + if (msg_type == RECG_PULL_ACK) { + ink_mutex_acquire(&g_force_req_mutex); + ink_cond_signal(&g_force_req_cond); + ink_mutex_release(&g_force_req_mutex); + } + } + return err; +} + + +//------------------------------------------------------------------------- +// raw_stat_sync_cont +//------------------------------------------------------------------------- +struct raw_stat_sync_cont: public Continuation +{ + raw_stat_sync_cont(ProxyMutex *m) + : Continuation(m) + { + SET_HANDLER(&raw_stat_sync_cont::exec_callbacks); + } + + int exec_callbacks(int event, Event *e) + { + REC_NOWARN_UNUSED(event); + REC_NOWARN_UNUSED(e); + while (true) { + RecExecRawStatSyncCbs(); + Debug("statsproc", "raw_stat_sync_cont() processed"); + sleep(REC_RAW_STAT_SYNC_INTERVAL_SEC); + } + return EVENT_DONE; + } +}; + + +//------------------------------------------------------------------------- +// config_update_cont +//------------------------------------------------------------------------- +struct config_update_cont: public Continuation +{ + config_update_cont(ProxyMutex *m) + : Continuation(m) + { + SET_HANDLER(&config_update_cont::exec_callbacks); + } + + int exec_callbacks(int event, Event *e) + { + REC_NOWARN_UNUSED(event); + REC_NOWARN_UNUSED(e); + while (true) { + RecExecConfigUpdateCbs(); + Debug("statsproc", "config_update_cont() processed"); + sleep(REC_CONFIG_UPDATE_INTERVAL_SEC); + } + return EVENT_DONE; + } +}; + + +//------------------------------------------------------------------------- +// sync_cont +//------------------------------------------------------------------------- +struct sync_cont: public Continuation +{ + textBuffer *m_tb; + + sync_cont(ProxyMutex *m) + : Continuation(m) + { + SET_HANDLER(&sync_cont::sync); + m_tb = NEW(new textBuffer(65536)); + } + + ~sync_cont() + { + if (m_tb != NULL) { + delete m_tb; + m_tb = NULL; + } + } + + int sync(int event, Event *e) + { + REC_NOWARN_UNUSED(event); + REC_NOWARN_UNUSED(e); + while (true) { + send_push_message(); + RecSyncStatsFile(); + if (RecSyncConfigToTB(m_tb) == REC_ERR_OKAY) { + int nbytes; + RecDebug(DL_Note, "Writing '%s'", g_rec_config_fpath); + RecHandle h_file = RecFileOpenW(g_rec_config_fpath); + RecFileWrite(h_file, m_tb->bufPtr(), m_tb->spaceUsed(), &nbytes); + RecFileClose(h_file); + } + Debug("statsproc", "sync_cont() processed"); + sleep(REC_REMOTE_SYNC_INTERVAL_SEC); + } + return EVENT_DONE; + } +}; + + +//------------------------------------------------------------------------- +// RecProcessInit +//------------------------------------------------------------------------- +int +RecProcessInit(RecModeT mode_type, Diags *_diags) +{ + if (g_initialized) { + return REC_ERR_OKAY; + } + + g_mode_type = mode_type; + + if (RecCoreInit(mode_type, _diags) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + + /* -- defer RecMessageInit() until ProcessManager is initialized and + * started + if (RecMessageInit(mode_type) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + + if (RecMessageRegisterRecvCb(recv_message_cb__process, NULL)) { + return REC_ERR_FAIL; + } + + ink_cond_init(&g_force_req_cond); + ink_mutex_init(&g_force_req_mutex, NULL); + if (mode_type == RECM_CLIENT) { + send_pull_message(RECG_PULL_REQ); + ink_cond_wait(&g_force_req_cond, &g_force_req_mutex); + ink_mutex_release(&g_force_req_mutex); + } + */ + + g_initialized = true; + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecProcessInitMessage +//------------------------------------------------------------------------- +int +RecProcessInitMessage(RecModeT mode_type) +{ + if (g_message_initialized) { + return REC_ERR_OKAY; + } + + if (RecMessageInit(mode_type) == REC_ERR_FAIL) { + return REC_ERR_FAIL; + } + + if (RecMessageRegisterRecvCb(recv_message_cb__process, NULL)) { + return REC_ERR_FAIL; + } + + ink_cond_init(&g_force_req_cond); + ink_mutex_init(&g_force_req_mutex, NULL); + if (mode_type == RECM_CLIENT) { + send_pull_message(RECG_PULL_REQ); + ink_mutex_acquire(&g_force_req_mutex); + ink_cond_wait(&g_force_req_cond, &g_force_req_mutex); + ink_mutex_release(&g_force_req_mutex); + } + + g_message_initialized = true; + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecProcessStart +//------------------------------------------------------------------------- +int +RecProcessStart() +{ + if (g_started) { + return REC_ERR_OKAY; + } + + Debug("statsproc", "Starting sync processors:"); + raw_stat_sync_cont *rssc = NEW(new raw_stat_sync_cont(new_ProxyMutex())); + Debug("statsproc", "\traw-stat syncer"); + eventProcessor.spawn_thread(rssc, "[STAT_SYNC]"); + + config_update_cont *cuc = NEW(new config_update_cont(new_ProxyMutex())); + Debug("statsproc", "\tconfig syncer"); + eventProcessor.spawn_thread(cuc, "[CONF_SYNC]"); + + sync_cont *sc = NEW(new sync_cont(new_ProxyMutex())); + Debug("statsproc", "\tremote syncer"); + eventProcessor.spawn_thread(sc, "[REM_SYNC]"); + + g_started = true; + + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecAllocateRawStatBlock +//------------------------------------------------------------------------- +RecRawStatBlock * +RecAllocateRawStatBlock(int num_stats) +{ + off_t ethr_stat_offset; + RecRawStatBlock *rsb; + + // allocate thread-local raw-stat memory + if ((ethr_stat_offset = eventProcessor.allocate(num_stats * sizeof(RecRawStat))) == -1) { + return NULL; + } + // create the raw-stat-block structure + rsb = (RecRawStatBlock *) xmalloc(sizeof(RecRawStatBlock)); + memset(rsb, 0, sizeof(RecRawStatBlock)); + rsb->ethr_stat_offset = ethr_stat_offset; + rsb->global = (RecRawStat **) xmalloc(num_stats * sizeof(RecRawStat *)); + memset(rsb->global, 0, num_stats * sizeof(RecRawStat *)); + rsb->num_stats = 0; + rsb->max_stats = num_stats; + ink_mutex_init(&(rsb->mutex),"net stat mutex"); + return rsb; +} + + +//------------------------------------------------------------------------- +// RecRegisterRawStat +//------------------------------------------------------------------------- +int +RecRegisterRawStat(RecRawStatBlock *rsb, RecT rec_type, const char *name, RecDataT data_type, RecPersistT persist_type, int id, + RecRawStatSyncCb sync_cb) +{ + Debug("stats", "RecRawStatSyncCb(%s): rsb pointer:%p id:%d\n", name, rsb, id); + + // check to see if we're good to proceed + ink_debug_assert(id < rsb->max_stats); + + int err = REC_ERR_OKAY; + + RecRecord *r; + RecData data_default; + memset(&data_default, 0, sizeof(RecData)); + + // register the record + if ((r = RecRegisterStat(rec_type, name, data_type, data_default, persist_type)) == NULL) { + err = REC_ERR_FAIL; + goto Ldone; + } + r->rsb_id = id; // This is the index within the RSB raw block for this stat, used for lookups by name. + if (i_am_the_record_owner(r->rec_type)) { + r->sync_required = r->sync_required | REC_PEER_SYNC_REQUIRED; + } else { + send_register_message(r); + } + + // store a pointer to our record->stat_meta.data_raw in our rsb + rsb->global[id] = &(r->stat_meta.data_raw); + rsb->global[id]->last_sum = 0; + rsb->global[id]->last_count = 0; + + // setup the periodic sync callback + RecRegisterRawStatSyncCb(name, sync_cb, rsb, id); + +Ldone: + return err; +} + + +//------------------------------------------------------------------------- +// RecRawStatSync... +//------------------------------------------------------------------------- + +// Note: On these RecRawStatSync callbacks, our 'data' is protected +// under its lock by the caller, so no need to worry! +int +RecRawStatSyncSum(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + REC_NOWARN_UNUSED(name); + RecRawStat total; + + Debug("stats", "raw sync:sum for %s", name); + raw_stat_sync_to_global(rsb, id); + total.sum = rsb->global[id]->sum; + total.count = rsb->global[id]->count; + RecDataSetFromInk64(data_type, data, total.sum); + + return REC_ERR_OKAY; +} + +int +RecRawStatSyncCount(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + REC_NOWARN_UNUSED(name); + RecRawStat total; + + Debug("stats", "raw sync:count for %s", name); + raw_stat_sync_to_global(rsb, id); + total.sum = rsb->global[id]->sum; + total.count = rsb->global[id]->count; + RecDataSetFromInk64(data_type, data, total.count); + + return REC_ERR_OKAY; +} + +int +RecRawStatSyncAvg(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + REC_NOWARN_UNUSED(name); + RecRawStat total; + RecFloat avg = 0.0f; + + Debug("stats", "raw sync:avg for %s", name); + raw_stat_sync_to_global(rsb, id); + total.sum = rsb->global[id]->sum; + total.count = rsb->global[id]->count; + if (total.count != 0) + avg = (float) ((double) total.sum / (double) total.count); + RecDataSetFromFloat(data_type, data, avg); + return REC_ERR_OKAY; +} + +int +RecRawStatSyncHrTimeAvg(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + REC_NOWARN_UNUSED(name); + RecRawStat total; + RecFloat r; + + Debug("stats", "raw sync:hr-timeavg for %s", name); + raw_stat_sync_to_global(rsb, id); + total.sum = rsb->global[id]->sum; + total.count = rsb->global[id]->count; + if (total.count == 0) { + r = 0.0f; + } else { + r = (float) ((double) total.sum / (double) total.count); + r = r / (float) (HRTIME_SECOND); + } + RecDataSetFromFloat(data_type, data, r); + return REC_ERR_OKAY; +} + +int +RecRawStatSyncIntMsecsToFloatSeconds(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + REC_NOWARN_UNUSED(name); + RecRawStat total; + RecFloat r; + + Debug("stats", "raw sync:seconds for %s", name); + raw_stat_sync_to_global(rsb, id); + total.sum = rsb->global[id]->sum; + total.count = rsb->global[id]->count; + if (total.count == 0) { + r = 0.0f; + } else { + r = (float) ((double) total.sum / 1000); + } + RecDataSetFromFloat(data_type, data, r); + return REC_ERR_OKAY; +} + +int +RecRawStatSyncMHrTimeAvg(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock *rsb, int id) +{ + REC_NOWARN_UNUSED(name); + RecRawStat total; + RecFloat r; + + Debug("stats", "raw sync:mhr-timeavg for %s", name); + raw_stat_sync_to_global(rsb, id); + total.sum = rsb->global[id]->sum; + total.count = rsb->global[id]->count; + if (total.count == 0) { + r = 0.0f; + } else { + r = (float) ((double) total.sum / (double) total.count); + r = r / (float) (HRTIME_MSECOND); + } + RecDataSetFromFloat(data_type, data, r); + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecIncrRawStatXXX +//------------------------------------------------------------------------- +int +RecIncrRawStatBlock(RecRawStatBlock *rsb, EThread *ethread, RecRawStat *stat_array) +{ + REC_NOWARN_UNUSED(rsb); + REC_NOWARN_UNUSED(ethread); + REC_NOWARN_UNUSED(stat_array); + return REC_ERR_FAIL; +} + + +//------------------------------------------------------------------------- +// RecSetRawStatXXX +//------------------------------------------------------------------------- +int +RecSetRawStatSum(RecRawStatBlock *rsb, int id, int64_t data) +{ + raw_stat_clear_sum(rsb, id); + ink_atomic_swap64(&(rsb->global[id]->sum), data); + return REC_ERR_OKAY; +} + +int +RecSetRawStatCount(RecRawStatBlock *rsb, int id, int64_t data) +{ + raw_stat_clear_count(rsb, id); + ink_atomic_swap64(&(rsb->global[id]->count), data); + return REC_ERR_OKAY; +} + +int +RecSetRawStatBlock(RecRawStatBlock *rsb, RecRawStat *stat_array) +{ + REC_NOWARN_UNUSED(rsb); + REC_NOWARN_UNUSED(stat_array); + return REC_ERR_FAIL; +} + + +//------------------------------------------------------------------------- +// RecGetRawStatXXX +//------------------------------------------------------------------------- + +int +RecGetRawStatSum(RecRawStatBlock *rsb, int id, int64_t *data) +{ + RecRawStat total; + + raw_stat_get_total(rsb, id, &total); + *data = total.sum; + return REC_ERR_OKAY; +} + +int +RecGetRawStatCount(RecRawStatBlock *rsb, int id, int64_t *data) +{ + RecRawStat total; + + raw_stat_get_total(rsb, id, &total); + *data = total.count; + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecIncrGlobalRawStatXXX +//------------------------------------------------------------------------- +int +RecIncrGlobalRawStat(RecRawStatBlock *rsb, int id, int64_t incr) +{ + ink_atomic_increment64(&(rsb->global[id]->sum), incr); + ink_atomic_increment64(&(rsb->global[id]->count), 1); + return REC_ERR_OKAY; +} + +int +RecIncrGlobalRawStatSum(RecRawStatBlock *rsb, int id, int64_t incr) +{ + ink_atomic_increment64(&(rsb->global[id]->sum), incr); + return REC_ERR_OKAY; +} + +int +RecIncrGlobalRawStatCount(RecRawStatBlock *rsb, int id, int64_t incr) +{ + ink_atomic_increment64(&(rsb->global[id]->count), incr); + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecSetGlobalRawStatXXX +//------------------------------------------------------------------------- +int +RecSetGlobalRawStatSum(RecRawStatBlock *rsb, int id, int64_t data) +{ + ink_atomic_swap64(&(rsb->global[id]->sum), data); + return REC_ERR_OKAY; +} + +int +RecSetGlobalRawStatCount(RecRawStatBlock *rsb, int id, int64_t data) +{ + ink_atomic_swap64(&(rsb->global[id]->count), data); + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RecGetGlobalRawStatXXX +//------------------------------------------------------------------------- +int +RecGetGlobalRawStatSum(RecRawStatBlock *rsb, int id, int64_t *data) +{ + *data = rsb->global[id]->sum; + return REC_ERR_OKAY; +} + +int +RecGetGlobalRawStatCount(RecRawStatBlock *rsb, int id, int64_t *data) +{ + *data = rsb->global[id]->count; + return REC_ERR_OKAY; +} + + +//------------------------------------------------------------------------- +// RegGetGlobalRawStatXXXPtr +//------------------------------------------------------------------------- +RecRawStat * +RecGetGlobalRawStatPtr(RecRawStatBlock *rsb, int id) +{ + return rsb->global[id]; +} + +int64_t * +RecGetGlobalRawStatSumPtr(RecRawStatBlock *rsb, int id) +{ + return &(rsb->global[id]->sum); +} + +int64_t * +RecGetGlobalRawStatCountPtr(RecRawStatBlock *rsb, int id) +{ + return &(rsb->global[id]->count); +} + + +//------------------------------------------------------------------------- +// RecRegisterRawStatSyncCb +//------------------------------------------------------------------------- +int +RecRegisterRawStatSyncCb(const char *name, RecRawStatSyncCb sync_cb, RecRawStatBlock *rsb, int id) +{ + int err = REC_ERR_FAIL; + RecRecord *r; + + ink_rwlock_rdlock(&g_records_rwlock); + if (ink_hash_table_lookup(g_records_ht, name, (void **) &r)) { + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_STAT(r->rec_type)) { + if (!(r->stat_meta.sync_cb)) { + r->stat_meta.sync_rsb = rsb; + r->stat_meta.sync_id = id; + r->stat_meta.sync_cb = sync_cb; + err = REC_ERR_OKAY; + } else { + ink_release_assert(false); // We shouldn't register CBs twice... + } + } + rec_mutex_release(&(r->lock)); + } + ink_rwlock_unlock(&g_records_rwlock); + + return err; +} + + +//------------------------------------------------------------------------- +// RecExecRawStatSyncCbs +//------------------------------------------------------------------------- +int +RecExecRawStatSyncCbs() +{ + RecRecord *r; + int i, num_records; + + num_records = g_num_records; + for (i = 0; i < num_records; i++) { + r = &(g_records[i]); + rec_mutex_acquire(&(r->lock)); + if (REC_TYPE_IS_STAT(r->rec_type)) { + if (r->stat_meta.sync_cb) { + (*(r->stat_meta.sync_cb)) (r->name, r->data_type, &(r->data), r->stat_meta.sync_rsb, r->stat_meta.sync_id); + r->sync_required = REC_SYNC_REQUIRED; + } + } + rec_mutex_release(&(r->lock)); + } + + return REC_ERR_OKAY; +} diff --git a/lib/records/RecTree.cc b/lib/records/RecTree.cc new file mode 100644 index 00000000..ba6b0bbe --- /dev/null +++ b/lib/records/RecTree.cc @@ -0,0 +1,279 @@ +/** @file + + RecTree and RecTreeNode definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "P_RecTree.h" + +#define RecTreeDebug printf +bool rec_debug = false; + + +/************************************************************************* + * + * RecTreeNode + * + *************************************************************************/ +RecTreeNode::RecTreeNode(const char *t): +record_ptr(NULL), +subtree_ptr(new RecTree(this)), +var_name_ptr(NULL), +num_leaf(0) +{ + if (t) { + node_name = xstrdup(t); + } else { + node_name = xstrdup("root"); + } +} + + + +RecTreeNode::~RecTreeNode() +{ + if (node_name) { + xfree(node_name); + } +} + +/** + Print the current node's content. If this node is a leaf, that is, + the subtree_list print count is zero, print the full variable name. + +*/ +void +RecTreeNode::print() +{ + if (num_leaf == 0) { + RecTreeDebug("\t Leaf: %s\n", var_name_ptr); + } else { + subtree_ptr->print(); + RecTreeDebug("Node: %s\n", node_name); + } +} + + +/************************************************************************* + * + * RecTree + * + *************************************************************************/ +RecTree::RecTree(RecTreeNode * n) +{ + if (n == NULL) { + n = new RecTreeNode("base"); + } + this_node = n; +} + + +/************************************************************************* + * + *************************************************************************/ +void +RecTree::rec_tree_insert(const char *var_name, const char *var_name_ptr) +{ + if ((var_name == NULL) || (!strlen(var_name))) { + return; + } + + if ((var_name_ptr == NULL) || (!strlen(var_name_ptr))) { + var_name_ptr = var_name; + } + + Tokenizer targetTok("."); + targetTok.Initialize(var_name); + tok_iter_state targetTok_state; + const char *first_token = targetTok.iterFirst(&targetTok_state); + + const char *rest_token = strchr(var_name, REC_VAR_NAME_DELIMITOR); + if (rest_token) { + rest_token++; + if (rec_debug) { + RecTreeDebug("%s %s\n", first_token, rest_token); + } + } + + RecTreeNode *subtree = NULL; + + // First subtree who has the first token + for (subtree = first(); subtree; subtree = next(subtree)) { + if (!strcmp(subtree->node_name, first_token)) { + if (rec_debug) { + // RecTreeDebug("RecTree::insert() -- found subtree %s\n", first_token); + } + break; + } + } + + // no subtree has the first token + if (!subtree) { + if (rec_debug) { + RecTreeDebug("RecTree::insert() -- add subtree with %s\n", first_token); + } + subtree = new RecTreeNode((char *) first_token); + ink_assert(subtree); + m_root.enqueue(subtree); + } + + if (rest_token) { + if (rec_debug) { + RecTreeDebug("RecTree::insert() -- insert the rest %s\n", rest_token); + } + subtree->subtree_ptr->rec_tree_insert(rest_token, var_name_ptr); + } else { + subtree->var_name_ptr = var_name_ptr; + if (rec_debug) { + RecTreeDebug("RecTree:insert() -- leaf node: %s\n", subtree->var_name_ptr); + } + } + + if (this_node) { + (this_node->num_leaf)++; + } + +} + + +/************************************************************************* + * + *************************************************************************/ +void +RecTree::print() +{ + for (RecTreeNode * node = first(); node; node = next(node)) { + node->print(); + } +} + + +/************************************************************************* + * + *************************************************************************/ +RecTree * +RecTree::rec_tree_get(char *path_name) +{ + + Tokenizer targetTok("."); + targetTok.Initialize(path_name); + tok_iter_state targetTok_state; + const char *first_token = targetTok.iterFirst(&targetTok_state); + + char *rest_token = strchr(path_name, REC_VAR_NAME_DELIMITOR); + if (rest_token != NULL) { + rest_token++; + } + + RecTreeNode *subtree = NULL; + + // First subtree who has the first token + for (subtree = first(); subtree; subtree = next(subtree)) { + if (!strcmp(subtree->node_name, first_token)) { + if (rec_debug) { + RecTreeDebug("RecTree::get() -- found subtree %s\n", first_token); + } + break; + } + } + + if (!subtree) { + if (rec_debug) { + RecTreeDebug("RecTree::get() -- can't find subtree %s\n", first_token); + } + return NULL; + } else { + char wildcard[2]; + memset(wildcard, 0, 2); + snprintf(wildcard, sizeof(wildcard), "%c", REC_VAR_NAME_WILDCARD); + if (rest_token == NULL || !strcmp(rest_token, wildcard)) { + return subtree->subtree_ptr; + } else { + if (rec_debug) { + RecTreeDebug("RecTree::get() -- getting the rest %s\n", rest_token); + } + return subtree->subtree_ptr->rec_tree_get(rest_token); + } + } + +} + + +/************************************************************************* + * rec_tree_get_list + * + *************************************************************************/ +void +RecTree::rec_tree_get_list(char *path_name, char ***buf, int *count) +{ + + int i = 0; + RecTree *subtree = rec_tree_get(path_name); + + if (!subtree) { + (*count) = 0; + return; + } + + (*count) = subtree->this_node->num_leaf; + if (rec_debug) { + RecTreeDebug("RecTreeGetList subtree %s has %d leafs\n", subtree->this_node->node_name, (*count)); + } + + *buf = (char **) xmalloc(sizeof(char *) * (*count)); + for (i = 0; i < (*count); i++) { + (*buf)[i] = (char *) xmalloc(sizeof(char)); + } + + int index = 0; + subtree->p_rec_tree_get_list(path_name, &(*buf), &index); + ink_assert((*count) == index); + + if (rec_debug) { + for (i = 0; i < (*count); i++) { + RecTreeDebug("[%d] %s\n", i, (*buf)[i]); + } + } + +} + + +/** Recursive/private version of RecTreeGetList(). */ +void +RecTree::p_rec_tree_get_list(char *path_name, char ***buffer, int *index) +{ + + if (this_node->var_name_ptr) { + (*buffer)[(*index)] = (char*)this_node->var_name_ptr; + if (rec_debug) { + RecTreeDebug("%d %s\n", (*index), (*buffer)[(*index)]); + } + (*index)++; + } + + for (RecTreeNode * subtree = first(); subtree; subtree = next(subtree)) { + if (rec_debug) { + RecTreeDebug("current node: %s, subtree node: %s\n", this_node->node_name, subtree->node_name); + } + subtree->subtree_ptr->p_rec_tree_get_list(&(*path_name), &(*buffer), &(*index)); + } + +} diff --git a/lib/records/RecUtils.cc b/lib/records/RecUtils.cc new file mode 100644 index 00000000..06542737 --- /dev/null +++ b/lib/records/RecUtils.cc @@ -0,0 +1,266 @@ +/** @file + + Record utils definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "P_RecUtils.h" +#include "P_RecCore.h" +#include "P_RecTree.h" + +// diags defined in RecCore.cc +extern Diags *g_diags; + +//------------------------------------------------------------------------- +// RecAlloc +//------------------------------------------------------------------------- +RecRecord* +RecAlloc(RecT rec_type, const char *name, RecDataT data_type) +{ + if (g_num_records >= REC_MAX_RECORDS) { + Warning("too many stats/configs, please increase REC_MAX_RECORDS or rebuild with --with_max_api_stats="); + return NULL; + } + + int i = ink_atomic_increment(&g_num_records, 1); + RecRecord *r = &(g_records[i]); + // Note: record should already be memset to 0 from RecCoreInit() + r->rec_type = rec_type; + r->name = xstrdup(name); + r->order = i; + r->data_type = data_type; + rec_mutex_init(&(r->lock), NULL); + + g_records_tree->rec_tree_insert(r->name); + + return r; +} + + +//------------------------------------------------------------------------- +// RecDataClear +//------------------------------------------------------------------------- +void +RecDataClear(RecDataT data_type, RecData * data) +{ + if ((data_type == RECD_STRING) && (data->rec_string)) { + xfree(data->rec_string); + } + memset(data, 0, sizeof(RecData)); +} + + +//------------------------------------------------------------------------- +// RecDataSet +//------------------------------------------------------------------------- +bool +RecDataSet(RecDataT data_type, RecData * data_dst, RecData * data_src) +{ + bool rec_set = false; + + switch (data_type) { + case RECD_STRING: + if (data_src->rec_string == NULL) { + if (data_dst->rec_string != NULL) { + xfree(data_dst->rec_string); + data_dst->rec_string = NULL; + rec_set = true; + } + } else if (((data_dst->rec_string) && (strcmp(data_dst->rec_string, data_src->rec_string) != 0)) || + ((data_dst->rec_string == NULL) && (data_src->rec_string != NULL))) { + if (data_dst->rec_string) { + xfree(data_dst->rec_string); + } + data_dst->rec_string = xstrdup(data_src->rec_string); + rec_set = true; + } + break; + case RECD_INT: + if (data_dst->rec_int != data_src->rec_int) { + data_dst->rec_int = data_src->rec_int; + rec_set = true; + } + break; + case RECD_FLOAT: + if (data_dst->rec_float != data_src->rec_float) { + data_dst->rec_float = data_src->rec_float; + rec_set = true; + } + break; + case RECD_COUNTER: + if (data_dst->rec_counter != data_src->rec_counter) { + data_dst->rec_counter = data_src->rec_counter; + rec_set = true; + } + break; + default: + ink_assert(!"Wrong RECD type!"); + } + return rec_set; + +} + + +//------------------------------------------------------------------------- +// RecDataSetFromInk64 +//------------------------------------------------------------------------- +bool +RecDataSetFromInk64(RecDataT data_type, RecData * data_dst, int64_t data_int64) +{ + switch (data_type) { + case RECD_INT: + data_dst->rec_int = data_int64; + break; + case RECD_FLOAT: + data_dst->rec_float = (float) (data_int64); + break; + case RECD_STRING: + { + char buf[32 + 1]; + if (data_dst->rec_string) { + xfree(data_dst->rec_string); + } + snprintf(buf, 32, "%" PRId64 "", data_int64); + data_dst->rec_string = xstrdup(buf); + break; + } + case RECD_COUNTER: + data_dst->rec_counter = data_int64; + break; + default: + ink_debug_assert(!"Unexpected RecD type"); + return false; + } + + return true; +} + + +//------------------------------------------------------------------------- +// RecDataSetFromFloat +//------------------------------------------------------------------------- +bool +RecDataSetFromFloat(RecDataT data_type, RecData * data_dst, float data_float) +{ + switch (data_type) { + case RECD_INT: + data_dst->rec_int = (RecInt) data_float; + break; + case RECD_FLOAT: + data_dst->rec_float = (float) (data_float); + break; + case RECD_STRING: + { + char buf[32 + 1]; + if (data_dst->rec_string) { + xfree(data_dst->rec_string); + } + snprintf(buf, 32, "%f", data_float); + data_dst->rec_string = xstrdup(buf); + break; + } + case RECD_COUNTER: + data_dst->rec_counter = (RecCounter) data_float; + break; + default: + ink_debug_assert(!"Unexpected RecD type"); + return false; + } + + return true; +} + + +//------------------------------------------------------------------------- +// RecDataSetFromString +//------------------------------------------------------------------------- +bool +RecDataSetFromString(RecDataT data_type, RecData * data_dst, char *data_string) +{ + bool rec_set; + RecData data_src; + + switch (data_type) { + case RECD_INT: + data_src.rec_int = ink_atoi64(data_string); + break; + case RECD_FLOAT: + data_src.rec_float = atof(data_string); + break; + case RECD_STRING: + if (strcmp((data_string), "NULL") == 0) + data_src.rec_string = NULL; + else + data_src.rec_string = data_string; + break; + case RECD_COUNTER: + data_src.rec_counter = ink_atoi64(data_string); + break; + default: + ink_debug_assert(!"Unexpected RecD type"); + return false; + } + rec_set = RecDataSet(data_type, data_dst, &data_src); + + return rec_set; +} + + +//------------------------------------------------------------------------- +// RecLog +//------------------------------------------------------------------------- +void +RecLog(DiagsLevel dl, const char *format_string, ...) +{ + va_list ap; + + va_start(ap, format_string); + if (g_diags) { + g_diags->log_va(NULL, dl, NULL, NULL, format_string, ap); + } + va_end(ap); +} + + +//------------------------------------------------------------------------- +// RecDebug +//------------------------------------------------------------------------- +void +RecDebug(DiagsLevel dl, const char *format_string, ...) +{ + va_list ap; + + va_start(ap, format_string); + if (g_diags) { + g_diags->log_va("rec", dl, NULL, NULL, format_string, ap); + } + va_end(ap); +} + + +//------------------------------------------------------------------------- +// RecDebugOff +//------------------------------------------------------------------------- +void +RecDebugOff() +{ + g_diags = NULL; +} diff --git a/lib/records/test_I_RecLocal.cc b/lib/records/test_I_RecLocal.cc new file mode 100644 index 00000000..ac3cf0f3 --- /dev/null +++ b/lib/records/test_I_RecLocal.cc @@ -0,0 +1,286 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_RecLocal.h" +#include "P_RecUtils.h" +#include "test_RecordsConfig.h" + +#include "P_RecCore.h" + +Diags *diags = NULL; +void RecDumpRecordsHt(RecT rec_type); + + +//------------------------------------------------------------------------- +// Test01: Callback Test +// +// The following test verifies that the callbacks are executed. +//------------------------------------------------------------------------- +int g_config_update_result = 0; + +int +cb_test_1a(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(data_type); + if ((cookie == (void *) 0x12345678) && (strcmp(data.rec_string, "cb_test_1__changed") == 0)) { + g_config_update_result++; + printf(" - cb_test_1(%d) name: %s, data: %s, cookie: 0x%x\n", + g_config_update_result, name, data.rec_string, cookie); + } else { + g_config_update_result = 0; + } + return REC_ERR_OKAY; +} + +int +cb_test_1b(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + return cb_test_1a(name, data_type, data, cookie); +} + +int +cb_test_2a(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data_type); + NOWARN_UNUSED(data); + NOWARN_UNUSED(cookie); + g_config_update_result = -1; + return REC_ERR_FAIL; +} + +int +cb_test_2b(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + return cb_test_2a(name, data_type, data, cookie); +} + +void +Test01() +{ + g_config_update_result = 0; + printf("\n[Test01: Callback Tests]\n"); + int failures = 0; + + printf(" [RecRegisterConfigUpdateCb]\n"); + + // Initialize variables + RecSetRecordString("proxy.config.local.cb_test_1", "cb_test_1__original"); + RecSetRecordString("proxy.config.local.cb_test_2", "cb_test_2__original"); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Register config update callbacks + RecRegisterConfigUpdateCb("proxy.config.local.cb_test_1", cb_test_1a, (void *) 0x12345678); + RecRegisterConfigUpdateCb("proxy.config.local.cb_test_1", cb_test_1b, (void *) 0x12345678); + RecRegisterConfigUpdateCb("proxy.config.local.cb_test_2", cb_test_2a, (void *) 0x87654321); + RecRegisterConfigUpdateCb("proxy.config.local.cb_test_2", cb_test_2b, (void *) 0x87654321); + + // Change proxy.config.cb_test_1 + RecSetRecordString("proxy.config.local.cb_test_1", "cb_test_1__changed"); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Check globals to make sure the right thing happened + if (g_config_update_result == 2) { + printf(" SUMMARY: PASS (%d)\n", g_config_update_result); + } else { + printf(" SUMMARY: FAIL (%d)\n", g_config_update_result); + } + +} + + +//------------------------------------------------------------------------- +// Test02: Callback (Multi-lock) Test +// +// The following test verifies we can access the variables within its own +// callbacks. When a callback is invoked, the record's mutex lock has +// already taken. If RecMutex works properly, we can still access the +// variable within its own callback. +//------------------------------------------------------------------------- +int +cb_test_3a(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(data_type); + RecString rec_result; + int rec_status = RecGetRecordString_Xmalloc(name, &rec_result); + + if ((rec_status == REC_ERR_OKAY) && + (cookie == (void *) 0x12344321) && (strcmp(rec_result, "cb_test_3__changed") == 0)) { + + ink_assert(strcmp(rec_result, data.rec_string) == 0); + + g_config_update_result++; + printf(" - cb_test_3(%d) name: %s, data: %s, cookie: 0x%x\n", g_config_update_result, name, rec_result, cookie); + } else { + g_config_update_result = 0; + } + return REC_ERR_OKAY; +} + +int +cb_test_3b(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + return cb_test_3a(name, data_type, data, cookie); +} + +void +Test02() +{ + g_config_update_result = 0; + printf("\n[Test02: Callback (Multi-lock) Test]\n"); + int failures = 0; + + printf(" [RecRegisterConfigUpdateCb]\n"); + + // Initialize variables + RecSetRecordString("proxy.config.local.cb_test_3", "cb_test_3__original"); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Register config update callbacks + RecRegisterConfigUpdateCb("proxy.config.local.cb_test_3", cb_test_3a, (void *) 0x12344321); + RecRegisterConfigUpdateCb("proxy.config.local.cb_test_3", cb_test_3b, (void *) 0x12344321); + + // Change proxy.config.cb_test_1 + RecSetRecordString("proxy.config.local.cb_test_3", "cb_test_3__changed"); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Check globals to make sure the right thing happened + if (g_config_update_result == 2) { + printf(" SUMMARY: PASS (%d)\n", g_config_update_result); + } else { + printf(" SUMMARY: FAIL (%d)\n", g_config_update_result); + } + +} + + +//------------------------------------------------------------------------- +// Test-3: RecTree +// +// Simply verifies the number of records in g_records is the same as the +// number of "proxy" variable reference-able by the RecTree +//------------------------------------------------------------------------- +#define SIZE_COMPARE(_a, _b) \ + RecGetRecordList("proxy."_a, &var_buf, &buf_len); \ + if (buf_len != 0) {\ + delete[] var_buf; \ + } \ + length = 0; \ + for (r=0; r 0) { + delete[]var_buf; + } + if (buf_len == length) { + printf(" - proxy.*\t\t(rec_size:%d == tree_size:%d)\n", length, buf_len); + } else { + printf(" - proxy.*\t\t(rec_size:%d != tree_size:%d)\n", length, buf_len); + g_config_update_result++; + } + + SIZE_COMPARE("plugin", RECT_PLUGIN); + SIZE_COMPARE("config", RECT_CONFIG); + SIZE_COMPARE("process", RECT_PROCESS); + SIZE_COMPARE("node", RECT_NODE); + SIZE_COMPARE("cluster", RECT_CLUSTER); + SIZE_COMPARE("local", RECT_LOCAL); + if (g_config_update_result == 0) { + printf(" SUMMARY: PASS\n"); + } else { + printf(" SUMMARY: FAIL\n"); + } + +} + + +//------------------------------------------------------------------------- +// main +//------------------------------------------------------------------------- + +int +main(int argc, char **argv) +{ + NOWARN_UNUSED(argc); + + // start diags logging + FILE *log_fp; + if ((log_fp = fopen("reclocal.log", "a+")) != NULL) { + int status = setvbuf(log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(log_fp); + log_fp = NULL; + } + } + diags = NEW(new Diags("rec", NULL, log_fp)); + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + diags->print(NULL, DL_Note, NULL, NULL, "Starting '%s'", argv[0]); + + // system initialization + RecLocalInit(diags); + RecLocalInitMessage(); + RecordsConfigRegister(); + RecLocalStart(); + + // test + Test01(); // Local callbacks + Test02(); // Local callbacks -- mulit-lock + Test03(); // RecTree + + while (true) { + RecDumpRecordsHt(RECT_NULL); + sleep(10); + } + + return 0; + +} diff --git a/lib/records/test_I_RecProcess.cc b/lib/records/test_I_RecProcess.cc new file mode 100644 index 00000000..ca026df0 --- /dev/null +++ b/lib/records/test_I_RecProcess.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_RecProcess.h" +#include "test_RecProcess.i" diff --git a/lib/records/test_P_RecProcess.cc b/lib/records/test_P_RecProcess.cc new file mode 100644 index 00000000..b8d65dba --- /dev/null +++ b/lib/records/test_P_RecProcess.cc @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_RecProcess.h" +#include "test_RecProcess.i" diff --git a/lib/records/test_RecProcess.i b/lib/records/test_RecProcess.i new file mode 100644 index 00000000..f7d21342 --- /dev/null +++ b/lib/records/test_RecProcess.i @@ -0,0 +1,687 @@ +/** @file + + A small test and sample program for librecprocess.a + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_hrtime.h" +#include "P_RecUtils.h" +#include "test_RecordsConfig.h" + +Diags *diags = NULL; + +void RecDumpRecordsHt(RecT rec_type); + +void +syslog_thr_init() +{ + openlog("test_I_RecProcess", LOG_PID | LOG_NDELAY | LOG_NOWAIT, LOG_USER); +} + +//------------------------------------------------------------------------- +// Test01: Parse Tests +// +// The following test just verifies that we can parse the +// 'records.config' file format correctly (e.g can we handle weird +// spacing, malformed lines, etc). The test also verifies some of the +// basic RecGetRecord functionality. +// +// Run this test with the 'test_records.config' config file. Note +// that the configs used by this test are registered in the +// 'test_RecordsConfig.cc' file. +//------------------------------------------------------------------------- + +#define PARSE_TEST_UNAVAILABLE(name, failures) \ + do { \ + RecString rec_string = 0; \ + if (RecGetRecordString_Xmalloc("proxy.config.parse_"name, &rec_string) != REC_ERR_FAIL) { \ + if (rec_string) xfree(rec_string); \ + printf(" parse_"name": FAIL\n"); \ + failures++; \ + } else { \ + printf(" parse_"name": PASS\n"); \ + } \ + } while (0); + +#define PARSE_TEST_COMPARE(name, value, failures) \ + do { \ + RecString rec_string = 0; \ + if (RecGetRecordString_Xmalloc("proxy.config.parse_"name, &rec_string) == REC_ERR_OKAY) { \ + if (strcmp(rec_string, value) == 0) { \ + printf(" parse_"name": PASS\n"); \ + } else { \ + printf(" parse_"name": FAIL\n"); \ + failures++; \ + } \ + xfree(rec_string); \ + } else { \ + printf(" parse_"name": FAIL\n"); \ + failures++; \ + } \ + } while (0); + +void +Test01() +{ + printf("[Test01: Parse Tests]\n"); + int failures = 0; + + // test 1 and 1b + PARSE_TEST_UNAVAILABLE("test_1a", failures); + PARSE_TEST_UNAVAILABLE("test_1b", failures); + + // test 2, 2b, 3, 3b, 4, 4b + PARSE_TEST_COMPARE("test_2a", "X", failures); + PARSE_TEST_COMPARE("test_2b", "X", failures); + PARSE_TEST_COMPARE("test_3b", "XXX", failures); + PARSE_TEST_COMPARE("test_3b", "XXX", failures); + PARSE_TEST_COMPARE("test_4a", "XXX XXX XXX", failures); + PARSE_TEST_COMPARE("test_4b", "XXX XXX XXX", failures); + + if (failures == 0) { + printf(" SUMMARY: PASS\n"); + } else { + printf(" SUMMARY: FAIL\n"); + } + return; +} + +//------------------------------------------------------------------------- +// Test02: Config Tests +// +// The following test stresses some additional config features +// (e.g. registration of config update callbacks, config linking, and +// config setting). As with Test01, config registration must be done +// in 'test_RecordsConfig.cc'. +//------------------------------------------------------------------------- + +bool g_config_update_result = false; + +RecInt g_link_test_1 = 0; +RecFloat g_link_test_2 = 0.0f; +RecCounter g_link_test_3 = 0; + +int +cb_test_1(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(data_type); + if ((cookie == (void *) 0x12345678) && (strcmp(data.rec_string, "cb_test_1__changed") == 0)) { + printf(" - cb_test_1 (name: %s, data: %s, cookie: 0x%x\n", name, data.rec_string, cookie); + g_config_update_result = true; + } else { + g_config_update_result = false; + } + return REC_ERR_OKAY; +} + +int +cb_test_2(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data_type); + NOWARN_UNUSED(data); + NOWARN_UNUSED(cookie); + g_config_update_result = false; + return REC_ERR_FAIL; +} + +void +Test02() +{ + printf("[Test02: Config Tests]\n"); + int failures = 0; + + printf(" [RecRegisterConfigUpdateCb]\n"); + + // Initialize variables + RecSetRecordString("proxy.config.cb_test_1", "cb_test_1__original"); + RecSetRecordString("proxy.config.cb_test_2", "cb_test_2__original"); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + ink_sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Register config update callbacks + RecRegisterConfigUpdateCb("proxy.config.cb_test_1", cb_test_1, (void *) 0x12345678); + RecRegisterConfigUpdateCb("proxy.config.cb_test_2", cb_test_2, (void *) 0x87654321); + + // Change proxy.config.cb_test_1 + RecSetRecordString("proxy.config.cb_test_1", "cb_test_1__changed"); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + ink_sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Check globals to make sure the right thing happened + if (g_config_update_result == true) { + printf(" SUMMARY: PASS\n"); + } else { + printf(" SUMMARY: FAIL\n"); + } + + printf(" [RecLinkConfigXXX]\n"); + + // Set configs + RecSetRecordInt("proxy.config.link_test_1", 1); + RecSetRecordFloat("proxy.config.link_test_2", 100.0f); + RecSetRecordCounter("proxy.config.link_test_3", 5); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + ink_sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + // Link configs + RecLinkConfigInt("proxy.config.link_test_1", &g_link_test_1); + RecLinkConfigFloat("proxy.config.link_test_2", &g_link_test_2); + RecLinkConfigCounter("proxy.config.link_test_3", &g_link_test_3); + + // Initial check to make sure link worked + printf(" - g_link_test_1 = %d:%d, expect: 1\n", g_link_test_1); + printf(" - g_link_test_2 = %f, expect: %f\n", g_link_test_2, 100.0f); + printf(" - g_link_test_3 = %d:%d, expect: 5\n", g_link_test_3); + if (g_link_test_1 == 1 && g_link_test_2 == 100.0f && g_link_test_3 == 5) { + printf(" SUMMARY: PASS\n"); + } else { + printf(" SUMMARY: FAIL\n"); + } + + printf(" [RecGetRecordXXX]\n"); + failures = 0; + RecString rec_string = 0; + const int buf_len = 1024; + char buf[buf_len]; + + RecGetRecordString_Xmalloc("proxy.config.cb_test_2", &rec_string); + if (!rec_string || (rec_string && strcmp(rec_string, "cb_test_2__original")) != 0) { + printf(" RecGetRecordString_Xmalloc: FAIL (expected: 'cb_test_2__original', got: '%s')\n", + rec_string ? rec_string : ""); + } else { + printf(" RecGetRecordString_Xmalloc: PASS (%s)\n", rec_string); + } + + RecGetRecordString("proxy.config.cb_test_2", buf, buf_len); + if (strcmp(buf, "cb_test_2__original") != 0) { + printf(" RecGetRecordString: FAIL (expected: 'cb_test_2__original', got: '%s')\n", buf); + } else { + printf(" RecGetRecordString: PASS (%s)\n", buf); + } + + // Testing with RecGetRecordInt, RecGetRecordFloat and RecGetRecordCounter + RecInt rec_int = 0; + RecGetRecordInt("proxy.config.link_test_1", &rec_int); + if (rec_int != 1) { + printf(" RecGetRecordInt: FAIL (expected: 1, got %d:%d)\n", rec_int); + } else { + printf(" RecGetRecordInt: PASS (%d:%d)\n", rec_int); + } + + RecFloat rec_float = 0; + RecGetRecordFloat("proxy.config.link_test_2", &rec_float); + if (rec_float != 100.0f) { + printf(" RecGetRecordFloat: FAIL (expected: %f, got %f)\n", 100.0f, rec_float); + } else { + printf(" RecGetRecordFloat: PASS (%f)\n", rec_float); + } + + RecCounter rec_counter = 0; + RecGetRecordCounter("proxy.config.link_test_3", &rec_counter); + if (rec_counter != 5) { + printf(" RecGetRecordCounter: FAIL (expected: 5, got %d:%d)\n", rec_counter); + } else { + printf(" RecGetRecordCounter: PASS (%d:%d)\n", rec_counter); + } + + // Testing RecLinkConfigXXX, after calling RecLinkConfigXXX above, those + // variable will automatically be atomically updated when record changes in + // librecords. + printf(" [RecLinkConfigXXX]\n"); + + // Set the records + printf(" - RecSetRecordXXX\n"); + RecSetRecordString("proxy.config.cb_test_1", "cb_test_1_changed"); + RecSetRecordInt("proxy.config.link_test_1", 2); + RecSetRecordFloat("proxy.config.link_test_2", 200.0f); + RecSetRecordCounter("proxy.config.link_test_3", 6); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + ink_sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + + printf(" - g_link_test_1 = %d:%d, expect: 2\n", g_link_test_1); + printf(" - g_link_test_2 = %f, expect: %f\n", g_link_test_2, 200.0f); + printf(" - g_link_test_3 = %d:%d, expect: 6\n", g_link_test_3); + if (g_link_test_1 == 2 && g_link_test_2 == 200.0f && g_link_test_3 == 6) { + printf(" SUMMARY: PASS\n"); + } else { + printf(" SUMMARY: FAIL\n"); + } + + RecSetRecordInt("proxy.config.link_test_1", 1); + RecSetRecordFloat("proxy.config.link_test_2", 100.0f); + RecSetRecordCounter("proxy.config.link_test_3", 5); + printf(" - sleep(2*REC_CONFIG_UPDATE_INTERVAL_SEC)\n"); + ink_sleep(2 * REC_CONFIG_UPDATE_INTERVAL_SEC); + +} + +//------------------------------------------------------------------------- +// Test03: RawStat Tests +// +// The following test illustrates how one might use the RawStat +// interface to librecprocess.a. It also illustrates a custom RawStat +// sync function, 'raw_stat_sync_ticks_per_sec' that computes +// operations per second (used by AIO module). +//------------------------------------------------------------------------- + +enum my_stat_enum +{ + MY_STAT_A, + MY_STAT_B, + MY_STAT_C, + MY_STAT_D, + MY_STAT_E, + MY_STAT_F, + MY_STAT_G, + MY_STAT_COUNT +}; + +static RecRawStatBlock *g_rsb = NULL; +static int g_count = 0; + +static int g_ticks = 0; +static int g_time = 0; + +int +raw_stat_sync_ticks_per_sec(const char *name, RecDataT data_type, RecData * data, RecRawStatBlock * rsb, int id) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data_type); + + ink64 ticks_old, time_old; + ink64 ticks_new, time_new; + + RecRawStat *rrs = RecGetGlobalRawStatPtr(rsb, id); + ink64 *rrs_sum = RecGetGlobalRawStatSumPtr(rsb, id); + ink64 *rrs_count = RecGetGlobalRawStatCountPtr(rsb, id); + + RecGetGlobalRawStatSum(rsb, id, &ticks_old); + RecGetGlobalRawStatCount(rsb, id, &time_old); + + if ((rrs->sum != ticks_old) && (*rrs_sum != ticks_old)) { + printf("ERROR: (rrs->sum != ticks_old) && (*rrs_sum != ticks_old)\n"); + } + /*else { + printf("OKAY: GlobalRawStatSum == RecRawStat->sum == && GlobalRawStatSum == GlobalRawStatSumPtr, which is %d:%d\n", ticks_old); + } */ + if ((rrs->count != time_old) && (*rrs_count != time_old)) { + printf("ERROR: (rrs->count != time_old) && (*rrs_sum != ticks_old)\n"); + } + /*else { + printf("OKAY: GlobalRawStatCount == RecRawStat->count && GlobalRawStatCount == GlobalRawStatCountPtr, which is %d:%d\n", time_old); + } */ + ticks_new = g_ticks; + time_new = g_time; + + data->rec_float = (float) (ticks_new - ticks_old) / (float) (time_new - time_old); + + RecSetGlobalRawStatSum(rsb, id, ticks_new); + RecSetGlobalRawStatCount(rsb, id, time_new); + + return REC_ERR_OKAY; + +} + +struct RawStatCont:public Continuation +{ + RawStatCont(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&RawStatCont::dummy_function); + } + int dummy_function(int event, Event * e) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + printf("------------Raw Stat dump-------------\n"); + ink64 hr_start, hr_finish; + // comments out here. Why stat_a is int? + RecInt stat_b, stat_c, stat_f, stat_g; + RecFloat stat_a, stat_d, stat_e; + // comments out here + + hr_start = ink_get_hrtime(); + + // test_raw_stat_a should have around 16000 in it (avg of rand()) + RecIncrRawStat(g_rsb, mutex->thread_holding, (int) MY_STAT_A, rand()); + + // test_raw_stat_b should have g_count plustorial in it + RecIncrRawStatSum(g_rsb, mutex->thread_holding, (int) MY_STAT_B, g_count); + + // test_raw_stat_c should have g_count plustorial in it + //RecSetRawStatCount(g_rsb, (int) MY_STAT_C, g_count); + RecIncrRawStatCount(g_rsb, mutex->thread_holding, (int) MY_STAT_C, g_count); + + // test_raw_stat_f should have g_count in it + // I have switched this with test_raw_stat_c + RecSetRawStatCount(g_rsb, (int) MY_STAT_F, g_count); + + // test_raw_stat_g should have g_count in it + RecSetRawStatSum(g_rsb, (int) MY_STAT_G, g_count); + + // test_raw_stat_d should have 4 it (e.g. we're run 4 times a second) + ink_atomic_increment(&g_ticks, 1); + g_time = time(0); + + // sleep for a bit to take some time + struct timespec rgtp; + rgtp.tv_sec = 0; + rgtp.tv_nsec = 10000; + nanosleep(&rgtp, NULL); + + // FIXME: Read values and compare against expected values rather + // than just printing out + + // comments out here + RecGetRecordFloat("proxy.process.test_raw_stat_a", &stat_a); + RecGetRecordInt("proxy.process.test_raw_stat_b", &stat_b); + RecGetRecordInt("proxy.process.test_raw_stat_c", &stat_c); + RecGetRecordFloat("proxy.process.test_raw_stat_d", &stat_d); + RecGetRecordFloat("proxy.process.test_raw_stat_e", &stat_e); + RecGetRecordInt("proxy.process.test_raw_stat_f", &stat_f); + RecGetRecordInt("proxy.process.test_raw_stat_g", &stat_g); + + /* + printf("-> g_count: %d, thr: 0x%x, stat_a: %d%d, stat_b: %d:%d, stat_c: %d:%d, stat_d: %f\n", + g_count, mutex->thread_holding, stat_a, stat_b, stat_c, stat_d); + + printf("-> g_link_test_1: %d:%d, g_link_test_2: %f\n", + g_link_test_1, g_link_test_2); + */ + + // Compare read value stat_a and expected value test_raw_stat_a + RecRawStat test_raw_stat_a; + RecFloat avg = 0.0f; + test_raw_stat_a.sum = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_A]->sum)); + test_raw_stat_a.count = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_A]->count)); + if (test_raw_stat_a.count != 0) + avg = (float) ((double) test_raw_stat_a.sum / (double) test_raw_stat_a.count); + + if (stat_a != avg) { + printf("ERROR: stat_a: %f, expect stat_a: %f\n", stat_a, avg); + } else { + printf("OKAY: stat_a: %f, expect stat_a: %f\n", stat_a, avg); + } + + // Compare read value stat_b and expected value test_raw_stat_b + RecRawStat test_raw_stat_b; + test_raw_stat_b.sum = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_B]->sum)); + if (stat_b != test_raw_stat_b.sum) { + printf("ERROR: After RecIncrRawStatSum, stat_b: %d:%d, expect stat_b: %d:%d\n", stat_b, test_raw_stat_b.sum); + } else { + printf("OKAY: After RecIncrRawStatSum, stat_b: %d:%d, expect stat_b: %d:%d\n", stat_b, test_raw_stat_b.sum); + } + + // Compare read value stat_c and expected value test_raw_stat_c + RecRawStat test_raw_stat_c; + test_raw_stat_c.count = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_C]->count)); + if (stat_c != test_raw_stat_c.count) { + printf("ERROR: After RecIncrRawStatCount, stat_c: %d:%d, expect stat_c: %d:%d\n", stat_c, test_raw_stat_c.count); + } else { + printf("OKAY: After RecIncrRawStatCount, stat_c: %d:%d, expect stat_c: %d:%d\n", stat_c, test_raw_stat_c.count); + } + + // Compare read value stat_d and expected value test_raw_stat_d + ink64 ticks_old, time_old; + RecGetGlobalRawStatSum(g_rsb, MY_STAT_D, &ticks_old); + RecGetGlobalRawStatCount(g_rsb, MY_STAT_D, &time_old); + RecFloat data = (float) (g_ticks - ticks_old) / (float) (g_time - time_old); + if (stat_d != 4.0f) { + printf("ERROR: stat_d: %f, expect stat_d: %f or I got data: %f\n", stat_d, 4.0f, data); + } else { + printf("OKAY: stat_d: %f, expect stat_d: %f or I got data: %f\n", stat_d, 4.0f, data); + } + + // Compare read value stat_e and expected value test_raw_stat_e + RecRawStat test_raw_stat_e; + RecFloat r; + test_raw_stat_e.sum = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_E]->sum)); + test_raw_stat_e.count = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_E]->count)); + if (test_raw_stat_e.count == 0) { + r = 0.0f; + } else { + r = (float) ((double) test_raw_stat_e.sum / (double) test_raw_stat_e.count); + r = r / (float) (HRTIME_SECOND); + } + if (stat_e != r) { + printf("ERROR: stat_e: %f, expect stat_e from avg: %f\n", stat_e, r); + } else { + printf("OKAY: stat_e: %f, expect stat_e from avg: %f\n", stat_e, r); + } + + // Compare read value stat_f and expected value test_raw_stat_f + // Since RecSet only set g_rsb->global[MY_STAT_F]->count to be g_count value. + // It will not set data.rec_int for stat_f until the RecExecRawStatSyncCbs + // is called. RecExecRawStatSyncCbs callback RecRawStatSyncCount which set + // data.rec_int to be g_rsb->global[MY_STAT_F]->count. The schedule for + // RecExecRawStatSyncCbs is REC_RAW_STAT_SYNC_INTERVAL_SEC = 3 secs. + // The normal for this dummy_function is 1 sec. There is no way we can + // get the right value for this. Let ask Eric for this :) + // I have increase the ink_sleep time (about 3 secs) between RecSet and RecGet + // for stat_c hoping that we got the RecExecRawStatSyncCbs at the middle of them + // so we can get the right value for stat_c. However, this will screw up + // stat_d badly as we get NaN for stat_d. + RecRawStat test_raw_stat_f; + test_raw_stat_f.count = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_F]->count)); + RecInt check_stat_f; + RecGetRawStatCount(g_rsb, (int) MY_STAT_F, &check_stat_f); + if (stat_f != test_raw_stat_f.count || stat_f != check_stat_f) { + printf("ERROR: After RecSetRawStatCount, stat_f: %d:%d, stat_f by REC_ATOMIC_READ64: %d:%d\n", stat_f, + test_raw_stat_f.count); + printf(" stat_f by RecGetRawStatCount: %d:%d\n", check_stat_f); + } else { + printf("OKAY: After RecSetRawStatCount, stat_f: %d:%d, stat_f by REC_ATOMIC_READ64: %d:%d\n", stat_f, + test_raw_stat_f.count); + printf(" stat_f by RecGetRawStatCount: %d:%d\n", check_stat_f); + } + + // Compare read value stat_g and expeced value test_raw_stat_g + RecRawStat test_raw_stat_g; + test_raw_stat_g.sum = REC_ATOMIC_READ64(&(g_rsb->global[MY_STAT_G]->sum)); + RecInt check_stat_g; + RecGetRawStatSum(g_rsb, (int) MY_STAT_G, &check_stat_g); + if (stat_g != test_raw_stat_g.count || stat_g != check_stat_g) { + printf("ERROR: After RecSetRawStatSum, stat_g: %d:%d, stat_g by REC_ATOMIC_READ64: %d:%d\n", stat_g, + test_raw_stat_g.sum); + printf(" stat_g by RecGetRawStatSum: %d:%d\n", check_stat_g); + } else { + printf("OKAY: After RecSetRawStatSum, stat_g: %d:%d, stat_g by REC_ATOMIC_READ64: %d:%d\n", stat_g, + test_raw_stat_g.sum); + printf(" stat_g by RecGetRawStatSum: %d:%d\n", check_stat_g); + } + ink_atomic_increment(&g_count, 1); + + // test_raw_stat_e should have the time it takes to run this function + hr_finish = ink_get_hrtime(); + RecIncrRawStat(g_rsb, mutex->thread_holding, (int) MY_STAT_E, hr_finish - hr_start); + + return 0; + } +}; + +void +Test03() +{ + printf("[Test03: RawStat Test]\n"); + + // Register raw statistics + g_rsb = RecAllocateRawStatBlock((int) MY_STAT_COUNT); + + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_a", + RECD_FLOAT, RECP_NULL, (int) MY_STAT_A, RecRawStatSyncAvg); + + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_b", + RECD_INT, RECP_PERSISTENT, (int) MY_STAT_B, RecRawStatSyncSum); + + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_c", + RECD_INT, RECP_NULL, (int) MY_STAT_C, RecRawStatSyncCount); + + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_d", + RECD_FLOAT, RECP_NULL, (int) MY_STAT_D, raw_stat_sync_ticks_per_sec); + + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_e", + RECD_FLOAT, RECP_NULL, (int) MY_STAT_E, RecRawStatSyncHrTimeAvg); + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_f", + RECD_INT, RECP_NULL, (int) MY_STAT_F, RecRawStatSyncCount); + // If forget to Register this RawStat, we will have SEGV when checking + // g_rsb->global[MY_STAT_G] + RecRegisterRawStat(g_rsb, RECT_PROCESS, "proxy.process.test_raw_stat_g", + RECD_INT, RECP_NULL, (int) MY_STAT_G, RecRawStatSyncSum); + + // Schedule a bunch of continuations that will use the stats registered above + RawStatCont *sc = new RawStatCont(new_ProxyMutex()); + eventProcessor.schedule_every(sc, HRTIME_SECONDS(1), ET_CALL, EVENT_INTERVAL, NULL); + eventProcessor.schedule_every(sc, HRTIME_SECONDS(1), ET_CALL, EVENT_INTERVAL, NULL); + eventProcessor.schedule_every(sc, HRTIME_SECONDS(1), ET_CALL, EVENT_INTERVAL, NULL); + eventProcessor.schedule_every(sc, HRTIME_SECONDS(1), ET_CALL, EVENT_INTERVAL, NULL); + +} + +//------------------------------------------------------------------------- +// DumpRecordHtCont +//------------------------------------------------------------------------- + +struct DumpRecordsHtCont:public Continuation +{ + DumpRecordsHtCont(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&DumpRecordsHtCont::dummy_function); + } + int dummy_function(int event, Event * e) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + RecDumpRecordsHt(RECT_NULL); + return 0; + } +}; + +//------------------------------------------------------------------------- +// TreeTest01: +// +//------------------------------------------------------------------------- + +void +TreeTest01() +{ + char **var_buf = NULL; + int buf_len = 0; + RecGetRecordList("proxy.config", &var_buf, &buf_len); + for (int i = 0; i < buf_len; i++) { + ink_debug_assert(var_buf[i]); + diags->print(NULL, DL_Note, NULL, NULL, "\tRecTree node: (proxy.config.*) %s", var_buf[i]); + } + delete[]var_buf; + printf("\n"); + if (buf_len == 12) { + diags->print(NULL, DL_Note, NULL, NULL, "\tRecTree Test -- PASS\n"); + } else { + diags->print(NULL, DL_Note, NULL, NULL, "\tRecTree Test -- FAIL\n"); + } + printf("\n"); +} + + +//------------------------------------------------------------------------- +// TreeTest02: +// +// This should only run after Test03. +// Determine whether proxy.process.* variable are referred by the RecTree +// properly. +//------------------------------------------------------------------------- + +void +TreeTest02() +{ + char **var_buf = NULL; + int buf_len = 0; + RecGetRecordList("proxy.process", &var_buf, &buf_len); + for (int i = 0; i < buf_len; i++) { + ink_debug_assert(var_buf[i]); + diags->print(NULL, DL_Note, NULL, NULL, "\tRecTree (proxy.process.*) node: %s", var_buf[i]); + } + delete[]var_buf; + printf("\n"); + if (buf_len == 7) { + diags->print(NULL, DL_Note, NULL, NULL, "\tRecTree Test -- PASS\n"); + } else { + diags->print(NULL, DL_Note, NULL, NULL, "\tRecTree Test -- FAIL\n"); + } + printf("\n"); +} + +//------------------------------------------------------------------------- +// main +//------------------------------------------------------------------------- + +int +main(int argc, char **argv) +{ + + RecModeT mode_type = RECM_STAND_ALONE; + if ((argc == 2) && (strcmp(argv[1], "-M") == 0)) { + mode_type = RECM_CLIENT; + } + // Start diags logging + FILE *log_fp; + if ((log_fp = fopen("recprocess.log", "a+")) != NULL) { + int status = setvbuf(log_fp, NULL, _IOLBF, 512); + if (status != 0) { + fclose(log_fp); + log_fp = NULL; + } + } + diags = NEW(new Diags("rec", NULL, log_fp)); + diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug); + diags->print(NULL, DL_Note, NULL, NULL, "Starting '%s'", argv[0]); + + // System initialization. Note that a pointer to the diags object + // is passed into librecprocess.a. If manager isn't running, we + // need to register our own configs + RecProcessInit(mode_type, diags); + RecProcessInitMessage(mode_type); + if (mode_type == RECM_STAND_ALONE) { + RecordsConfigRegister(); + } + ink_event_system_init(EVENT_SYSTEM_MODULE_VERSION); + eventProcessor.start(4); + RecProcessStart(); + + RecSignalManager(1, "This is a signal, signaled by RecSignalManager"); + + // See if we're sync'd okay + RecDumpRecordsHt(RECT_NULL); + + + // Run tests + TreeTest01(); + Test01(); + Test02(); + Test03(); + TreeTest02(); + + + // Schedule dump continuation so that we can see what's going on + DumpRecordsHtCont *drhc = new DumpRecordsHtCont(new_ProxyMutex()); + eventProcessor.schedule_every(drhc, HRTIME_SECONDS(10), ET_CALL, EVENT_INTERVAL, NULL); + + this_thread()->execute(); + return 0; +} diff --git a/lib/records/test_RecTree.cc b/lib/records/test_RecTree.cc new file mode 100644 index 00000000..5fa5083d --- /dev/null +++ b/lib/records/test_RecTree.cc @@ -0,0 +1,81 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_RecTree.h" +#include "stdio.h" + +int +main(int argc, char **argv) +{ + + REC_NOWARN_UNUSED(argc); + REC_NOWARN_UNUSED(argv); + + RecTree *new_rec_tree = new RecTree(NULL); + new_rec_tree->rec_tree_insert("proxy.process.librecords.first_child"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.first_child.grandchild1"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.first_child.grandchild2"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.first_child.grandchild2.grandgrandchild1"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.first_child.grandchild2.grandgrandchild2"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.first_child.grandchild3"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.second_child"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.second_child.grandchild1"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.1"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.process.librecords.2"); + printf("\n"); + new_rec_tree->rec_tree_insert("proxy.node.http.hitrate"); + printf("\n"); + new_rec_tree->print(); + + /* Test getting subtree */ + printf("\nTest getting subtree(1)\n"); + printf("----------------------------------------------------------------\n"); + RecTree *sub_tree = new_rec_tree->rec_tree_get("proxy.process.librecords"); + sub_tree->print(); + + printf("\nTest getting subtree(2)\n"); + printf("----------------------------------------------------------------\n"); + sub_tree = new_rec_tree->rec_tree_get("proxy.process.*"); + sub_tree->print(); + + /* Test getting a list of variables */ + printf("\nTest getting variables list\n"); + printf("----------------------------------------------------------------\n"); + int count = 0; + char **variable_list; + new_rec_tree->rec_tree_get_list("proxy.process", &variable_list, &count); + for (int i = 0; i < count; i++) { + printf("[RecTreeTest] %s\n", variable_list[i]); + } + + printf("\n -- Fin --\n"); +} diff --git a/lib/records/test_RecordsConfig.cc b/lib/records/test_RecordsConfig.cc new file mode 100644 index 00000000..0c395ebf --- /dev/null +++ b/lib/records/test_RecordsConfig.cc @@ -0,0 +1,60 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "I_RecCore.h" + +//------------------------------------------------------------------------- +// RecordsConfigRegister +//------------------------------------------------------------------------- + +void +RecordsConfigRegister() +{ + + RecRegisterConfigString(RECT_CONFIG, "proxy.config.parse_test_2a", NULL, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.parse_test_2b", NULL, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.parse_test_3a", NULL, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.parse_test_3b", NULL, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.parse_test_4a", NULL, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.parse_test_4b", NULL, RECU_DYNAMIC, RECC_NULL, NULL); + + RecRegisterConfigString(RECT_CONFIG, "proxy.config.cb_test_1", "cb_test_1__original", RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.cb_test_2", "cb_test_2__original", RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.local.cb_test_1", "cb_test_1__original", RECU_DYNAMIC, RECC_NULL, + NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.local.cb_test_2", "cb_test_2__original", RECU_DYNAMIC, RECC_NULL, + NULL); + RecRegisterConfigString(RECT_CONFIG, "proxy.config.local.cb_test_3", "cb_test_3__original", RECU_DYNAMIC, RECC_NULL, + NULL); + RecRegisterConfigInt(RECT_CONFIG, "proxy.config.link_test_1", 0, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigFloat(RECT_CONFIG, "proxy.config.link_test_2", 0.0f, RECU_DYNAMIC, RECC_NULL, NULL); + RecRegisterConfigCounter(RECT_CONFIG, "proxy.config.link_test_3", 0, RECU_DYNAMIC, RECC_NULL, NULL); + + // NODE + RecRegisterStatString(RECT_NODE, "proxy.node.cb_test_1", "cb_test_1__original", RECP_NULL); + RecRegisterStatString(RECT_NODE, "proxy.node.cb_test_2", "cb_test_2__original", RECP_NULL); + RecRegisterStatInt(RECT_NODE, "proxy.node.cb_test_int", 0, RECP_NULL); + RecRegisterStatFloat(RECT_NODE, "proxy.node.cb_test_float", 0.0f, RECP_NULL); + RecRegisterStatCounter(RECT_NODE, "proxy.node.cb_test_count", 0, RECP_NULL); + +} diff --git a/lib/records/test_RecordsConfig.h b/lib/records/test_RecordsConfig.h new file mode 100644 index 00000000..df1884bd --- /dev/null +++ b/lib/records/test_RecordsConfig.h @@ -0,0 +1,28 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _TEST_RECORDS_CONFIG_H_ + +void RecordsConfigRegister(); + +#endif diff --git a/lib/records/test_records.config b/lib/records/test_records.config new file mode 100644 index 00000000..be9df8ed --- /dev/null +++ b/lib/records/test_records.config @@ -0,0 +1,20 @@ +########################################################################### +# Test records.config +########################################################################### +# parse tests + CONFIG proxy.config.parse_test_0a STRING +CONFIG proxy.config.parse_test_1a STRING +CONFIG proxy.config.parse_test_1b STRING +CONFIG proxy.config.parse_test_2a STRING X +CONFIG proxy.config.parse_test_2b STRING X +CONFIG proxy.config.parse_test_3a STRING XXX +CONFIG proxy.config.parse_test_3b STRING XXX + CONFIG proxy.config.parse_test_4a STRING XXX XXX XXX +CONFIG proxy.config.parse_test_4b STRING XXX XXX XXX +########################################################################## +# User Overridden Configs Below +########################################################################## +CONFIG proxy.config.cb_test_1 STRING cb_test_1__original +CONFIG proxy.config.link_test_1 INT 1 +CONFIG proxy.config.link_test_2 FLOAT 100.000000 +CONFIG proxy.config.link_test_3 COUNTER 5 diff --git a/lib/ts/Allocator.cc b/lib/ts/Allocator.cc new file mode 100644 index 00000000..e7a7fad8 --- /dev/null +++ b/lib/ts/Allocator.cc @@ -0,0 +1,43 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/**************************************************************************** + + Allocator.h + + +*****************************************************************************/ + +#include "libts.h" +#include "Allocator.h" +#include "ink_align.h" + +Allocator::Allocator(const char *name, unsigned int element_size, unsigned int chunk_size, unsigned int alignment) +{ +#ifdef USE_DALLOC + da.init(name, element_size, alignment); +#else + ink_freelist_init(&fl, name, element_size, chunk_size, 0, alignment); +#endif +} diff --git a/lib/ts/Allocator.h b/lib/ts/Allocator.h new file mode 100644 index 00000000..2009c0d8 --- /dev/null +++ b/lib/ts/Allocator.h @@ -0,0 +1,331 @@ +/** @file + + Fast-Allocators + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Provides three classes + - Allocator for allocating memory blocks of fixed size + - ClassAllocator for allocating objects + - SpaceClassAllocator for allocating sparce objects (most members uninitialized) + + These class provides a efficient way for handling dynamic allocation. + The fast allocator maintains its own freepool of objects from + which it doles out object. Allocated objects when freed go back + to the free pool. + + @note Fast allocators could accumulate a lot of objects in the + free pool as a result of bursty demand. Memory used by the objects + in the free pool never gets freed even if the freelist grows very + large. + + */ + +#ifndef _Allocator_h_ +#define _Allocator_h_ + +#include +#include "ink_queue.h" +#include "ink_port.h" +#include "ink_resource.h" + +#ifdef USE_DALLOC +#include "DAllocatore.h" +#endif + +#define RND16(_x) (((_x)+15)&~15) + +/** Allocator for fixed size memory blocks. */ +class Allocator +{ +public: +#ifdef USE_DALLOC + DAllocator da; +#else + InkFreeList fl; +#endif + + /** + Allocate a block of memory (size specified during construction + of Allocator. + + */ + void *alloc_void(); + + /** Deallocate a block of memory allocated by the Allocator. */ + void free_void(void *ptr); + + Allocator() + { +#ifndef USE_DALLOC + memset(&fl, 0, sizeof fl); +#endif + } + + /** + Creates a new allocator. + + @param name identification tag used for mem tracking . + @param element_size size of memory blocks to be allocated. + @param chunk_size number of units to be allocated if free pool is empty. + @param alignment of objects must be a power of 2. + + */ + Allocator(const char *name, unsigned int element_size, unsigned int chunk_size = 128, unsigned int alignment = 8); + + /** Re-initialize the parameters of the allocator. */ + void re_init(const char *name, unsigned int element_size, unsigned int chunk_size, unsigned int alignment); +}; + +/** + Allocator for Class objects. It uses a prototype object to do + fast initialization. Prototype of the template class is created + when the fast allocator is created. This is instantiated with + default (no argument) constructor. Constructor is not called for + the allocated objects. Instead, the prototype is just memory + copied onto the new objects. This is done for performance reasons. + +*/ +template class ClassAllocator:public Allocator { +public: + + /** Allocates objects of the templated type. */ + C * alloc(); + + /** + Deallocates objects of the templated type. + + @param ptr pointer to be freed. + + */ + void free(C * ptr); + + /** + Allocate objects of the templated type via the inherited interface + using void pointers. + + */ + void *alloc_void() + { + return (void *) alloc(); + } + + /** + Deallocate objects of the templated type via the inherited + interface using void pointers. + + @param ptr pointer to be freed. + + */ + void free_void(void *ptr) + { + free((C *) ptr); + } + + /** + Create a new class specific ClassAllocator. + + @param name some identifying name, used for mem tracking purposes. + @param chunk_size number of units to be allocated if free pool is empty. + @param alignment of objects must be a power of 2. + + */ + ClassAllocator(const char *name, unsigned int chunk_size = 128, unsigned int alignment = 16); + + /** Private data. */ + struct _proto + { + C typeObject; + int64_t space_holder; + } proto; +}; + +/** + Allocator for space class, a class with a lot of uninitialized + space/members. It uses an instantiate fucntion do initialization + of objects. This is particulary useful if most of the space in + the objects does not need to be intialized. The inifunction passed + can be used to intialize a few fields selectively. Using + ClassAllocator for space objects would unnecessarily initialized + all of the members. + +*/ +template class SparceClassAllocator:public ClassAllocator { +public: + + /** Allocates objects of the templated type. */ + C * alloc(); + + /** + Create a new class specific SparceClassAllocator. + + @param name some identifying name, used for mem tracking purposes. + @param chunk_size number of units to be allocated if free pool is empty. + @param alignment of objects must be a power of 2. + @param instantiate_func + + */ + SparceClassAllocator(const char *name, + unsigned int chunk_size = 128, + unsigned int alignment = 16, void (*instantiate_func) (C * proto, C * instance) = NULL); + /** Private data. */ + void (*instantiate) (C * proto, C * instance); +}; + +inline void +Allocator::re_init(const char *name, unsigned int element_size, unsigned int chunk_size, unsigned int alignment) +{ +#ifdef USE_DALLOC + da.init(name, element_size, alignment); +#else + ink_freelist_init(&this->fl, name, element_size, chunk_size, 0, alignment); +#endif +} + +#if !defined (PURIFY) && !defined (_NO_FREELIST) +inline void * +Allocator::alloc_void() +{ +#ifdef USE_DALLOC + return this->da.alloc(); +#else + return ink_freelist_new(&this->fl); +#endif +} + +inline void +Allocator::free_void(void *ptr) +{ +#ifdef USE_DALLOC + this->da.free(ptr); +#else + ink_freelist_free(&this->fl, ptr); +#endif +} +#else +// no freelist, non WIN32 platform +inline void * +Allocator::alloc_void() +{ + return (void *) ink_memalign(this->fl.alignment, this->fl.type_size); +} +inline void +Allocator::free_void(void *ptr) +{ + if (likely(ptr)) + ::free(ptr); + return; +} +#endif /* end no freelist */ + +template inline + ClassAllocator::ClassAllocator(const char *name, unsigned int chunk_size, unsigned int alignment) +{ +#ifdef USE_DALLOC + this->da.init(name, RND16(sizeof(C)), RND16(alignment)); +#else +#if !defined(_NO_FREELIST) + ink_freelist_init(&this->fl, name, RND16(sizeof(C)), chunk_size, 0, RND16(alignment)); +#endif //_NO_FREELIST +#endif /* USE_DALLOC */ +} + +template inline +SparceClassAllocator::SparceClassAllocator(const char *name, unsigned int chunk_size, unsigned int alignment, + void (*instantiate_func) (C * proto, C * instance)) : ClassAllocator (name, chunk_size, alignment) +{ + instantiate = instantiate_func; // NULL by default +} + +#if !defined (PURIFY) && !defined (_NO_FREELIST) + +// use freelist +template inline C * ClassAllocator::alloc() +{ +#ifdef USE_DALLOC + void *ptr = this->da.alloc(); +#else + void *ptr = ink_freelist_new(&this->fl); +#endif + if (sizeof(C) < 512) { + for (unsigned int i = 0; i < RND16(sizeof(C)) / sizeof(int64_t); i++) + ((int64_t *) ptr)[i] = ((int64_t *) &this->proto.typeObject)[i]; + } else + memcpy(ptr, &this->proto.typeObject, sizeof(C)); + return (C *) ptr; +} + +template inline C * SparceClassAllocator::alloc() +{ +#ifdef USE_DALLOC + void *ptr = this->da.alloc(); +#else + void *ptr = ink_freelist_new(&this->fl); +#endif + if (!instantiate) { + if (sizeof(C) < 512) { + for (unsigned int i = 0; i < RND16(sizeof(C)) / sizeof(int64_t); i++) + ((int64_t *) ptr)[i] = ((int64_t *) &this->proto.typeObject)[i]; + } else + memcpy(ptr, &this->proto.typeObject, sizeof(C)); + } else + (*instantiate) ((C *) &this->proto.typeObject, (C *) ptr); + return (C *) ptr; +} + +template inline void ClassAllocator::free(C * ptr) +{ +#ifdef USE_DALLOC + this->da.free(ptr); +#else + ink_freelist_free(&this->fl, ptr); +#endif + return; +} + +#else // _NO_FREELIST + +// no freelist +template inline C * ClassAllocator::alloc() +{ + void *ptr = (void *) ink_memalign(8, sizeof(C)); + memcpy(ptr, &this->proto.typeObject, sizeof(C)); + return (C *) ptr; +} + +template inline C * SparceClassAllocator::alloc() +{ + void *ptr = (void *) ink_memalign(8, sizeof(C)); + + if (instantiate == NULL) + memcpy(ptr, &this->proto.typeObject, sizeof(C)); + else + (*instantiate) ((C *) &this->proto.typeObject, (C *) ptr); + + return (C *) ptr; +} + +template inline void ClassAllocator::free(C * ptr) +{ + if (ptr) + ::free(ptr); + return; +} +#endif // _NO_FREELIST +#endif // _Allocator_h_ diff --git a/lib/ts/Arena.cc b/lib/ts/Arena.cc new file mode 100644 index 00000000..8013557e --- /dev/null +++ b/lib/ts/Arena.cc @@ -0,0 +1,160 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include +#include + + +#define DEFAULT_ALLOC_SIZE 1024 +#define DEFAULT_BLOCK_SIZE (DEFAULT_ALLOC_SIZE - (sizeof (ArenaBlock) - 8)) + + +static Allocator defaultSizeArenaBlock("ArenaBlock", DEFAULT_ALLOC_SIZE); + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +static inline ArenaBlock * +blk_alloc(int size) +{ + ArenaBlock *blk; + + if (size == DEFAULT_BLOCK_SIZE) { + blk = (ArenaBlock *) defaultSizeArenaBlock.alloc_void(); + } else { + blk = (ArenaBlock *) xmalloc(size + sizeof(ArenaBlock) - 8); + } + + blk->next = NULL; + blk->m_heap_end = &blk->data[size]; + blk->m_water_level = &blk->data[0]; + + return blk; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +static inline void +blk_free(ArenaBlock * blk) +{ + int size; + + size = blk->m_heap_end - &blk->data[0]; + if (size == DEFAULT_BLOCK_SIZE) { + defaultSizeArenaBlock.free_void(blk); + } else { + xfree(blk); + } +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +static void * +block_alloc(ArenaBlock * block, size_t size, size_t alignment) +{ + char *mem; + + mem = block->m_water_level; + if (((size_t) mem) & (alignment - 1)) { + mem += (alignment - ((size_t) mem)) & (alignment - 1); + } + + if ((block->m_heap_end >= mem) && (((size_t) block->m_heap_end - (size_t) mem) >= size)) { + block->m_water_level = mem + size; + return mem; + } + + return NULL; +} + +void * +Arena::alloc(size_t size, size_t alignment) +{ + ArenaBlock *b; + unsigned int block_size; + void *mem; + + ink_assert((alignment & (alignment - 1)) == 0); + + b = m_blocks; + while (b) { + mem = block_alloc(b, size, alignment); + if (mem) { + return mem; + } + b = b->next; + } + + block_size = (unsigned int) (size * 1.5); + if (block_size < DEFAULT_BLOCK_SIZE) { + block_size = DEFAULT_BLOCK_SIZE; + } + + b = blk_alloc(block_size); + b->next = m_blocks; + m_blocks = b; + + mem = block_alloc(b, size, alignment); + return mem; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +Arena::free(void *mem, size_t size) +{ + if (m_blocks) { + ArenaBlock *b; + + b = m_blocks; + while (b->next) { + b = b->next; + } + + if (b->m_water_level == ((char *) mem + size)) { + b->m_water_level = (char *) mem; + } + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +Arena::reset() +{ + ArenaBlock *b; + + while (m_blocks) { + b = m_blocks->next; + blk_free(m_blocks); + m_blocks = b; + } + ink_assert(m_blocks == NULL); +} diff --git a/lib/ts/Arena.h b/lib/ts/Arena.h new file mode 100644 index 00000000..e3c26f5a --- /dev/null +++ b/lib/ts/Arena.h @@ -0,0 +1,182 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __ARENA_H__ +#define __ARENA_H__ + + +#include +#include +#include "ink_assert.h" + + +struct ArenaBlock +{ + ArenaBlock *next; + char *m_heap_end; + char *m_water_level; + char data[8]; +}; + + +class Arena +{ +public: + Arena():m_blocks(NULL) + { + } + ~Arena() + { + reset(); + } + + inkcoreapi void *alloc(size_t size, size_t alignment = sizeof(double)); + void free(void *mem, size_t size); + size_t str_length(const char *str); + char *str_alloc(size_t len); + void str_free(char *str); + char *str_store(const char *str, size_t len); + + inkcoreapi void reset(); + +private: + ArenaBlock * m_blocks; +}; + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +inline size_t +Arena::str_length(const char *str) +{ + unsigned char *s, *e; + size_t len; + + e = (unsigned char *) str; + s = e - 1; + + while (*s >= 128) { + s -= 1; + } + + len = *s++; + while (s != e) { + len = (len * 128) + (255 - *s++); + } + + return len; +} + +/*------------------------------------------------------------------------- + layout = [length][data] + + length 1 = [1] + length 127 = [127] + length 128 = [1][255] + length 128 + 1 = [1][254] + length 128 + 2 = [1][253] + length 128 + 127 = [1][128] + length 128 + 128 = [2][255] + length 128 * 128 = [1][255][255] + length 128 * 128 + 1 = [1][255][254] + length 128 * 128 + 2 = [1][255][253] + length 128 * 128 + 127 = [1][255][128] + length 128 * 128 + 128 = [1][254][255] + -------------------------------------------------------------------------*/ + +inline char * +Arena::str_alloc(size_t len) +{ + unsigned char *mem, *p; + size_t size; + size_t tmp; + + size = len + 1 + 1; + tmp = len; + + while (tmp >= 128) { + size += 1; + tmp /= 128; + } + + mem = (unsigned char *) alloc(size, 1); + + mem += (size - len - 1); + p = mem - 1; + tmp = len; + + while (tmp >= 128) { + *p-- = (unsigned char) (255 - (tmp % 128)); + tmp /= 128; + } + *p = (unsigned char) tmp; + + return (char *) mem; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +inline void +Arena::str_free(char *str) +{ + unsigned char *p, *s, *e; + size_t len; + + e = (unsigned char *) str; + s = e - 1; + + while (*s >= 128) { + s -= 1; + } + + p = s; + + len = *s++; + while (s != e) { + len = (len * 128) + (255 - *s++); + } + + len += (e - p) + 1; + free(p, len); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +inline char * +Arena::str_store(const char *str, size_t len) +{ + char *mem; + + mem = str_alloc(len); + memcpy(mem, str, len); + mem[len] = '\0'; + + return mem; +} + + +#endif /* __ARENA_H__ */ + diff --git a/lib/ts/Bitops.cc b/lib/ts/Bitops.cc new file mode 100644 index 00000000..44a99425 --- /dev/null +++ b/lib/ts/Bitops.cc @@ -0,0 +1,63 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "Bitops.h" + + +unsigned char bit_table[256] = { + 0, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 7, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 8, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 7, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 6, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, + 5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, +}; + +unsigned char bit_count_table[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; diff --git a/lib/ts/Bitops.h b/lib/ts/Bitops.h new file mode 100644 index 00000000..76ed1f0d --- /dev/null +++ b/lib/ts/Bitops.h @@ -0,0 +1,275 @@ +/** @file + + Utility functions for efficient bit operations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __BITOPS_H__ +#define __BITOPS_H__ +#include "libts.h" + +/** + Find First (bit) Set. Index starts at 1. + + @return zero for zero arg. + +*/ +static inline int +ink_ffs(int n) +{ + return ffs(n); +} + +/** + Returns the index of the first bit (least significant bit), set "1" + for each char in the range (start end). + + @param start pointer to the first character. + @param end pointer to the location after the last character. + @param p (if not null) returns the location of the first char that + has a bit set. + @return index of the first bit set in the first character that has a + bit turned on. Zero if all bits are zero. + +*/ +static inline int +bitops_first_set(unsigned char *start, unsigned char *end, unsigned char **p) +{ + extern unsigned char bit_table[]; + + int idx; + + idx = 0; + while (start != end) { + idx = bit_table[*start]; + if (idx) { + break; + } + start += 1; + } + + if (p) { + *p = start; + } + + return idx; +} + +/** + Returns the index of the first bit (least significant bit), unset "0" + for each char in the range (start end). + + @param start pointer to the first character. + @param end pointer to the location after the last character. + @param p (if not null) returns the location of the first char that + has a bit unset. + @return index of the first bit set in the first character that has a + bit turned off. Zero if all bits are 1. + +*/ +static inline int +bitops_first_unset(unsigned char *start, unsigned char *end, unsigned char **p) +{ + extern unsigned char bit_table[]; + + int idx; + + idx = 0; + while (start != end) { + idx = bit_table[~(*start)]; + if (idx) { + break; + } + start += 1; + } + + if (p) { + *p = start; + } + + return idx; +} + +/** + Returns the index of the first bit (least significant bit), set "1" + for each char in the range (start end). + + @param start pointer to the first character. + @param end pointer to the location after the last character. + @param offset + @return index of the first bit set in the first character that has a + bit turned on. Zero if all bits are zero. + +*/ +static inline int +bitops_next_set(unsigned char *start, unsigned char *end, int offset) +{ + extern unsigned char bit_table[]; + + unsigned char *p; + unsigned char c; + size_t idx; + int t; + + idx = 0; + p = start + offset / 8; + t = (offset % 8) + 1; + + while (p != end) { + idx = bit_table[*p]; + if (idx) { + c = *p; + while (idx && (idx <= (size_t) t)) { + c &= ~(1 << (idx - 1)); + idx = bit_table[c]; + } + + if (idx) { + break; + } + } + p += 1; + t = 0; + } + + if (idx) { + idx -= 1; + idx += (p - start) * 8; + } else { + idx = (size_t) - 1; + } + + return (int) idx; +} + +static inline int +bitops_next_unset(unsigned char *start, unsigned char *end, int offset) +{ + extern unsigned char bit_table[]; + + unsigned char *p; + unsigned char c; + size_t idx; + int t; + + idx = 0; + p = start + offset / 8; + t = (offset % 8) + 1; + + while (p != end) { + c = ~(*p); + idx = bit_table[c]; + if (idx) { + while (idx && (idx <= (size_t) t)) { + c &= ~(1 << (idx - 1)); + idx = bit_table[c]; + } + + if (idx) { + break; + } + } + p += 1; + t = 0; + } + + if (idx) { + idx -= 1; + idx += (p - start) * 8; + } else { + idx = (size_t) - 1; + } + + return (int) idx; +} + +static inline int +bitops_count(unsigned char *start, unsigned char *end) +{ + extern unsigned char bit_count_table[]; + + int count; + + count = 0; + while (start != end) { + count += bit_count_table[*start++]; + } + + return count; +} + +static inline void +bitops_union(unsigned char *s1, unsigned char *s2, int len) +{ + int i; + + if (!s1 || !s2) { + return; + } + + for (i = 0; i < len; i++) { + s1[i] |= s2[i]; + } +} + +static inline unsigned char +bitops_set(unsigned char val, int bit) +{ + return (val | (1 << bit)); +} + +static inline void +bitops_set(unsigned char *val, int bit) +{ + int pos = bit >> 3; + int idx = bit & 0x7; + val[pos] |= (1 << idx); +} + +static inline unsigned char +bitops_unset(unsigned char val, int bit) +{ + return (val & ~(1 << bit)); +} + +static inline void +bitops_unset(unsigned char *val, int bit) +{ + int pos = bit >> 3; + int idx = bit & 0x7; + val[pos] &= ~(1 << idx); +} + +static inline int +bitops_isset(unsigned char val, int bit) +{ + return ((val & (1 << bit)) != 0); +} + +static inline int +bitops_isset(unsigned char *val, int bit) +{ + int pos = bit / 8; + int idx = bit % 8; + return ((val[pos] & (1 << idx)) != 0); +} + +#endif /* __BITOPS_H__ */ + diff --git a/lib/ts/Compatability.h b/lib/ts/Compatability.h new file mode 100644 index 00000000..13667e2a --- /dev/null +++ b/lib/ts/Compatability.h @@ -0,0 +1,76 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#if !defined (_Compatability_h_) +#define _Compatability_h_ + +#include +#include +#include +#include +#include + +#include "ink_port.h" +#include "ink_resource.h" + +// We can't use #define for min and max becuase it will conflict with +// other declarations of min and max functions. This conflict +// occurs with STL +template T min(const T a, const T b) +{ + return a < b ? a : b; +} + +template T max(const T a, const T b) +{ + return a > b ? a : b; +} + +// Define the directory separator for UNIX +#define DIR_SEP "/" + +#define _O_ATTRIB_NORMAL 0x0000 +#define _O_ATTRIB_OVERLAPPED 0x0000 + +// +// If you the gethostbyname() routines on your system are automatically +// re-entrent (as in Digital Unix), define the following +// +#if defined(linux) +#define NEED_ALTZONE_DEFINED +#define MAP_SHARED_MAP_NORESERVE (MAP_SHARED) +#elif defined(darwin) +#define MAP_SHARED_MAP_NORESERVE (MAP_SHARED) +#else +#define MAP_SHARED_MAP_NORESERVE (MAP_SHARED | MAP_NORESERVE) +#endif + +#if defined(darwin) +typedef uint32_t in_addr_t; +#endif + +#define NEED_HRTIME + +#include "Resource.h" + +#endif diff --git a/lib/ts/CompileParseRules.cc b/lib/ts/CompileParseRules.cc new file mode 100644 index 00000000..a3faf0ab --- /dev/null +++ b/lib/ts/CompileParseRules.cc @@ -0,0 +1,147 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define COMPILE_PARSE_RULES + +#include "ParseRules.h" + +const unsigned int parseRulesCType[256] = { 0 }; +const char parseRulesCTypeToUpper[256] = { 0 }; +const char parseRulesCTypeToLower[256] = { 0 }; + +unsigned int tparseRulesCType[256]; +char tparseRulesCTypeToUpper[256]; +char tparseRulesCTypeToLower[256]; + + +#include +#include +#include "ink_string.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +static char * +uint_to_binary(unsigned int u) +{ + int i; + static char buf[33]; + for (i = 0; i < 32; i++) { + buf[i] = ((u & (1 << (31 - i))) ? '1' : '0'); + } + buf[32] = '\0'; + return (buf); +} + +int +main() +{ + int c; + for (c = 0; c < 256; c++) { + tparseRulesCType[c] = 0; + tparseRulesCTypeToLower[c] = ParseRules::ink_tolower(c); + tparseRulesCTypeToUpper[c] = ParseRules::ink_toupper(c); + + if (ParseRules::is_char(c)) + tparseRulesCType[c] |= is_char_BIT; + if (ParseRules::is_upalpha(c)) + tparseRulesCType[c] |= is_upalpha_BIT; + if (ParseRules::is_loalpha(c)) + tparseRulesCType[c] |= is_loalpha_BIT; + if (ParseRules::is_alpha(c)) + tparseRulesCType[c] |= is_alpha_BIT; + if (ParseRules::is_digit(c)) + tparseRulesCType[c] |= is_digit_BIT; + if (ParseRules::is_ctl(c)) + tparseRulesCType[c] |= is_ctl_BIT; + if (ParseRules::is_ws(c)) + tparseRulesCType[c] |= is_ws_BIT; + if (ParseRules::is_hex(c)) + tparseRulesCType[c] |= is_hex_BIT; + char cc = c; + if (ParseRules::is_pchar(&cc)) + tparseRulesCType[c] |= is_pchar_BIT; + if (ParseRules::is_extra(c)) + tparseRulesCType[c] |= is_extra_BIT; + if (ParseRules::is_safe(c)) + tparseRulesCType[c] |= is_safe_BIT; + if (ParseRules::is_unsafe(c)) + tparseRulesCType[c] |= is_unsafe_BIT; + if (ParseRules::is_national(c)) + tparseRulesCType[c] |= is_national_BIT; + if (ParseRules::is_reserved(c)) + tparseRulesCType[c] |= is_reserved_BIT; + if (ParseRules::is_unreserved(c)) + tparseRulesCType[c] |= is_unreserved_BIT; + if (ParseRules::is_punct(c)) + tparseRulesCType[c] |= is_punct_BIT; + if (ParseRules::is_end_of_url(c)) + tparseRulesCType[c] |= is_end_of_url_BIT; + if (ParseRules::is_tspecials(c)) + tparseRulesCType[c] |= is_tspecials_BIT; + if (ParseRules::is_spcr(c)) + tparseRulesCType[c] |= is_spcr_BIT; + if (ParseRules::is_splf(c)) + tparseRulesCType[c] |= is_splf_BIT; + if (ParseRules::is_wslfcr(c)) + tparseRulesCType[c] |= is_wslfcr_BIT; + if (ParseRules::is_eow(c)) + tparseRulesCType[c] |= is_eow_BIT; + if (ParseRules::is_token(c)) + tparseRulesCType[c] |= is_token_BIT; + if (ParseRules::is_wildmat(c)) + tparseRulesCType[c] |= is_wildmat_BIT; + if (ParseRules::is_sep(c)) + tparseRulesCType[c] |= is_sep_BIT; + if (ParseRules::is_empty(c)) + tparseRulesCType[c] |= is_empty_BIT; + if (ParseRules::is_alnum(c)) + tparseRulesCType[c] |= is_alnum_BIT; + if (ParseRules::is_space(c)) + tparseRulesCType[c] |= is_space_BIT; + if (ParseRules::is_control(c)) + tparseRulesCType[c] |= is_control_BIT; + if (ParseRules::is_mime_sep(c)) + tparseRulesCType[c] |= is_mime_sep_BIT; + if (ParseRules::is_http_field_name(c)) + tparseRulesCType[c] |= is_http_field_name_BIT; + if (ParseRules::is_http_field_value(c)) + tparseRulesCType[c] |= is_http_field_value_BIT; + } + + FILE *fp = fopen("ParseRulesCType", "w"); + for (c = 0; c < 256; c++) { + fprintf(fp, "/* %3d (%c) */\t", c, (isprint(c) ? c : '?')); + fprintf(fp, "0x%08X%c\t\t", tparseRulesCType[c], (c != 255 ? ',' : ' ')); + fprintf(fp, "/* [%s] */\n", uint_to_binary((unsigned int) (tparseRulesCType[c]))); + } + fclose(fp); + fp = fopen("ParseRulesCTypeToUpper", "w"); + for (c = 0; c < 256; c++) + fprintf(fp, "%d%c\n", tparseRulesCTypeToUpper[c], c != 255 ? ',' : ' '); + fclose(fp); + fp = fopen("ParseRulesCTypeToLower", "w"); + for (c = 0; c < 256; c++) + fprintf(fp, "%d%c\n", tparseRulesCTypeToLower[c], c != 255 ? ',' : ' '); + fclose(fp); + + return (0); +} diff --git a/lib/ts/DAllocator.cc b/lib/ts/DAllocator.cc new file mode 100644 index 00000000..4bac09d5 --- /dev/null +++ b/lib/ts/DAllocator.cc @@ -0,0 +1,253 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + + DAllocator.h + + A pool allocator with some debugging feature including double free + detection and integration with the mem-tracker + + + ****************************************************************************/ + +#include "DAllocator.h" +#include "Resource.h" + +#define DALLOC_START_ELEMENTS 32 +#define DALLOC_DESCRIPTOR_MAGIC 0x343bbbff + +#define DALLOC_RED_ZONE_BYTES 16 +#define DALLOC_MAKE_RED_ZONE(x) (uint32_t) x | 0x189dda3f + +void +write_red_zone(void *el, int el_size) +{ + + if (el_size < DALLOC_RED_ZONE_BYTES * 2) { + return; + } + + uint32_t red = DALLOC_MAKE_RED_ZONE(el); + + + int i; + uint32_t *write_ptr = (uint32_t *) el; + + // Redzone the front the object + for (i = 0; i < DALLOC_RED_ZONE_BYTES / sizeof(uint32_t); i++) { + *write_ptr = red; + write_ptr++; + } + + // Redzone the back of the object + write_ptr = (uint32_t *) (((char *) el) + el_size - DALLOC_RED_ZONE_BYTES); + for (i = 0; i < DALLOC_RED_ZONE_BYTES / sizeof(uint32_t); i++) { + *write_ptr = red; + write_ptr++; + } +} + +int +check_red_zone(void *el, int el_size) +{ + + if (el_size < DALLOC_RED_ZONE_BYTES * 2) { + return 1; + } + + uint32_t red = DALLOC_MAKE_RED_ZONE(el); + + int i; + uint32_t *read_ptr = (uint32_t *) el; + + // Check the front the object + for (i = 0; i < DALLOC_RED_ZONE_BYTES / sizeof(uint32_t); i++) { + if (*read_ptr != red) { + return 0; + } + read_ptr++; + } + + // Check the back of the object + read_ptr = (uint32_t *) (((char *) el) + el_size - DALLOC_RED_ZONE_BYTES); + for (i = 0; i < DALLOC_RED_ZONE_BYTES / sizeof(uint32_t); i++) { + if (*read_ptr != red) { + return 0; + } + read_ptr++; + } + + return 1; +} + +AllocPoolDescriptor::AllocPoolDescriptor():region_start(NULL), region_end(NULL), num_el(0), el_size(0), descriptors(NULL) +{ +} + +void +AllocPoolDescriptor::add_elements(int num, DAllocator * da) +{ + num_el = num; + el_size = da->el_size; + + int size = el_size * num; + region_start = ink_memalign(da->alignment, size); + region_end = ((char *) region_start) + size; + + if (unlikely((descriptors = (AllocDescriptor *) xmalloc(sizeof(AllocDescriptor) * num_el)) == 0)) { + ink_fatal(1, "AllocPoolDescriptor::add_elements: couldn't allocate %d bytes", + (int) (sizeof(AllocDescriptor) * num_el)); + } + + for (int i = 0; i < num_el; i++) { + descriptors[i].magic = DALLOC_DESCRIPTOR_MAGIC; + descriptors[i].link.next = NULL; + descriptors[i].link.prev = NULL; + descriptors[i].state = DALLOC_FREE; + descriptors[i].el = ((char *) region_start) + (el_size * i); + ink_assert(descriptors[i].el < region_end); + + write_red_zone(descriptors[i].el, da->el_size); + da->free_list.push(descriptors + i); + } +} + +void +DAllocator::init(const char *name_arg, unsigned type_size, unsigned alignment_arg) +{ + + // We can change sizes if we haven't allocated anything yet + bool re_init_ok = (pools.head == NULL && free_list.head == NULL); + + if (name == NULL) { + ink_mutex_init(&mutex, name_arg); + name = (name_arg == 0) ? name_arg : "unknown"; + } else { + name = name_arg; + } + + if (alignment == 0 || re_init_ok) { + alignment = alignment_arg; + } else { + ink_release_assert(alignment); + } + + if (el_size == 0 || re_init_ok) { + el_size = type_size; + } else { + ink_release_assert(el_size == type_size); + } + +} + +void +DAllocator::add_pool(int num_el) +{ + + AllocPoolDescriptor *p; + p = NEW(new AllocPoolDescriptor); + p->add_elements(num_el, this); + pools.push(p); +} + +void * +DAllocator::alloc() +{ + + AllocDescriptor *descriptor; + + ink_mutex_acquire(&mutex); + + if (!free_list.head) { + // Nothing on freelist + int new_elements; + if (pools.head) { + new_elements = pools.head->num_el * 2; + } else { + new_elements = DALLOC_START_ELEMENTS; + } + add_pool(new_elements); + } + + + descriptor = free_list.pop(); + + ink_mutex_release(&mutex); + + ink_assert(descriptor); + + ink_assert(descriptor->state == DALLOC_FREE); + descriptor->state = DALLOC_IN_USE; + + ink_release_assert(check_red_zone(descriptor->el, el_size) == 1); + + return descriptor->el; +} + +void +DAllocator::free(void *to_free) +{ + + ink_mutex_acquire(&mutex); + + // First thing to do is find the pool descriptor for this element + AllocPoolDescriptor *p = pools.head; + + while (p) { + + if (to_free < p->region_end && to_free >= p->region_start) + break; + + p = p->link.next; + } + + // If there is no matching pool, this a bogus free + ink_release_assert(p); + + // Now find the element descriptor for this element + int region_offset = (int) (((char *) to_free) - ((char *) p->region_start)); + ink_assert(region_offset >= 0); + ink_release_assert(region_offset % el_size == 0); + int index = region_offset / el_size; + + AllocDescriptor *d = p->descriptors + index; + ink_release_assert(d->magic == DALLOC_DESCRIPTOR_MAGIC); + ink_release_assert(d->state == DALLOC_IN_USE); + ink_release_assert(d->el == to_free); + + d->state = DALLOC_FREE; + write_red_zone(d->el, el_size); + + free_list.enqueue(d); + + ink_mutex_release(&mutex); +} + +DAllocator::DAllocator():name(NULL), alignment(0), el_size(0) +{ +} + +DAllocator::~DAllocator() +{ +} diff --git a/lib/ts/DAllocator.h b/lib/ts/DAllocator.h new file mode 100644 index 00000000..853e041d --- /dev/null +++ b/lib/ts/DAllocator.h @@ -0,0 +1,102 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + + DAllocator.h + + A pool allocator with some debugging feature including double free + detection + + The basic idea behind this allocator is that you can store information + about each allocated block separately from the block allowing easy + double free detection. It's also easy to integrate with the + memory tracker but I found most fast allocated stuff doesn't lend + it self well to this approach as it's typically allocated through + wrapper functions + + + ****************************************************************************/ + +#ifndef _D_ALLOCATOR_H_ +#define _D_ALLOCATOR_H_ + +#include "List.h" +#include "ink_mutex.h" + +enum DallocState +{ + DALLOC_UNKNOWN = 0, + DALLOC_FREE, + DALLOC_IN_USE +}; + +struct AllocDescriptor +{ + int magic; + DallocState state; + void *el; + + LINK(AllocDescriptor, link); // list of free elements +}; + +struct DAllocator; +struct AllocPoolDescriptor +{ + AllocPoolDescriptor(); + void add_elements(int num, DAllocator * da); + + void *region_start; + void *region_end; + int num_el; + int el_size; + + AllocDescriptor *descriptors; + + SLINK(AllocPoolDescriptor, link); +}; + +struct DAllocator +{ + ink_mutex mutex; + const char *name; + int alignment; + int el_size; + + SList(AllocPoolDescriptor,link) pools; + Que(AllocDescriptor,link) free_list; + + DAllocator(); + ~DAllocator(); + + void init(const char *name, unsigned type_size, unsigned alignment); + void *alloc(); + void free(void *to_free); + +private: + void add_pool(int num_el); +}; + + + +#endif diff --git a/lib/ts/Diags.cc b/lib/ts/Diags.cc new file mode 100644 index 00000000..388b9d92 --- /dev/null +++ b/lib/ts/Diags.cc @@ -0,0 +1,569 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Diags.cc + + This file contains code to manipulate run-time diagnostics, and print + warnings and errors at runtime. Action tags and debugging tags are + supported, allowing run-time conditionals affecting diagnostics. + + Joe User should only need to use the macros at the bottom of Diags.h + + + ****************************************************************************/ + +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_unused.h" +#include "ink_error.h" +#include "ink_assert.h" +#include "ink_time.h" +#include "ink_hrtime.h" +#include "Diags.h" +#include "Compatability.h" + + +int diags_on_for_plugins = 0; +bool DiagsConfigState::enabled[2] = { false, false }; + +// Global, used for all diagnostics +inkcoreapi Diags *diags = NULL; + +////////////////////////////////////////////////////////////////////////////// +// +// char *SrcLoc::str(char *buf, int buflen) +// +// This method takes a SrcLoc source location data structure and +// converts it to a human-readable representation, in the buffer +// with length . The buffer will always be NUL-terminated, and +// must always have a length of at least 1. The buffer address is +// returned on success. The routine will only fail if the SrcLoc is +// not valid, or the buflen is less than 1. +// +////////////////////////////////////////////////////////////////////////////// + +char * +SrcLoc::str(char *buf, int buflen) +{ + if (!valid || buflen < 1) + return (NULL); + if (func != NULL) { + snprintf(buf, buflen, "%s:%d (%s)", file, line, func); + } else { + snprintf(buf, buflen, "%s:%d", file, line); + } + buf[buflen - 1] = NUL; + return (buf); +} + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Diags::Diags(char *bdt, char *bat) +// +// This is the constructor for the Diags class. The constructor takes +// two strings called the "base debug tags" (bdt) and the +// "base action tags" (bat). These represent debug/action overrides, +// to override the records.config values. They current come from +// command-line options. +// +// If bdt is not NULL, and not "", it overrides records.config settings. +// If bat is not NULL, and not "", it overrides records.config settings. +// +// When the constructor is done, records.config callbacks will be set, +// the initial values read, and the Diags instance will be ready to use. +// +////////////////////////////////////////////////////////////////////////////// + +Diags::Diags(char *bdt, char *bat, FILE * _diags_log_fp): +diags_log_fp(_diags_log_fp), show_location(0) +{ + int i; + + magic = DIAGS_MAGIC; + cleanup_func = NULL; + ink_mutex_init(&tag_table_lock, "Diags::tag_table_lock"); + + //////////////////////////////////////////////////////// + // initialize the default, base debugging/action tags // + //////////////////////////////////////////////////////// + + base_debug_tags = NULL; + base_action_tags = NULL; + if (bdt && *bdt) { + base_debug_tags = xstrdup(bdt); + } + if (bat && *bat) { + base_action_tags = xstrdup(bat); + } + + config.enabled[DiagsTagType_Debug] = (base_debug_tags != NULL); + config.enabled[DiagsTagType_Action] = (base_action_tags != NULL); + diags_on_for_plugins = config.enabled[DiagsTagType_Debug]; + + for (i = 0; i < DiagsLevel_Count; i++) { + config.outputs[i].to_stdout = true; + config.outputs[i].to_stderr = false; + config.outputs[i].to_syslog = true; + config.outputs[i].to_diagslog = true; + } + + ////////////////////////////////////////////////////////////////// + // start off with empty tag tables, will build in reconfigure() // + ////////////////////////////////////////////////////////////////// + + activated_tags[DiagsTagType_Debug] = NULL; + activated_tags[DiagsTagType_Action] = NULL; + prefix_str = ""; + +} + +Diags::~Diags() +{ + diags_log_fp = NULL; + + xfree(base_debug_tags); + xfree(base_action_tags); + + deactivate_all(DiagsTagType_Debug); + deactivate_all(DiagsTagType_Action); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// void Diags::print_va(...) +// +// This is the lowest-level diagnostic printing routine, that does the +// work of formatting and outputting diagnostic and error messages, +// in the standard format. +// +// This routine takes an optional , which is printed in +// parentheses if its value is not NULL. It takes a , +// which is converted to a prefix string, unless is set to +// a non-NULL value (in which case is used in preference. +// print_va takes an optional source location structure pointer , +// which can be NULL. If is not NULL, the source code location +// is converted to a string, and printed between angle brackets. +// Finally, it takes a printf format string , and a +// va_list list of varargs. +// +// This routine outputs to all of the output targets enabled for this +// debugging level in config.outputs[diags_level]. Many higher level +// diagnosting printing routines are built upon print_va, including: +// +// void print(...) +// void log_va(...) +// void log(...) +// +////////////////////////////////////////////////////////////////////////////// + +void +Diags::print_va(const char *debug_tag, DiagsLevel diags_level, + const char *prefix, SrcLoc * loc, + const char *format_string, va_list ap) +{ + struct timeval tp; + const char *prefix_string, *s; + char *buffer, *d, timestamp_buf[48]; + char format_buf[1024], format_buf_w_ts[1024], *end_of_format; + + //////////////////////////////////////////////////////////////////////// + // there are 2 format buffers that hold a printf-style format string // + // format_buf contains : () // + // and format_buf_w_ts has the same thing with a prepended timestamp. // + //////////////////////////////////////////////////////////////////////// + + format_buf[0] = NUL; + format_buf_w_ts[0] = NUL; + + ///////////////////////////////////////////////////// + // format_buf holds 1024 characters, end_of_format // + // points to the current available character // + ///////////////////////////////////////////////////// + + end_of_format = format_buf; + *end_of_format = NUL; + + // add the thread id + pthread_t id = pthread_self(); + end_of_format += snprintf(end_of_format, sizeof(format_buf), "{%" PRIu64 "} ", (uint64_t) id); + + //////////////////////////////// + // start with the user prefix // + //////////////////////////////// + + prefix_string = (prefix ? prefix : level_name(diags_level)); + + for (s = prefix_string; *s; *end_of_format++ = *s++); + *end_of_format++ = ':'; + *end_of_format++ = ' '; + + ///////////////////////////// + // append location, if any // + ///////////////////////////// + + if (loc && loc->valid) { + char *lp, buf[256]; + lp = loc->str(buf, sizeof(buf)); + if (lp) { + *end_of_format++ = '<'; + for (s = lp; *s; *end_of_format++ = *s++); + *end_of_format++ = '>'; + *end_of_format++ = ' '; + } + } + ////////////////////////// + // append debugging tag // + ////////////////////////// + + if (debug_tag) { + *end_of_format++ = '('; + for (s = debug_tag; *s; *end_of_format++ = *s++); + *end_of_format++ = ')'; + *end_of_format++ = ' '; + } + ////////////////////////////////////////////////////// + // append original format string, and NUL terminate // + ////////////////////////////////////////////////////// + + for (s = format_string; *s; *end_of_format++ = *s++); + *end_of_format++ = NUL; + + + ////////////////////////////////////////////////////////////////// + // prepend timestamp into the timestamped version of the buffer // + ////////////////////////////////////////////////////////////////// + + ink_gethrtimeofday(&tp, NULL); + time_t cur_clock = (time_t) tp.tv_sec; + buffer = ink_ctime_r(&cur_clock, timestamp_buf); + snprintf(&(timestamp_buf[19]), (sizeof(timestamp_buf) - 20), ".%03d", (int) (tp.tv_usec / 1000)); + + d = format_buf_w_ts; + *d++ = '['; + for (int i = 4; buffer[i]; i++) + *d++ = buffer[i]; + *d++ = ']'; + *d++ = ' '; + + //const char mgmt_str[] = "Manager "; + for (int k = 0; prefix_str[k]; k++) + *d++ = prefix_str[k]; + for (s = format_buf; *s; *d++ = *s++); + *d++ = NUL; + + ////////////////////////////////////// + // now, finally, output the message // + ////////////////////////////////////// + + lock(); + if (config.outputs[diags_level].to_diagslog) { + if (diags_log_fp) { + va_list ap_scratch; + va_copy(ap_scratch, ap); + buffer = format_buf_w_ts; + vfprintf(diags_log_fp, buffer, ap_scratch); + { + int len = strlen(buffer); + if (len > 0 && buffer[len - 1] != '\n') { + putc('\n', diags_log_fp); + } + } + } + } + + if (config.outputs[diags_level].to_stdout) { + va_list ap_scratch; + va_copy(ap_scratch, ap); + buffer = format_buf_w_ts; + vfprintf(stdout, buffer, ap_scratch); + { + int len = strlen(buffer); + if (len > 0 && buffer[len - 1] != '\n') { + putc('\n', stdout); + } + } + } + + if (config.outputs[diags_level].to_stderr) { + va_list ap_scratch; + va_copy(ap_scratch, ap); + buffer = format_buf_w_ts; + vfprintf(stderr, buffer, ap_scratch); + { + int len = strlen(buffer); + if (len > 0 && buffer[len - 1] != '\n') { + putc('\n', stderr); + } + } + } + +#if !defined(freebsd) + unlock(); +#endif + + if (config.outputs[diags_level].to_syslog) { + int priority; + char syslog_buffer[2048]; + + switch (diags_level) { + case DL_Diag: + case DL_Debug: + priority = LOG_DEBUG; + + break; + case DL_Status: + priority = LOG_INFO; + break; + case DL_Note: + priority = LOG_NOTICE; + break; + case DL_Warning: + priority = LOG_WARNING; + break; + case DL_Error: + priority = LOG_ERR; + break; + case DL_Fatal: + priority = LOG_CRIT; + break; + case DL_Alert: + priority = LOG_ALERT; + break; + case DL_Emergency: + priority = LOG_EMERG; + break; + default: + priority = LOG_NOTICE; + break; + } + vsnprintf(syslog_buffer, sizeof(syslog_buffer) - 1, format_buf, ap); + syslog(priority, "%s", syslog_buffer); + } +#if defined(freebsd) + unlock(); +#endif +} + + +////////////////////////////////////////////////////////////////////////////// +// +// bool Diags::tag_activated(char * tag, DiagsTagType mode) +// +// This routine inquires if a particular in the tag table of +// type is activated, returning true if it is, false if it +// isn't. If is NULL, true is returned. The call uses a lock +// to get atomic access to the tag tables. +// +////////////////////////////////////////////////////////////////////////////// + +bool +Diags::tag_activated(const char *tag, DiagsTagType mode) +{ + bool activated = false; + + if (tag == NULL) + return (true); + + lock(); + if (activated_tags[mode]) + activated = (activated_tags[mode]->match(tag) != -1); + unlock(); + + return (activated); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// void Diags::activate_taglist(char * taglist, DiagsTagType mode) +// +// This routine adds all tags in the vertical-bar-seperated taglist +// to the tag table of type . Each addition is done under a lock. +// If an individual tag is already set, that tag is ignored. If +// is NULL, this routine exits immediately. +// +////////////////////////////////////////////////////////////////////////////// + +void +Diags::activate_taglist(char *taglist, DiagsTagType mode) +{ + if (taglist) { + lock(); + if (activated_tags[mode]) { + delete activated_tags[mode]; + } + activated_tags[mode] = NEW(new DFA); + activated_tags[mode]->compile(taglist); + unlock(); + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// void Diags::deactivate_all(DiagsTagType mode) +// +// This routine deactivates all tags in the tag table of type . +// The deactivation is done under a lock. When done, the taglist will +// be empty. +// +////////////////////////////////////////////////////////////////////////////// + +void +Diags::deactivate_all(DiagsTagType mode) +{ + lock(); + if (activated_tags[mode]) { + delete activated_tags[mode]; + activated_tags[mode] = NULL; + } + unlock(); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// const char *Diags::level_name(DiagsLevel dl) +// +// This routine returns a string name corresponding to the error +// level
, suitable for us as an output log entry prefix. +// +////////////////////////////////////////////////////////////////////////////// + +const char * +Diags::level_name(DiagsLevel dl) +{ + switch (dl) { + case DL_Diag: + return ("DIAG"); + case DL_Debug: + return ("DEBUG"); + case DL_Status: + return ("STATUS"); + case DL_Note: + return ("NOTE"); + case DL_Warning: + return ("WARNING"); + case DL_Error: + return ("ERROR"); + case DL_Fatal: + return ("FATAL"); + case DL_Alert: + return ("ALERT"); + case DL_Emergency: + return ("EMERGENCY"); + default: + return ("DIAG"); + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// void Diags::dump(FILE *fp) +// +////////////////////////////////////////////////////////////////////////////// + +void +Diags::dump(FILE * fp) +{ + int i; + + fprintf(fp, "Diags:\n"); + fprintf(fp, " debug.enabled: %d\n", config.enabled[DiagsTagType_Debug]); + fprintf(fp, " debug default tags: '%s'\n", (base_debug_tags ? base_debug_tags : "NULL")); + fprintf(fp, " action.enabled: %d\n", config.enabled[DiagsTagType_Action]); + fprintf(fp, " action default tags: '%s'\n", (base_action_tags ? base_action_tags : "NULL")); + fprintf(fp, " outputs:\n"); + for (i = 0; i < DiagsLevel_Count; i++) { + fprintf(fp, " %10s [stdout=%d, stderr=%d, syslog=%d, diagslog=%d]\n", + level_name((DiagsLevel) i), + config.outputs[i].to_stdout, + config.outputs[i].to_stderr, config.outputs[i].to_syslog, config.outputs[i].to_diagslog); + } +} + + + +void +DiagsDClosure::operator() (const char *tag, const char *format_string ...) +{ + va_list ap; + va_start(ap, format_string); + SrcLoc *lp = (diags->show_location ? &src_location : NULL); + diags->log_va(tag, level, NULL, lp, format_string, ap); + va_end(ap); +} + +// location optionally printed +void +DiagsDClosure::operator() (const char *tag, int show_loc, const char *format_string ...) +{ + va_list ap; + va_start(ap, format_string); + SrcLoc *lp = ((show_loc || diags->show_location) ? &src_location : NULL); + diags->log_va(tag, level, NULL, lp, format_string, ap); + va_end(ap); +} + + +void +DiagsEClosure::operator() (const char *format_string ...) +{ + va_list ap; + va_start(ap, format_string); + SrcLoc *lp = (diags->show_location ? &src_location : NULL); + diags->print_va(NULL, level, NULL, lp, format_string, ap); + va_end(ap); + va_start(ap, format_string); + if (DiagsLevel_IsTerminal(level)) { + if (diags->cleanup_func) + diags->cleanup_func(); + ink_fatal_va(1, (char *) format_string, ap); + } + va_end(ap); +} + +// location optionally printed +void +DiagsEClosure::operator() (int show_loc, const char *format_string ...) +{ + va_list ap; + va_start(ap, format_string); + SrcLoc *lp = ((show_loc || diags->show_location) ? &src_location : NULL); + diags->print_va(NULL, level, NULL, lp, format_string, ap); + va_end(ap); + va_start(ap, format_string); + if (DiagsLevel_IsTerminal(level)) { + if (diags->cleanup_func) + diags->cleanup_func(); + ink_fatal_va(1, (char *) format_string, ap); + } + va_end(ap); +} diff --git a/lib/ts/Diags.h b/lib/ts/Diags.h new file mode 100644 index 00000000..1e5ba83a --- /dev/null +++ b/lib/ts/Diags.h @@ -0,0 +1,446 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Diags.h + + This file contains code to manipulate run-time diagnostics, and print + warnings and errors at runtime. Action tags and debugging tags are + supported, allowing run-time conditionals affecting diagnostics. + + + ****************************************************************************/ + +#ifndef __DIAGS_H___ +#define __DIAGS_H___ + +#include +#include "ink_bool.h" +#include "ink_error.h" +#include "ink_mutex.h" +#include "Regex.h" +#include "ink_apidefs.h" + +#define DIAGS_MAGIC 0x12345678 + +class Diags; + +// extern int diags_on_for_plugins; +typedef enum +{ + DiagsTagType_Debug = 0, // do not renumber --- used as array index + DiagsTagType_Action = 1 +} DiagsTagType; + +struct DiagsModeOutput +{ + bool to_stdout; + bool to_stderr; + bool to_syslog; + bool to_diagslog; +}; + +typedef enum +{ // do not renumber --- used as array index + DL_Diag = 0, // process does not die + DL_Debug, // process does not die + DL_Status, // process does not die + DL_Note, // process does not die + DL_Warning, // process does not die + DL_Error, // process does not die + DL_Fatal, // causes process termination + DL_Alert, // causes process termination + DL_Emergency, // causes process termination + DL_Undefined // must be last, used for size! +} DiagsLevel; + +#define DiagsLevel_Count DL_Undefined + +#define DiagsLevel_IsTerminal(_l) (((_l) >= DL_Fatal) && ((_l) < DL_Undefined)) + +#ifdef TS_USE_DIAGS +// Cleanup Function Prototype - Called before ink_fatal to +// cleanup process state +typedef void (*DiagsCleanupFunc) (); + +struct DiagsConfigState +{ + // this is static to eliminate many loads from the critical path + static bool enabled[2]; // one debug, one action + DiagsModeOutput outputs[DiagsLevel_Count]; // where each level prints +}; + + +////////////////////////////////////////////////////////////////////////////// +// +// class SrcLoc +// +// The SrcLoc class wraps up a source code location, including file +// name, function name, and line number, and contains a method to +// format the result into a string buffer. +// +////////////////////////////////////////////////////////////////////////////// + +class SrcLoc +{ +public: + bool valid; + const char *file; + const char *func; + int line; + + void set(const char *_file, const char *_func, int _line) + { + valid = true; + file = _file; + func = _func; + line = _line; + } + + SrcLoc(const char *_file, const char *_func, int _line) + { + set(_file, _func, _line); + } + +SrcLoc():valid(false), file(NULL), func(NULL), line(0) { + } + ~SrcLoc() { + }; + + char *str(char *buf, int buflen); +}; + + +////////////////////////////////////////////////////////////////////////////// +// +// class Diags +// +// The Diags class is used for global configuration of the run-time +// diagnostics system. This class provides the following services: +// +// * run-time notices, debugging, warnings, errors +// * debugging tags to selectively enable & disable diagnostics +// * action tags to selectively enable & disable code paths +// * configurable output to stdout, stderr, syslog, error logs +// * traffic_manager interface supporting on-the-fly reconfiguration +// +////////////////////////////////////////////////////////////////////////////// + +class Diags +{ +public: + Diags(char *base_debug_tags, char *base_action_tags, FILE * _diags_log_fp = NULL); + ~Diags(); + + FILE *diags_log_fp; + unsigned int magic; + volatile DiagsConfigState config; + int show_location; + DiagsCleanupFunc cleanup_func; + const char *prefix_str; + + /////////////////////////// + // conditional debugging // + /////////////////////////// + + bool on(DiagsTagType mode = DiagsTagType_Debug) { + return (config.enabled[mode]); + } + bool on(const char *tag, DiagsTagType mode = DiagsTagType_Debug) { + return (config.enabled[mode] && tag_activated(tag, mode)); + } + + ///////////////////////////////////// + // low-level tag inquiry functions // + ///////////////////////////////////// + + inkcoreapi bool tag_activated(const char *tag, DiagsTagType mode = DiagsTagType_Debug); + + ///////////////////////////// + // raw printing interfaces // + ///////////////////////////// + + const char *level_name(DiagsLevel dl); + + inkcoreapi void print_va(const char *tag, DiagsLevel dl, const char *prefix, + SrcLoc * loc, const char *format_string, va_list ap); + + + ////////////////////////////// + // user printing interfaces // + ////////////////////////////// + + void print(const char *tag, DiagsLevel dl, const char *prefix, SrcLoc * loc, const char *format_string, ...) + { + va_list ap; + va_start(ap, format_string); + print_va(tag, dl, prefix, loc, format_string, ap); + va_end(ap); + } + + /////////////////////////////////////////////////////////////////////// + // user diagnostic output interfaces --- enabled on or off based // + // on the value of the enable flag, and the state of the debug tags. // + /////////////////////////////////////////////////////////////////////// + + void log_va(const char *tag, DiagsLevel dl, const char *prefix, SrcLoc * loc, const char *format_string, va_list ap) + { + if (!on(tag)) + return; + print_va(tag, dl, prefix, loc, format_string, ap); + } + + void log(const char *tag, DiagsLevel dl, const char *prefix, SrcLoc * loc, const char *format_string, ...) + { + va_list ap; + va_start(ap, format_string); + log_va(tag, dl, prefix, loc, format_string, ap); + va_end(ap); + } + + void dump(FILE * fp = stdout); + + void activate_taglist(char *taglist, DiagsTagType mode = DiagsTagType_Debug); + + void deactivate_all(DiagsTagType mode = DiagsTagType_Debug); + + char *base_debug_tags; // internal copy of default debug tags + char *base_action_tags; // internal copy of default action tags + +private: + ink_mutex tag_table_lock; // prevents reconfig/read races + DFA *activated_tags[2]; // 1 table for debug, 1 for action + + void lock() + { + ink_mutex_acquire(&tag_table_lock); + } + void unlock() + { + ink_mutex_release(&tag_table_lock); + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// +// class DiagsBaseClosure +// class DiagsDClosure +// class DiagsEClosure +// +// The following classes are hacks. Their whole raison d'etre is to +// make a macro that substitutes in __LINE__ and __FILE__ location +// info in addition to the normal diagnostic logging arguments. But, +// the lame cpp preprocessor doesn't let us represent and substitute +// variable numbers of arguments, so we can't do this. +// +// Instead, a DiagsClosure is created at a point in the code (usually +// within a macro that adds __LINE__ and __FILE__). DiagsClosure acts +// as a closure, wrapping up this location context, and supporting +// an operator() method that takes all the normal diagnostic log args. +// +// If the end, we can just say: +// +// Debug("http", "status = %d", status); +// +// This macro expands into an initialized creation of a DiagsClosure +// that saves the location of the Debug macro & debug level, and +// in effect invokes itself as a function of the original arguments: +// +// if (diags->on()) +// (*(new DiagsDClosure(diags,DL_Debug,_FILE_,_FUNC_,_LINE_))) +// ("http", "status = %d", status) +// +// If you know a way to make this directly into a macro structure, and +// bypass the DiagsClosure closures, be my guest... +// +// The DiagsDClosure and DiagsEClosure classes differ in that the +// DiagsDClosure supports debug tags, and DiagsEClosure does not. +// +////////////////////////////////////////////////////////////////////////////// + +class DiagsBaseClosure +{ +public: + Diags *diags; + DiagsLevel level; + SrcLoc src_location; + + DiagsBaseClosure(Diags * d, DiagsLevel l, const char *_file, const char *_func, int _line) + { + diags = d; + level = l; + src_location.file = _file; + src_location.func = _func; + src_location.line = _line; + src_location.valid = true; + } + + ~DiagsBaseClosure() + { } +}; + + +class DiagsDClosure:public DiagsBaseClosure +{ +public: + DiagsDClosure(Diags * d, DiagsLevel l, const char *file, const char *func, int line):DiagsBaseClosure(d, l, file, func, line) + { } + + ~DiagsDClosure() + { } + + // default: no location printed + void inkcoreapi operator() (const char *tag, const char *format_string ...); + + // location optionally printed + void operator() (const char *tag, int show_loc, const char *format_string ...); +}; + +// debug closures support debug tags + +// error closures do not support debug tags +class DiagsEClosure:public DiagsBaseClosure +{ +public: + DiagsEClosure(Diags * d, DiagsLevel l, const char *file, const char *func, int line):DiagsBaseClosure(d, l, file, func, line) + { } + + ~DiagsEClosure() + { } + + // default: no location printed + void inkcoreapi operator() (const char *format_string ...); + + // location optionally printed + void operator() (int show_loc, const char *format_string ...); +}; + +////////////////////////////////////////////////////////////////////////// +// // +// Macros // +// // +// The following are diagnostic macros that wrap up the compiler // +// __FILE__, __FUNCTION__, and __LINE__ macros into closures // +// and then invoke the closure on the remaining arguments. // +// // +// This closure hack is done, because the cpp preprocessor doesn't // +// support manipulation and union of varargs parameters. // +// // +////////////////////////////////////////////////////////////////////////// + +#if !defined (__GNUC__) +#ifndef __FUNCTION__ +#define __FUNCTION__ NULL +#endif +#endif + +extern inkcoreapi Diags *diags; + +#define DTA(l) diags,l,__FILE__,__FUNCTION__,__LINE__ +inline void +dummy_debug(char *dummy_arg ...) +{ + (void) dummy_arg; +} +inline void +dummy_debug(const char *dummy_arg ...) +{ + (void) dummy_arg; +} + +#if TS_USE_DIAGS +#define Diag if (diags->on()) DiagsDClosure(DTA(DL_Diag)) /*args */ +#define Debug if (diags->on()) DiagsDClosure(DTA(DL_Debug)) /*args */ +#define DebugOn DiagsDClosure(DTA(DL_Debug)) /*args */ +#else +#define Diag if (0) dummy_debug +#define Debug if (0) dummy_debug +#define DebugOn if (0) dummy_debug +#endif + +#define Status DiagsEClosure(DTA(DL_Status)) /*(args...) */ +#define Note DiagsEClosure(DTA(DL_Note)) /*(args...) */ +#define Warning DiagsEClosure(DTA(DL_Warning)) /*(args...) */ +#define Error DiagsEClosure(DTA(DL_Error)) /*(args...) */ +#define Fatal DiagsEClosure(DTA(DL_Fatal)) /*(args...) */ +#define Alert DiagsEClosure(DTA(DL_Alert)) /*(args...) */ +#define Emergency DiagsEClosure(DTA(DL_Emergency)) /*(args...) */ + +#if TS_USE_DIAGS +#define is_debug_tag_set(_t) diags->on(_t,DiagsTagType_Debug) +#define is_action_tag_set(_t) diags->on(_t,DiagsTagType_Action) +#define debug_tag_assert(_t,_a) (is_debug_tag_set(_t) ? (ink_release_assert(_a), 0) : 0) +#define action_tag_assert(_t,_a) (is_action_tag_set(_t) ? (ink_release_assert(_a), 0) : 0) +#define is_diags_on(_t) diags->on(_t) +#else +#define is_debug_tag_set(_t) 0 +#define is_action_tag_set(_t) 0 +#define debug_tag_assert(_t,_a) /**/ +#define action_tag_assert(_t,_a) /**/ +#endif +#define stat_debug_assert(_tst) (void)((_tst) || (Warning(#_tst), debug_tag_assert("stat_check",! #_tst), 0)) +#else // TS_USE_DIAGS + +class Diags +{ +public: + Diags(char *base_debug_tags, char *base_action_tags, FILE * diags_log_fp = NULL) { + } + + bool on(DiagsTagType mode = DiagsTagType_Debug) { + return false; + } + + bool on(const char *tag, DiagsTagType mode = DiagsTagType_Debug) { + return false; + } +}; + +extern inkcoreapi Diags *diags; + +#define Warning ink_warning +#define Note ink_notice +#define Status ink_notice +#define Fatal ink_fatal_die +#define Error ink_error +#define Alert ink_error +#define Emergency ink_fatal_die + +inline void +dummy_debug(char *dummy_arg ...) +{ + (void) dummy_arg; +} + +#define Diag if (0) dummy_debug +#define Debug if (0) dummy_debug +#define DebugOn if (0) dummy_debug +#define is_debug_tag_set(_t) 0 +#define is_action_tag_set(_t) 0 +#define debug_tag_assert(_t,_a) /**/ +#define action_tag_assert(_t,_a) +#define is_diags_on(_t) 0 +#endif // TS_USE_DIAGS +#endif /*_Diags_h_*/ diff --git a/lib/ts/DynArray.h b/lib/ts/DynArray.h new file mode 100644 index 00000000..3820d75a --- /dev/null +++ b/lib/ts/DynArray.h @@ -0,0 +1,195 @@ +/** @file + + Dynamic Array Implementation used by Regex.cc + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __DYN_ARRAY_H__ +#define __DYN_ARRAY_H__ + + +#include "Resource.h" + + +template class DynArray { +public: + DynArray(const T * val = 0, intptr_t initial_size = 0); + ~DynArray(); + +#ifndef __GNUC__ + operator const T *() const; +#endif + operator T *(); + T & operator[](intptr_t idx); + T & operator()(intptr_t idx); + T *detach(); + T defvalue() const; + intptr_t length(); + void clear(); + void set_length(intptr_t i); + +private: + void resize(intptr_t new_size); + +private: + T * data; + const T *default_val; + int size; + int pos; +}; + + +template inline DynArray::DynArray(const T * val, intptr_t initial_size) + : +data(NULL), +default_val(val), +size(0), +pos(-1) +{ + if (initial_size > 0) { + int i = 1; + + while (i < initial_size) + i <<= 1; + + resize(i); + } + +} + +template inline DynArray::~DynArray() +{ + if (data) { + delete[]data; + } +} + +#ifndef __GNUC__ +template inline DynArray::operator const T *() +const +{ + return + data; +} +#endif + +template < + class + T > + inline + DynArray < + T >::operator +T * () +{ + return data; +} + +template inline T & DynArray::operator [](intptr_t idx) { + return data[idx]; +} + +template inline T & DynArray::operator ()(intptr_t idx) { + if (idx >= size) { + intptr_t new_size; + + if (size == 0) { + new_size = 64; + } else { + new_size = size * 2; + } + + if (idx >= new_size) { + new_size = idx + 1; + } + + resize(new_size); + } + + if (idx > pos) { + pos = idx; + } + + return data[idx]; +} + +template inline T * DynArray::detach() +{ + T *d; + + d = data; + data = NULL; + + return d; +} + +template inline T DynArray::defvalue() const +{ + return *default_val; +} + +template inline intptr_t DynArray::length() +{ + return pos + 1; +} + +template inline void DynArray::clear() +{ + if (data) { + delete[]data; + data = NULL; + } + + size = 0; + pos = -1; +} + +template inline void DynArray::set_length(intptr_t i) +{ + pos = i - 1; +} + +template inline void DynArray::resize(intptr_t new_size) +{ + if (new_size > size) { + T *new_data; + intptr_t i; + + new_data = NEW(new T[new_size]); + + for (i = 0; i < size; i++) { + new_data[i] = data[i]; + } + + for (; i < new_size; i++) { + if (default_val) + new_data[i] = (T) * default_val; + } + + if (data) { + delete[]data; + } + data = new_data; + size = new_size; + } +} + + +#endif /* __DYN_ARRAY_H__ */ + diff --git a/lib/ts/HostLookup.cc b/lib/ts/HostLookup.cc new file mode 100644 index 00000000..ff2cd7a2 --- /dev/null +++ b/lib/ts/HostLookup.cc @@ -0,0 +1,1330 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * HostLookup.cc - Implementation of a hostname/domainname matcher + * + * + ****************************************************************************/ +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +#include "libts.h" +#include "HostLookup.h" +#include "MatcherUtils.h" + +// bool domaincmp(const char* hostname, const char* domain) +// +// Returns true if hostname is in domain +// +bool +domaincmp(const char *hostname, const char *domain) +{ + ink_assert(hostname != NULL); + ink_assert(domain != NULL); + + const char *host_cur = hostname + strlen(hostname); + const char *domain_cur = domain + strlen(domain); + + // Check to see if were passed emtpy stings for either + // argument. Empty strings do not match anything + // + if (domain_cur == domain || host_cur == hostname) { + return false; + } + // Go back to the last character + domain_cur--; + host_cur--; + + // Trailing dots should be ignored since they are optional + // + if (*(domain_cur) == '.') { + domain_cur--; + } + if (*(host_cur) == '.') { + host_cur--; + } + // Walk through both strings backward + while (domain_cur >= domain && host_cur >= hostname) { + + // If we still have characters left on both strings and + // they do not match, matching fails + // + if (tolower(*domain_cur) != tolower(*host_cur)) { + return false; + } + + domain_cur--; + host_cur--; + }; + + // There are three possible cases that could have gotten us + // here + // + // Case 1: we ran out of both strings + // Case 2: we ran out of domain but not hostname + // Case 3: we ran out of hostname but not domain + // + if (domain_cur < domain) { + if (host_cur < hostname) { + // This covers the case 1 + // ex: example.com matching example.com + return true; + } else { + // This covers case 2 (the most common case): + // ex: www.example.com matching .com or com + // But we must check that we do match + // www.inktomi.ecom against com + // + if (*(domain_cur + 1) == '.') { + return true; + } else if (*host_cur == '.') { + return true; + } else { + return false; + } + } + } else if (host_cur < hostname) { + // This covers the case 3 (a very unusual case) + // ex: example.com needing to match .example.com + if (*domain_cur == '.' && domain_cur == domain) { + return true; + } else { + return false; + } + } + + ink_assert(!"Should not get here"); + return false; +} + +// int hostcmp(const char* c1, const char* c2) +// +// Similar to strcasecmp except that if one string has a +// trailing '.' and the other one does not +// then they are equal +// +// Meant to compare to host names and +// take in out account that www.example.com +// and www.example.com. are the same host +// since the trailing dot is optional +// +int +hostcmp(const char *c1, const char *c2) +{ + ink_assert(c1 != NULL); + ink_assert(c2 != NULL); + do { + if (tolower(*c1) < tolower(*c2)) { + if (*c1 == '\0' && *c2 == '.' && *(c2 + 1) == '\0') { + break; + } + return -1; + } else if (tolower(*c1) > tolower(*c2)) { + if (*c2 == '\0' && *c1 == '.' && *(c1 + 1) == '\0') { + break; + } + return 1; + } + + if (*c1 == '\0') { + break; + } + c1++; + c2++; + } while (1); + + return 0; +} + +// static const unsigned char asciiToTable[256] +// +// Used to Map Legal hostname characters into +// to indexes used by char_table to +// index strings +// +// Legal hostname characters are 0-9, A-Z, a-z and '-' +// '_' is also included although it is not in the spec (RFC 883) +// +// Uppercase and lowercase "a-z" both map to same indexes +// since hostnames are not case sensative +// +// Illegal characters map to 255 +// +static const unsigned char asciiToTable[256] = { + 255, 255, 255, 255, 255, 255, 255, 255, // 0 - 7 + 255, 255, 255, 255, 255, 255, 255, 255, // 8 - 15 + 255, 255, 255, 255, 255, 255, 255, 255, // 16 - 23 + 255, 255, 255, 255, 255, 255, 255, 255, // 24 - 31 + 255, 255, 255, 255, 255, 255, 255, 255, // 32 - 39 + 255, 255, 255, 255, 255, 0, 255, 255, // 40 - 47 ('-') + 1, 2, 3, 4, 5, 6, 7, 8, // 48 - 55 (0-7) + 9, 10, 255, 255, 255, 255, 255, 255, // 56 - 63 (8-9) + 255, 11, 12, 13, 14, 15, 16, 17, // 64 - 71 (A-G) + 18, 19, 20, 21, 22, 23, 24, 25, // 72 - 79 (H-O) + 26, 27, 28, 29, 30, 31, 32, 33, // 80 - 87 (P-W) + 34, 35, 36, 255, 255, 255, 255, 37, // 88 - 95 (X-Z, '_') + 255, 11, 12, 13, 14, 15, 16, 17, // 96 - 103 (a-g) + 18, 19, 20, 21, 22, 23, 24, 25, // 104 - 111 (h-0) + 26, 27, 28, 29, 30, 31, 32, 33, // 112 - 119 (p-w) + 34, 35, 36, 255, 255, 255, 255, 255, // 120 - 127 (x-z) + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 +}; + +// Number of legal characters in the acssiToTable array +static const int numLegalChars = 38; + +// struct charIndex_el +// +// Used by class charIndex. Forms a single level +// in charIndex tree +// +struct charIndex_el +{ + charIndex_el(); + ~charIndex_el(); + HostBranch *branch_array[numLegalChars]; + charIndex_el *next_level[numLegalChars]; +}; + +charIndex_el::charIndex_el() +{ + memset(branch_array, 0, sizeof(branch_array)); + memset(next_level, 0, sizeof(next_level)); +} + +charIndex_el::~charIndex_el() +{ + int i; + + // Recursively delete all the lower levels of the + // data structure + for (i = 0; i < numLegalChars; i++) { + if (next_level[i] != NULL) { + delete next_level[i]; + } + } +} + +// struct charIndexIterInternal +// +// An internal struct to charIndexIterState +// Stores the location of an element in +// class charIndex +// +struct charIndexIterInternal +{ + charIndex_el *ptr; + int index; +}; + +// Used as a default return element for DynArray in +// struct charIndexIterState +static charIndexIterInternal default_iter = { NULL, -1 }; + +// struct charIndexIterState +// +// struct for the callee to keep interation state +// for class charIndex +// +struct charIndexIterState +{ + charIndexIterState(); + + // Where that level we are in interation + int cur_level; + + // Where we got the last element from + int cur_index; + charIndex_el *cur_el; + + // Queue of the above levels + DynArray q; +}; + +charIndexIterState::charIndexIterState():cur_level(-1), cur_index(-1), cur_el(NULL), q(&default_iter, 6) +{ +} + + +// class charIndex - A constant time string matcher intended for +// short strings in a sparsely populated DNS paritition +// +// Creates a look up table for character in data string +// +// Mapping from character to table index is done by +// asciiToTable[] +// +// The illegalKey hash table is side structure for any +// entries that contain illegal hostname characters that +// we can not index into the normal table +// +// Example: com +// c maps to 13, o maps to 25, m maps to 23 +// +// charIndex_el charIndex_el +// ----------- ------------ +// 0 | | | | | | +// . | | | | | | +// charIndex_el . | | | | | | +// ---------- . | | | | | | +// 0 | | | . | | | |-->23| ptr| 0 | (ptr is to the +// . | | | |-------->25| 0 | -----| | | | hostBranch for +// . | | | | . | | | | | | domain com) +// 13 | 0 | --|---| . | | | | | | +// . | | | . | | | | | | +// . | | | | | | | | | +// . | | | | | | | | | +// | | | ----------- -----------| +// | | | +// | | | +// | | | +// |--------| +// +// +// +class + charIndex +{ +public: + charIndex(); + ~ + charIndex(); + void + Insert(const char *match_data, HostBranch * toInsert); + HostBranch * + Lookup(const char *match_data); + HostBranch * + iter_first(charIndexIterState * s); + HostBranch * + iter_next(charIndexIterState * s); +private: + charIndex_el * + root; + InkHashTable * + illegalKey; +}; + +charIndex::charIndex():illegalKey(NULL) +{ + root = NEW(new charIndex_el); +} + +charIndex::~charIndex() +{ + InkHashTableIteratorState ht_iter; + InkHashTableEntry *ht_entry = NULL; + HostBranch *tmp; + + delete root; + + // Destroy the illegalKey hashtable if there is one and free + // up all of its values + if (illegalKey != NULL) { + ht_entry = ink_hash_table_iterator_first(illegalKey, &ht_iter); + + while (ht_entry != NULL) { + tmp = (HostBranch *) ink_hash_table_entry_value(illegalKey, ht_entry); + ink_assert(tmp != NULL); + delete tmp; + ht_entry = ink_hash_table_iterator_next(illegalKey, &ht_iter); + } + ink_hash_table_destroy(illegalKey); + } +} + +// void charIndex::Insert(const char* match_data, HostBranch* toInsert) +// +// Places a binding for match_data to toInsert into the index +// +void +charIndex::Insert(const char *match_data, HostBranch * toInsert) +{ + unsigned char index; + const char *match_start = match_data; + charIndex_el *cur = root; + charIndex_el *next; + + if (*match_data == '\0') { + // Should not happen + ink_assert(0); + return; + } + + while (1) { + index = asciiToTable[(unsigned char) (*match_data)]; + + // Check to see if our index into table is for an + // 'illegal' DNS character + if (index == 255) { + // Insert into illgals hash table + if (illegalKey == NULL) { + illegalKey = ink_hash_table_create(InkHashTableKeyType_String); + } + ink_hash_table_insert(illegalKey, (char *) match_start, toInsert); + break; + } + + // Check to see if are at the level we supposed be at + if (*(match_data + 1) == '\0') { + // The slot should always be emtpy, no duplicate + // keys are allowed + ink_assert(cur->branch_array[index] == NULL); + cur->branch_array[index] = toInsert; + break; + } else { + // We need to find the next level in the table + + next = cur->next_level[index]; + + // Check to see if we need to expand the table + if (next == NULL) { + next = NEW(new charIndex_el); + cur->next_level[index] = next; + } + cur = next; + } + match_data++; + } +} + + +// HostBranch* charIndex::Lookup(const char* match_data) +// +// Searches the charIndex on key match_data +// If there is a binding for match_data, returns a pointer to it +// otherwise a NULL pointer is returned +// +HostBranch * +charIndex::Lookup(const char *match_data) +{ + unsigned char index; + charIndex_el *cur = root; + void *hash_lookup; + const char *match_start = match_data; + + if (root == NULL || *match_data == '\0') { + return NULL; + } + + while (1) { + + index = asciiToTable[(unsigned char) (*match_data)]; + + // Check to see if our index into table is for an + // 'illegal' DNS character + if (index == 255) { + if (illegalKey == NULL) { + return NULL; + } else { + if (ink_hash_table_lookup(illegalKey, (char *) match_start, &hash_lookup)) { + return (HostBranch *) hash_lookup; + } else { + return NULL; + } + } + } + // Check to see if we are looking for the next level or + // a HostBranch + if (*(match_data + 1) == '\0') { + return cur->branch_array[index]; + } else { + cur = cur->next_level[index]; + + if (cur == NULL) { + return NULL; + } + } + + match_data++; + } +} + +// +// HostBranch* charIndex::iter_next(charIndexIterState* s) +// +// Initialize iterator state and returns the first element +// found in the charTable. If none is found, NULL +// is returned +// +HostBranch * +charIndex::iter_first(charIndexIterState * s) +{ + s->cur_level = 0; + s->cur_index = -1; + s->cur_el = root; + + return iter_next(s); +} + +// +// HostBranch* charIndex::iter_next(charIndexIterState* s) +// +// Finds the next element in the char index and returns +// a pointer to it. If there are no more elements, NULL +// is returned +// +HostBranch * +charIndex::iter_next(charIndexIterState * s) +{ + int index; + charIndex_el *current_el = s->cur_el; + intptr_t level = s->cur_level; + charIndexIterInternal stored_state; + HostBranch *r = NULL; + bool first_element; + + // bool first_element is used to tell if first elemente + // pointed to by s has already been returned to caller + // it has unless we are being called from iter_first + if (s->cur_index < 0) { + first_element = false; + index = s->cur_index + 1; + } else { + first_element = true; + index = s->cur_index; + } + + while (1) { + + // Check to see if we need to go back up a level + if (index >= numLegalChars) { + if (level <= 0) { + // No more levels so bail out + break; + } else { + // Go back up to a stored level + stored_state = s->q[level - 1]; + ink_assert(stored_state.ptr != NULL); + ink_assert(stored_state.index >= 0); + level--; + current_el = stored_state.ptr; + index = stored_state.index + 1; + } + } else { + // Check to see if there is something to return + // + // Note: we check for something to return before a descending + // a level so that when we come back up we will + // be done with this index + // + if (current_el->branch_array[index] != NULL && first_element == false) { + r = current_el->branch_array[index]; + s->cur_level = level; + s->cur_index = index; + s->cur_el = current_el; + break; + } else if (current_el->next_level[index] != NULL) { + // There is a lower level to iterate over, store our + // current state and descend + stored_state.ptr = current_el; + stored_state.index = index; + s->q(level) = stored_state; + current_el = current_el->next_level[index]; + index = 0; + level++; + } else { + // Nothing here so advance to next index + index++; + } + } + first_element = false; + } + + return r; +} + +// class hostArray +// +// Is a fixed size array for holding HostBrach* +// Allows only sequential access to data +// + +// Since the only iter state is an index into the +// array typedef it +typedef int hostArrayIterState; + +class hostArray +{ +public: + hostArray(); + ~hostArray(); + bool Insert(const char *match_data_in, HostBranch * toInsert); + HostBranch *Lookup(const char *match_data_in, bool bNotProcess); + HostBranch *iter_first(hostArrayIterState * s, char **key = NULL); + HostBranch *iter_next(hostArrayIterState * s, char **key = NULL); +private: + int num_el; // number of elements currently in the array + HostBranch *branch_array[HOST_ARRAY_MAX]; + char *match_data[HOST_ARRAY_MAX]; +}; + +hostArray::hostArray():num_el(0) +{ + memset(branch_array, 0, sizeof(branch_array)); + memset(match_data, 0, sizeof(match_data)); +} + +hostArray::~hostArray() +{ + for (int i = 0; i < num_el; i++) { + ink_assert(branch_array[i] != NULL); + ink_assert(match_data[i] != NULL); + xfree(match_data[i]); + } +} + +// bool hostArray::Insert(const char* match_data_in, HostBranch* toInsert) +// +// Places toInsert into the array with key match_data if there +// is adequate space, in which case true is returned +// If space is inadequate, false is returned and nothing is inserted +// +bool +hostArray::Insert(const char *match_data_in, HostBranch * toInsert) +{ + if (num_el >= HOST_ARRAY_MAX) { + return false; + } else { + branch_array[num_el] = toInsert; + match_data[num_el] = xstrdup(match_data_in); + num_el++; + return true; + } +} + +// HostBranch* hostArray::Lookup(const char* match_data_in) +// +// Looks for key match_data_in. If a binding is found, +// returns HostBranch* found to the key, otherwise +// NULL is returned +// +HostBranch * +hostArray::Lookup(const char *match_data_in, bool bNotProcess) +{ + HostBranch *r = NULL; + char *pMD; + + for (int i = 0; i < num_el; i++) { + pMD = match_data[i]; + + if (bNotProcess && '!' == *pMD) { + + char *cp = ++pMD; + if ('\0' == *cp) + continue; + + if (strcmp(cp, match_data_in) != 0) { + r = branch_array[i]; + } else { + continue; + } + } + + else if (strcmp(match_data[i], match_data_in) == 0) { + r = branch_array[i]; + break; + } + } + return r; +} + +// HostBranch* hostArray::iter_first(hostArrayIterState* s) { +// +// Initilizes s and returns the first element or +// NULL if no elements exist +// +HostBranch * +hostArray::iter_first(hostArrayIterState * s, char **key) +{ + *s = -1; + return iter_next(s, key); +} + +// HostBranch* hostArray::iter_next(hostArrayIterState* s) { +// +// Returns the next element in the hostArray or +// NULL if none exist +// +HostBranch * +hostArray::iter_next(hostArrayIterState * s, char **key) +{ + (*s)++; + + if (*s < num_el) { + if (key != NULL) { + *key = match_data[*s]; + } + return branch_array[*s]; + } else { + return NULL; + } +} + +// maps enum LeafType to strings +const char *LeafTypeStr[] = { + "Leaf Invalid", + "Host (Partial)", + "Host (Full)", + "Domain (Full)", + "Domain (Partial)" +}; + +static int negative_one = -1; + +HostBranch::HostBranch():level(0), type(HOST_TERMINAL), next_level(NULL), leaf_indexs(&negative_one, 1) +{ +} + +// HostBranch::~HostBranch() +// +// Recursive delete all host branches below us +// +HostBranch::~HostBranch() +{ + + // Hash Iteration + InkHashTable *ht; + InkHashTableIteratorState ht_iter; + InkHashTableEntry *ht_entry = NULL; + + // charIndex Iteration + charIndexIterState ci_iter; + charIndex *ci; + + // hostArray Iteration + hostArray *ha; + hostArrayIterState ha_iter; + + HostBranch *lower_branch; + + switch (type) { + case HOST_TERMINAL: + ink_assert(next_level == NULL); + break; + case HOST_HASH: + ink_assert(next_level != NULL); + ht = (InkHashTable *) next_level; + ht_entry = ink_hash_table_iterator_first(ht, &ht_iter); + + while (ht_entry != NULL) { + lower_branch = (HostBranch *) ink_hash_table_entry_value(ht, ht_entry); + delete lower_branch; + ht_entry = ink_hash_table_iterator_next(ht, &ht_iter); + } + ink_hash_table_destroy(ht); + break; + case HOST_INDEX: + ink_assert(next_level != NULL); + ci = (charIndex *) next_level; + lower_branch = ci->iter_first(&ci_iter); + while (lower_branch != NULL) { + delete lower_branch; + lower_branch = ci->iter_next(&ci_iter); + } + delete ci; + break; + case HOST_ARRAY: + ink_assert(next_level != NULL); + ha = (hostArray *) next_level; + lower_branch = ha->iter_first(&ha_iter); + while (lower_branch != NULL) { + delete lower_branch; + lower_branch = ha->iter_next(&ha_iter); + } + delete ha; + break; + } +} + +HostLookup::HostLookup(const char *name): +leaf_array(NULL), +array_len(-1), +num_el(-1), +matcher_name(name) +{ + + root = NEW(new HostBranch); + root->level = 0; + root->type = HOST_TERMINAL; + root->next_level = NULL; +} + +HostLookup::~HostLookup() +{ + + if (leaf_array != NULL) { + // Free up the match strings + for (int i = 0; i < num_el; i++) { + xfree(leaf_array[i].match); + } + delete[]leaf_array; + } + + delete root; +} + +static void +empty_print_fn(void *opaque_data) +{ + NOWARN_UNUSED(opaque_data); +} + +void +HostLookup::Print() +{ + Print(empty_print_fn); +} + +void +HostLookup::Print(HostLookupPrintFunc f) +{ + PrintHostBranch(root, f); +} + +// +// void HostLookup::PrintHostBranch(HostBranch* hb, HostLookupPrintFunc f) +// +// Recursively traverse the matching tree rooted at arg hb +// and print out each element +// +void +HostLookup::PrintHostBranch(HostBranch * hb, HostLookupPrintFunc f) +{ + + // Hash iteration + InkHashTable *ht; + InkHashTableIteratorState ht_iter; + InkHashTableEntry *ht_entry = NULL; + + // charIndex Iteration + charIndexIterState ci_iter; + charIndex *ci; + + // hostArray Iteration + hostArray *h_array; + hostArrayIterState ha_iter; + + HostBranch *lower_branch; + intptr_t curIndex; + intptr_t i; // Loop var + + for (i = 0; i < hb->leaf_indexs.length(); i++) { + curIndex = hb->leaf_indexs[i]; + printf("\t\t%s for %s\n", LeafTypeStr[leaf_array[curIndex].type], leaf_array[curIndex].match); + f(leaf_array[curIndex].opaque_data); + } + + switch (hb->type) { + case HOST_TERMINAL: + ink_assert(hb->next_level == NULL); + break; + case HOST_HASH: + ink_assert(hb->next_level != NULL); + ht = (InkHashTable *) hb->next_level; + ht_entry = ink_hash_table_iterator_first(ht, &ht_iter); + + while (ht_entry != NULL) { + lower_branch = (HostBranch *) ink_hash_table_entry_value(ht, ht_entry); + PrintHostBranch(lower_branch, f); + ht_entry = ink_hash_table_iterator_next(ht, &ht_iter); + } + break; + case HOST_INDEX: + ink_assert(hb->next_level != NULL); + ci = (charIndex *) hb->next_level; + lower_branch = ci->iter_first(&ci_iter); + while (lower_branch != NULL) { + PrintHostBranch(lower_branch, f); + lower_branch = ci->iter_next(&ci_iter); + } + break; + case HOST_ARRAY: + ink_assert(hb->next_level != NULL); + h_array = (hostArray *) hb->next_level; + lower_branch = h_array->iter_first(&ha_iter); + while (lower_branch != NULL) { + PrintHostBranch(lower_branch, f); + lower_branch = h_array->iter_next(&ha_iter); + } + break; + } +} + +// +// HostBranch* HostLookup::TableNewLevel(HostBranch* from, const char* level_data) +// +// Creates the next level structure in arg from +// Creates a HostBranch for level_data, inserts it in to the +// the next_level structure and returns a pointer to the new +// HostBranch +// +HostBranch * +HostLookup::TableNewLevel(HostBranch * from, const char *level_data) +{ + hostArray *new_ha_table; + charIndex *new_ci_table; + + ink_assert(from->type == HOST_TERMINAL); + + // Use the charIndex for high speed matching at the first level of + // the table. The first level is short strings, ie: com, edu, jp, fr + if (from->level == 0) { + new_ci_table = NEW(new charIndex); + from->type = HOST_INDEX; + from->next_level = new_ci_table; + } else { + new_ha_table = NEW(new hostArray); + from->type = HOST_ARRAY; + from->next_level = new_ha_table; + } + + return InsertBranch(from, level_data); +} + + +// +// HostBranch* HostLookup::InsertBranch(HostBranch* insert_to, const char* level_data) +// +// +// Abstrction to place a new node for level_data below node +// insert to. Inserts into any of the data types used by +// by class HostMatcher +// +HostBranch * +HostLookup::InsertBranch(HostBranch * insert_in, const char *level_data) +{ + + // Variables for moving an array into a hash table after it + // gets too big + // + hostArray *ha; + hostArrayIterState ha_iter; + HostBranch *tmp; + char *key = NULL; + InkHashTable *new_ht; + + + HostBranch *new_branch = NEW(new HostBranch); + new_branch->type = HOST_TERMINAL; + new_branch->level = insert_in->level + 1; + new_branch->next_level = NULL; + + switch (insert_in->type) { + case HOST_TERMINAL: + // Should not happen + ink_assert(0); + delete new_branch; + break; + case HOST_HASH: + ink_hash_table_insert((InkHashTable *) insert_in->next_level, (char *) level_data, new_branch); + break; + case HOST_INDEX: + ((charIndex *) insert_in->next_level)->Insert(level_data, new_branch); + break; + case HOST_ARRAY: + if (((hostArray *) insert_in->next_level)->Insert(level_data, new_branch) == false) { + + // The array is out of space, time to move to a hash table + ha = (hostArray *) insert_in->next_level; + new_ht = ink_hash_table_create(InkHashTableKeyType_String); + ink_hash_table_insert(new_ht, (char *) level_data, new_branch); + + // Iterate through the existing elements in the array and + // stuff them into the hash table + tmp = ha->iter_first(&ha_iter, &key); + ink_assert(tmp != NULL); + while (tmp != NULL) { + ink_assert(key != NULL); + ink_hash_table_insert(new_ht, key, tmp); + tmp = ha->iter_next(&ha_iter, &key); + } + + // Ring out the old, ring in the new + delete ha; + insert_in->next_level = new_ht; + insert_in->type = HOST_HASH; + } + break; + + } + + return new_branch; +} + +// HostBranch* HostLookup::FindNextLevel(HostBranch* from, +// const char* level_data) +// +// Searches in the branch for the next level down in the search +// structure bound to level data +// If found returns a pointer to the next level HostBranch, +// otherwise returns NULL +// +HostBranch * +HostLookup::FindNextLevel(HostBranch * from, const char *level_data, bool bNotProcess) +{ + + HostBranch *r = NULL; + InkHashTable *hash; + charIndex *ci_table; + hostArray *ha_table; + void *lookup; + + switch (from->type) { + case HOST_TERMINAL: + // Should not happen + ink_assert(0); + return NULL; + case HOST_HASH: + hash = (InkHashTable *) from->next_level; + ink_assert(hash != NULL); + if (ink_hash_table_lookup(hash, (char *) level_data, &lookup)) { + r = (HostBranch *) lookup; + } else { + r = NULL; + } + break; + case HOST_INDEX: + ci_table = (charIndex *) from->next_level; + ink_assert(ci_table != NULL); + r = ci_table->Lookup(level_data); + break; + case HOST_ARRAY: + ha_table = (hostArray *) from->next_level; + ink_assert(ha_table != NULL); + r = ha_table->Lookup(level_data, bNotProcess); + break; + } + return r; +} + +// void HostLookup::TableInsert(const char* match_data, int index) +// +// Insert the match data, index pair into domain/search table +// +// arg index is the index into both Data and HostLeaf array for +// the elements corresponding to match_data +// +void +HostLookup::TableInsert(const char *match_data, int index, bool domain_record) +{ + HostBranch *cur = this->root; + HostBranch *next; + char *match_copy = xstrdup(match_data); + Tokenizer match_tok("."); + int numTok; + int i; + + LowerCaseStr(match_copy); + numTok = match_tok.Initialize(match_copy, SHARE_TOKS); + + // Traverse down the search structure until we either + // Get beyond the fixed number depth of the host table + // OR We reach the level where the match stops + // + for (i = 0; i < HOST_TABLE_DEPTH; i++) { + + // Check to see we need to stop at the current level + if (numTok == cur->level) { + break; + } + + if (cur->next_level == NULL) { + cur = TableNewLevel(cur, match_tok[numTok - i - 1]); + } else { + next = FindNextLevel(cur, match_tok[numTok - i - 1]); + if (next == NULL) { + cur = InsertBranch(cur, match_tok[numTok - i - 1]); + } else { + cur = next; + } + } + } + + // Update the leaf type. There are three types: + // HOST_PARTIAL - Indicates that part of the hostname name + // was not matched by traversin the search structure since + // it had too elements. A comparison must be done at the + // leaf node to make sure we have a match + // HOST_COMPLETE - Indicates that the entire domain name + // in the match_data was matched by traversing the search + // structure, no further comparison is necessary + // + // DOMAIN_COMPLETE - Indicates that the entire domain name + // in the match_data was matched by traversing the search + // structure, no further comparison is necessary + // DOMAIN_PARTIAL - Indicates that part of the domain name + // was not matched by traversin the search structure since + // it had too elements. A comparison must be done at the + // leaf node to make sure we have a match + if (domain_record == false) { + if (numTok > HOST_TABLE_DEPTH) { + leaf_array[index].type = HOST_PARTIAL; + } else { + leaf_array[index].type = HOST_COMPLETE; + } + } else { + if (numTok > HOST_TABLE_DEPTH) { + leaf_array[index].type = DOMAIN_PARTIAL; + } else { + leaf_array[index].type = DOMAIN_COMPLETE; + } + } + + // Place the index in to leaf array into the match list for this + // HOST_BRANCH + cur->leaf_indexs(cur->leaf_indexs.length()) = index; + + xfree(match_copy); +} + +// bool HostLookup::MatchArray(HostLookupState* s, void**opaque_ptr, DynArray& array, +// bool host_done) +// +// Helper function to iterate throught arg array and update Result +// for each element in arg array +// +// host_done should be passed as true if this call represents the all fields +// in the matched against hostname being consumed. Example: for www.example.com +// this would be true for the call matching against the "www", but +// neither of the prior two fields, "inktomi" and "com" +// + +bool +HostLookup::MatchArray(HostLookupState * s, void **opaque_ptr, DynArray&array, bool host_done) +{ + intptr_t index; + intptr_t i; + + for (i = s->array_index + 1; i < array.length(); i++) { + index = array[i]; + + switch (leaf_array[index].type) { + case HOST_PARTIAL: + if (hostcmp(s->hostname, leaf_array[index].match) == 0) { + *opaque_ptr = leaf_array[index].opaque_data; + s->array_index = i; + return true; + } + break; + case HOST_COMPLETE: + // We have to have consumed the whole hostname for this to match + // so that we do not match a rule for "example.com" to + // "www.example.com + // + if (host_done == true) { + *opaque_ptr = leaf_array[index].opaque_data; + s->array_index = i; + return true; + } + break; + case DOMAIN_PARTIAL: + if (domaincmp(s->hostname, leaf_array[index].match) == false) { + break; + } + // FALL THROUGH + case DOMAIN_COMPLETE: + *opaque_ptr = leaf_array[index].opaque_data; + s->array_index = i; + return true; + case LEAF_INVALID: + // Should not get here + ink_assert(0); + break; + } + } + + s->array_index = i; + return false; +} + + +// bool HostLookup::MatchFirst(const char* host, HostLookupState* s, void** opaque_ptr) +// +// +bool +HostLookup::MatchFirst(const char *host, HostLookupState * s, void **opaque_ptr) +{ + char *last_dot = NULL; + + s->cur = root; + s->table_level = 0; + s->array_index = -1; + s->hostname = host ? host : ""; + s->host_copy = xstrdup(s->hostname); + LowerCaseStr(s->host_copy); + + // Find the top level domain in the host copy + s->host_copy_next = s->host_copy; + while (*s->host_copy_next != '\0') { + if (*s->host_copy_next == '.') { + last_dot = s->host_copy_next; + } + s->host_copy_next++; + } + + if (last_dot == NULL) { + // Must be an unqualified hostname, no dots + s->host_copy_next = s->host_copy; + } else { + s->host_copy_next = last_dot + 1; + } + + return MatchNext(s, opaque_ptr); +} + +// bool HostLookup::MatchNext(HostLookupState* s, void** opaque_ptr) +// +// Searches our tree and updates argresult for each element matching +// arg hostname +// +bool +HostLookup::MatchNext(HostLookupState * s, void **opaque_ptr) +{ + HostBranch *cur = s->cur; + + // Check to see if there is any work to be done + if (num_el <= 0) { + return false; + } + + while (s->table_level <= HOST_TABLE_DEPTH) { + + if (MatchArray(s, opaque_ptr, cur->leaf_indexs, (s->host_copy_next == NULL))) { + return true; + } + // Check to see if we run out of tokens in the hostname + if (s->host_copy_next == NULL) { + break; + } + // Check to see if there are any lower levels + if (cur->type == HOST_TERMINAL) { + break; + } + + cur = FindNextLevel(cur, s->host_copy_next, true); + + if (cur == NULL) { + break; + } else { + s->cur = cur; + s->array_index = -1; + s->table_level++; + + // Find the next part of the hostname to process + if (s->host_copy_next <= s->host_copy) { + // Nothing left + s->host_copy_next = NULL; + } else { + + // Back up to period ahead of us and axe it + s->host_copy_next--; + ink_assert(*s->host_copy_next == '.'); + *s->host_copy_next = '\0'; + + s->host_copy_next--; + + while (1) { + + if (s->host_copy_next <= s->host_copy) { + s->host_copy_next = s->host_copy; + break; + } + // Check for our stop. If we hit a period, we want + // the our portion of the hostname starts one character + // after it + if (*s->host_copy_next == '.') { + s->host_copy_next++; + break; + } + + s->host_copy_next--; + } + } + } + } + + return false; +} + +// void HostLookup::AllocateSpace(int num_entries) +// +// Allocate the leaf array structure +// +void +HostLookup::AllocateSpace(int num_entries) +{ + // Should not have been allocated before + ink_assert(array_len == -1); + + leaf_array = NEW(new HostLeaf[num_entries]); + memset(leaf_array, 0, sizeof(HostLeaf) * num_entries); + + array_len = num_entries; + num_el = 0; +} + +// void HostLookup::NewEntry(const char* match_data, bool domain_record, void* opaque_data_in) +// +// Insert a new element in to the table +// +void +HostLookup::NewEntry(const char *match_data, bool domain_record, void *opaque_data_in) +{ + + // Make sure space has been allocated + ink_assert(num_el >= 0); + ink_assert(array_len >= 0); + + // Make sure we do not overrun the array; + ink_assert(num_el < array_len); + + leaf_array[num_el].match = xstrdup(match_data); + leaf_array[num_el].opaque_data = opaque_data_in; + + if ('!' != *(leaf_array[num_el].match)) { + leaf_array[num_el].len = strlen(match_data); + leaf_array[num_el].isNot = false; + } else { + leaf_array[num_el].len = strlen(match_data) - 1; + leaf_array[num_el].isNot = true; + } + + TableInsert(match_data, num_el, domain_record); + num_el++; +} diff --git a/lib/ts/HostLookup.h b/lib/ts/HostLookup.h new file mode 100644 index 00000000..4df36e41 --- /dev/null +++ b/lib/ts/HostLookup.h @@ -0,0 +1,128 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * HostLookup.h - Interface to genernal purpose matcher + * + * + ****************************************************************************/ + +#ifndef _HOST_LOOKUP_H_ +#define _HOST_LOOKUP_H_ +// HostLookup constantss +const int HOST_TABLE_DEPTH = 3; // Controls the max number of levels in the logical tree +const int HOST_ARRAY_MAX = 8; // Sets the fixed array size + +// +// Begin Host Lookup Helper types +// +enum HostNodeType +{ HOST_TERMINAL, HOST_HASH, HOST_INDEX, HOST_ARRAY }; +enum LeafType +{ LEAF_INVALID, HOST_PARTIAL, HOST_COMPLETE, + DOMAIN_COMPLETE, DOMAIN_PARTIAL +}; + +// The data in the HostMatcher tree is pointers to HostBranches. +// No duplicates keys permitted in the tree. To handle multiple +// data items bound the same key, the HostBranch has the lead_indexs +// array which stores pointers (in the form of array indexes) to +// HostLeaf structs +// +// There is HostLeaf struct for each data item put into the +// table +// +struct HostLeaf +{ + LeafType type; + char *match; // Contains a copy of the match data + int len; // length of the data + bool isNot; // used by any fasssst path ... + void *opaque_data; // Data associated with this leaf +}; + +struct HostBranch +{ + HostBranch(); + ~HostBranch(); + int level; // what level in the tree. the root is level 0 + HostNodeType type; // tells what kind of data structure is next_level is + void *next_level; // opaque pointer to lookup structure + DynArrayleaf_indexs; // pointers HostLeaf(s) +}; + +typedef void (*HostLookupPrintFunc) (void *opaque_data); +// +// End Host Lookup Helper types +// + +struct HostLookupState +{ + HostLookupState():cur(NULL), table_level(0), array_index(0), hostname(NULL), host_copy(NULL), host_copy_next(NULL) + { + }; + ~HostLookupState() { + xfree(host_copy); + }; + HostBranch *cur; + int table_level; + int array_index; + const char *hostname; + char *host_copy; // request lower-cased host name copy + char *host_copy_next; // ptr to part of host_copy for next use +}; + +class HostLookup +{ +public: + HostLookup(const char *name); + ~HostLookup(); + void NewEntry(const char *match_data, bool domain_record, void *opaque_data_in); + void AllocateSpace(int num_entries); + bool Match(const char *host); + bool Match(const char *host, void **opaque_ptr); + bool MatchFirst(const char *host, HostLookupState * s, void **opaque_ptr); + bool MatchNext(HostLookupState * s, void **opaque_ptr); + void Print(HostLookupPrintFunc f); + void Print(); + HostLeaf *getLArray() + { + return leaf_array; + }; +private: + void TableInsert(const char *match_data, int index, bool domain_record); + HostBranch *TableNewLevel(HostBranch * from, const char *level_data); + HostBranch *InsertBranch(HostBranch * insert_in, const char *level_data); + HostBranch *FindNextLevel(HostBranch * from, const char *level_data, bool bNotProcess = false); + bool MatchArray(HostLookupState * s, void **opaque_ptr, DynArray&array, bool host_done); + void PrintHostBranch(HostBranch * hb, HostLookupPrintFunc f); + HostBranch *root; // The top of the search tree + HostLeaf *leaf_array; // array of all leaves in tree + int array_len; // the length of the arrays + int num_el; // the numbe of itmems in the tree + const char *matcher_name; // Used for Debug/Warning/Error messages +}; + + +#endif diff --git a/lib/ts/INK_MD5.h b/lib/ts/INK_MD5.h new file mode 100644 index 00000000..000d8a61 --- /dev/null +++ b/lib/ts/INK_MD5.h @@ -0,0 +1,164 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _INK_MD5_h_ +#define _INK_MD5_h_ +#include "MMH.h" + +#include "ink_bool.h" +#include "ink_code.h" +#include "ink_port.h" + +// #define USE_MMH_FOR_MD5 + +struct INK_MD5 +{ + uint64_t b[2]; + const INK_MD5 & operator =(const INK_MD5 & md5) + { + b[0] = md5.b[0]; + b[1] = md5.b[1]; + return md5; + } + uint32_t word(int i) + { + uint32_t *p = (uint32_t *) & b[0]; + return p[i]; + } + unsigned char byte(int i) + { + unsigned char *p = (unsigned char *) &b[0]; + return p[i]; + } + INK_MD5 & loadFromBuffer(char *md5_buf) { + int i; + char *s, *d; + + for (i = 0, s = md5_buf, d = (char *) (&(b[0])); i < 8; i++, *d++ = *s++); + for (i = 0, d = (char *) (&(b[1])); i < 8; i++, *d++ = *s++); + return (*this); + } + INK_MD5 & storeToBuffer(char *md5_buf) { + int i; + char *s, *d; + + for (i = 0, d = md5_buf, s = (char *) (&(b[0])); i < 8; i++, *d++ = *s++); + for (i = 0, s = (char *) (&(b[1])); i < 8; i++, *d++ = *s++); + return (*this); + } + INK_MD5 & operator =(char *md5) { + return (loadFromBuffer(md5)); + } + INK_MD5 & operator =(unsigned char *md5) { + return (loadFromBuffer((char *) md5)); + } + + char *toStr(char *md5_str) + { + int i; + char *s, *d; + + for (i = 0, d = md5_str, s = (char *) (&(b[0])); i < 8; i++, *d++ = *s++); + for (i = 0, s = (char *) (&(b[1])); i < 8; i++, *d++ = *s++); + return (md5_str); + } + void encodeBuffer(unsigned char *buffer, int len) + { + unsigned char md5[16]; + ink_code_md5(buffer, len, md5); + *this = md5; + } + void encodeBuffer(const char *buffer, int len) + { + encodeBuffer((unsigned char *) buffer, len); + } + char *str() + { + return ((char *) b); + } + char *toHexStr(char hex_md5[33]) + { + return (ink_code_md5_stringify_fast(hex_md5, str())); + } + void set(INK_MD5 & md5) + { + loadFromBuffer((char *) &md5); + } + void set(INK_MD5 * md5) + { + loadFromBuffer((char *) md5); + } + void set(char *p) + { + loadFromBuffer(p); + } + void set(uint64_t a1, uint64_t a2) + { + b[0] = a1; + b[1] = a2; + } + char *string(char buf[33]) + { + char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + int i, j; + unsigned char *u = (unsigned char *) &b[0]; + + for (i = 0, j = 0; i < 16; i += 1, j += 2) { + buf[j + 0] = hex_digits[u[i] >> 4]; + buf[j + 1] = hex_digits[u[i] & 0xF]; + } + buf[32] = '\0'; + return buf; + } + + uint64_t fold() + { + return (b[0] ^ b[1]); + } + + uint64_t operator[] (int i) + { + return b[i]; + } + bool operator==(INK_MD5 & md5) + { + return b[0] == md5.b[0] && b[1] == md5.b[1]; + } + INK_MD5() { + b[0] = 0; + b[1] = 0; + } + INK_MD5(uint64_t a1, uint64_t a2) { + b[0] = a1; + b[1] = a2; + } +}; + +#ifdef USE_MMH_FOR_MD5 +#define INK_MD5 MMH +#define ink_code_incr_MD5_init ink_code_incr_MMH_init +#define ink_code_incr_MD5_update ink_code_incr_MMH_update +#define ink_code_incr_MD5_final ink_code_incr_MMH_final +#endif + +#endif diff --git a/lib/ts/I_Layout.h b/lib/ts/I_Layout.h new file mode 100644 index 00000000..26baf748 --- /dev/null +++ b/lib/ts/I_Layout.h @@ -0,0 +1,107 @@ +/** @file + + Layout + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Part of the utils library which contains classes that use multiple + components of the IO-Core to implement some useful functionality. The + classes also serve as good examples of how to use the IO-Core. + + */ + +#ifndef _I_Layout_h +#define _I_Layout_h + +/** + The Layout is a simple place holder for the distribution layout. + + */ +struct Layout +{ + char *prefix; + char *exec_prefix; + char *bindir; + char *sbindir; + char *sysconfdir; + char *datadir; + char *includedir; + char *libdir; + char *libexecdir; + char *localstatedir; + char *sharedstatedir; + char *runtimedir; + char *logdir; + char *mandir; + char *infodir; + char *cachedir; + + Layout(const char *prefix = 0); + ~Layout(); + + /** + Return file path relative to Layout->prefix + Memory is allocated, so use xfree() when no longer needed + + */ + char *relative(const char *file); + + /** + Return file path relative to Layout->prefix + Store the path to buf. The buf should be large eough to store + PATH_MAX characters + + */ + void relative(char *buf, size_t bufsz, const char *file); + + /** + Return file path relative to dir + Memory is allocated, so use xfree() when no longer needed + Example usage: Layout::relative_to(default_layout()->sysconfdir, "foo.bar"); + + */ + static char *relative_to(const char *dir, const char *file); + + /** + Return file path relative to dir + Store the path to buf. The buf should be large eough to store + PATH_MAX characters + Example usage: Layout::relative_to(default_layout()->sysconfdir, "foo.bar"); + + */ + static void relative_to(char *buf, size_t bufsz, const char *dir, const char *file); + + /** + Creates a Layout Object with the given prefix. If no + prefix is given, the prefix defaults to the one specified + at the compile time. + + */ + static void create(const char *prefix = 0); + + /** + Returns the Layout object created by create_default_layout(). + + */ + static Layout *get(); +}; + +#endif diff --git a/lib/ts/I_Version.h b/lib/ts/I_Version.h new file mode 100644 index 00000000..adfdd57d --- /dev/null +++ b/lib/ts/I_Version.h @@ -0,0 +1,100 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + + Version.h + + + **************************************************************************/ + +#ifndef _Version_h +#define _Version_h + +struct VersionNumber +{ + short int ink_major; // incompatible change + short int ink_minor; // minor change, not incompatible +}; + +struct Version +{ + VersionNumber cacheDB; + VersionNumber cacheDir; + VersionNumber clustering; + VersionNumber clustering_min; +}; + +enum ModuleVersion +{ MODULE_VERSION_MIN = 0, MODULE_VERSION_MAX = 2147483647 }; +enum ModuleHeaderType +{ PUBLIC_MODULE_HEADER, PRIVATE_MODULE_HEADER }; + +#define makeModuleVersion(_major_version, _minor_version, _module_type) \ +((ModuleVersion)((((int)_module_type) << 24) + \ + (((int)_major_version) << 16) + \ + (((int)_minor_version) << 8))) + +#define majorModuleVersion(_v) ((((int)_v) >> 16) & 255) +#define minorModuleVersion(_v) ((((int)_v) >> 8) & 255) +#define moduleVersionType(_v) ((((int)_v) >> 24) & 127) + +static inline int +checkModuleVersion(ModuleVersion userVersion, ModuleVersion libVersion) +{ + if (moduleVersionType(userVersion) == PUBLIC_MODULE_HEADER) { + if ((majorModuleVersion(userVersion) != majorModuleVersion(libVersion)) || + (minorModuleVersion(userVersion) > minorModuleVersion(libVersion))) + return -1; + return 0; + } else if (moduleVersionType(userVersion) == PRIVATE_MODULE_HEADER) { + if ((majorModuleVersion(userVersion) != majorModuleVersion(libVersion)) || + (minorModuleVersion(userVersion) != minorModuleVersion(libVersion))) + return -1; + return 0; + } else + return -1; +} + +class AppVersionInfo +{ +public: + int defined; + char PkgStr[128]; + char AppStr[128]; + char VersionStr[128]; + char BldNumStr[128]; + char BldTimeStr[128]; + char BldDateStr[128]; + char BldMachineStr[128]; + char BldPersonStr[128]; + char BldCompileFlagsStr[128]; + char FullVersionInfoStr[256]; + + AppVersionInfo(); + void setup(const char *pkg_name, const char *app_name, const char *app_version, + const char *build_date, const char *build_time, const char *build_machine, + const char *build_person, const char *build_cflags); +}; + +#endif /*_Version_h*/ diff --git a/lib/ts/InkErrno.h b/lib/ts/InkErrno.h new file mode 100644 index 00000000..7f8676e4 --- /dev/null +++ b/lib/ts/InkErrno.h @@ -0,0 +1,72 @@ +/** @file + + Error code defines + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Contains all the errno codes that we may need (above and beyond those + provided by /usr/include/errno.h) + +*/ + +#if !defined (_Errno_h_) +#define _Errno_h_ +#include + +#define INK_START_ERRNO 20000 + +#define SOCK_ERRNO INK_START_ERRNO +#define NET_ERRNO INK_START_ERRNO+100 +#define CLUSTER_ERRNO INK_START_ERRNO+200 +#define CACHE_ERRNO INK_START_ERRNO+400 +#define HTTP_ERRNO INK_START_ERRNO+600 + +#define ENET_THROTTLING (NET_ERRNO+1) +#define ENET_CONNECT_TIMEOUT (NET_ERRNO+2) +#define ENET_CONNECT_FAILED (NET_ERRNO+3) + +#define ESOCK_DENIED (SOCK_ERRNO+0) +#define ESOCK_TIMEOUT (SOCK_ERRNO+1) +#define ESOCK_NO_SOCK_SERVER_CONN (SOCK_ERRNO+2) + +// Error codes for CLUSTER_EVENT_OPEN_FAILED +#define ECLUSTER_NO_VC (CLUSTER_ERRNO+0) +#define ECLUSTER_NO_MACHINE (CLUSTER_ERRNO+1) +#define ECLUSTER_OP_TIMEOUT (CLUSTER_ERRNO+2) +#define ECLUSTER_ORB_DATA_READ (CLUSTER_ERRNO+3) +#define ECLUSTER_ORB_EIO (CLUSTER_ERRNO+4) +#define ECLUSTER_CHANNEL_INUSE (CLUSTER_ERRNO+5) +#define ECLUSTER_NOMORE_CHANNELS (CLUSTER_ERRNO+6) + +#define ECACHE_NO_DOC (CACHE_ERRNO+0) +#define ECACHE_DOC_BUSY (CACHE_ERRNO+1) +#define ECACHE_DIR_BAD (CACHE_ERRNO+2) +#define ECACHE_BAD_META_DATA (CACHE_ERRNO+3) +#define ECACHE_READ_FAIL (CACHE_ERRNO+4) +#define ECACHE_WRITE_FAIL (CACHE_ERRNO+5) +#define ECACHE_MAX_ALT_EXCEEDED (CACHE_ERRNO+6) +#define ECACHE_NOT_READY (CACHE_ERRNO+7) +#define ECACHE_ALT_MISS (CACHE_ERRNO+8) +#define ECACHE_BAD_READ_REQUEST (CACHE_ERRNO+9) + +#define EHTTP_ERROR (HTTP_ERRNO+0) + +#endif diff --git a/lib/ts/InkPool.h b/lib/ts/InkPool.h new file mode 100644 index 00000000..a26ad511 --- /dev/null +++ b/lib/ts/InkPool.h @@ -0,0 +1,96 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __INK_POOL_H_INCLUDED__ +#define __INK_POOL_H_INCLUDED__ + +// +// Template of a static size pool of objects. +// +// +template class InkStaticPool { +public: + + InkStaticPool(int size):sz1(size + 1), head(0), tail(0) + { + pool = new C *[sz1]; + } + + virtual ~ InkStaticPool() { + cleanUp(); + delete[]pool; + } + + C *get(); + bool put(C * newObj); + void put_or_delete(C * newObj) + { + if (!put(newObj)) + delete newObj; + } + +protected: + void cleanUp(void); + +private: + const int sz1; + int head; + int tail; + C **pool; +}; + +template inline C * InkStaticPool::get() +{ + if (head != tail) { + C *res = pool[head++]; + head %= sz1; + return (res); + } + return (NULL); +} + +template inline bool InkStaticPool::put(C * newObj) +{ + if (newObj == NULL) + return (false); // cannot put NULL pointer + + int newTail = (tail + 1) % sz1; + bool res = (newTail != head); + if (res) { + pool[tail] = newObj; + tail = newTail; + } + return (res); +} + +template inline void InkStaticPool::cleanUp(void) +{ + while (true) { + C *tp = get(); + if (tp == NULL) + break; + delete tp; + } +} + +#endif // #ifndef __INK_POOL_H_INCLUDED__ diff --git a/lib/ts/Layout.cc b/lib/ts/Layout.cc new file mode 100644 index 00000000..89c2ad5e --- /dev/null +++ b/lib/ts/Layout.cc @@ -0,0 +1,236 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "I_Layout.h" + +static Layout *layout = NULL; + +Layout * +Layout::get() +{ + if (layout == NULL) { + ink_assert("need to call create_default_layout before accessing" "default_layout()"); + } + return layout; +} + +void +Layout::create(const char *prefix) +{ + if (layout == NULL) { + layout = NEW(new Layout(prefix)); + } +} + +static char * +layout_relative(const char *root, const char *file) +{ + char path[PATH_MAX]; + + if (ink_filepath_merge(path, PATH_MAX, root, file, + INK_FILEPATH_TRUENAME)) { + int err = errno; + // Log error + if (err == EACCES) { + ink_error("Cannot merge path '%s' above the root '%s'\n", file, root); + } else if (err == E2BIG) { + ink_error("Excedding file name length limit of %d characters\n", PATH_MAX); + } + else { + // TODO: Make some pretty errors. + ink_error("Cannot merge '%s' with '%s' error=%d\n", file, root, err); + } + return NULL; + } + return xstrdup(path); +} + +char * +Layout::relative(const char *file) +{ + return layout_relative(prefix, file); +} + +void +Layout::relative(char *buf, size_t bufsz, const char *file) +{ + char path[PATH_MAX]; + + if (ink_filepath_merge(path, PATH_MAX, prefix, file, + INK_FILEPATH_TRUENAME)) { + int err = errno; + // Log error + if (err == EACCES) { + ink_error("Cannot merge path '%s' above the root '%s'\n", file, prefix); + } else if (err == E2BIG) { + ink_error("Excedding file name length limit of %d characters\n", PATH_MAX); + } + else { + // TODO: Make some pretty errors. + ink_error("Cannot merge '%s' with '%s' error=%d\n", file, prefix, err); + } + return; + } + size_t path_len = strlen(path) + 1; + if (path_len > bufsz) { + ink_error("Provided buffer is too small: %d, required %d\n", + bufsz, path_len); + } + else { + strcpy(buf, path); + } +} + +char * +Layout::relative_to(const char *dir, const char *file) +{ + return layout_relative(dir, file); +} + +void +Layout::relative_to(char *buf, size_t bufsz, const char *dir, const char *file) +{ + char path[PATH_MAX]; + + if (ink_filepath_merge(path, PATH_MAX, dir, file, + INK_FILEPATH_TRUENAME)) { + int err = errno; + // Log error + if (err == EACCES) { + ink_error("Cannot merge path '%s' above the root '%s'\n", file, dir); + } else if (err == E2BIG) { + ink_error("Excedding file name length limit of %d characters\n", PATH_MAX); + } + else { + // TODO: Make some pretty errors. + ink_error("Cannot merge '%s' with '%s' error=%d\n", file, dir, err); + } + return; + } + size_t path_len = strlen(path) + 1; + if (path_len > bufsz) { + ink_error("Provided buffer is too small: %d, required %d\n", + bufsz, path_len); + } + else { + strcpy(buf, path); + } +} + +Layout::Layout(const char *_prefix) +{ + if (_prefix) { + prefix = xstrdup(_prefix); + } else { + char *env_path; + char path[PATH_MAX]; + int len; + + if ((env_path = getenv("TS_ROOT"))) { + len = strlen(env_path); + if ((len + 1) > PATH_MAX) { + ink_error("TS_ROOT environment variable is too big: %d, max %d\n", + len, PATH_MAX -1); + return; + } + strcpy(path, env_path); + while (len > 1 && path[len - 1] == '/') { + path[len - 1] = '\0'; + --len; + } + } else { + // Use compile time --prefix + ink_strncpy(path, TS_BUILD_PREFIX, sizeof(path)); + } + + if (access(path, R_OK) == -1) { + ink_error("unable to access() TS_ROOT '%s': %d, %s\n", + path, errno, strerror(errno)); + return; + } + prefix = xstrdup(path); + } + exec_prefix = layout_relative(prefix, TS_BUILD_EXEC_PREFIX); + bindir = layout_relative(prefix, TS_BUILD_BINDIR); + sbindir = layout_relative(prefix, TS_BUILD_SBINDIR); + sysconfdir = layout_relative(prefix, TS_BUILD_SYSCONFDIR); + datadir = layout_relative(prefix, TS_BUILD_DATADIR); + includedir = layout_relative(prefix, TS_BUILD_INCLUDEDIR); + libdir = layout_relative(prefix, TS_BUILD_LIBDIR); + libexecdir = layout_relative(prefix, TS_BUILD_LIBEXECDIR); + localstatedir = layout_relative(prefix, TS_BUILD_LOCALSTATEDIR); + runtimedir = layout_relative(prefix, TS_BUILD_RUNTIMEDIR); + logdir = layout_relative(prefix, TS_BUILD_LOGDIR); + mandir = layout_relative(prefix, TS_BUILD_MANDIR); + infodir = layout_relative(prefix, TS_BUILD_INFODIR); + cachedir = layout_relative(prefix, TS_BUILD_CACHEDIR); + +#ifdef DEBUG +// TODO: Use a propper Debug logging +// +#define PrintSTR(var) \ + fprintf(stdout, "%18s = '%s'\n", "--" #var, (var == NULL? "NULL" : var)); + + fprintf(stdout, "Layout configuration\n"); + PrintSTR(prefix); + PrintSTR(exec_prefix); + PrintSTR(bindir); + PrintSTR(sbindir); + PrintSTR(sysconfdir); + PrintSTR(datadir); + PrintSTR(includedir); + PrintSTR(libdir); + PrintSTR(libexecdir); + PrintSTR(localstatedir); + PrintSTR(runtimedir); + PrintSTR(logdir); + PrintSTR(mandir); + PrintSTR(infodir); + PrintSTR(cachedir); +#endif + +} + +Layout::~Layout() +{ +#define SafeFree(x) \ + if (x) xfree(x); + + SafeFree(prefix); + SafeFree(exec_prefix); + SafeFree(bindir); + SafeFree(sbindir); + SafeFree(sysconfdir); + SafeFree(datadir); + SafeFree(includedir); + SafeFree(libdir); + SafeFree(libexecdir); + SafeFree(localstatedir); + SafeFree(runtimedir); + SafeFree(logdir); + SafeFree(mandir); + SafeFree(infodir); + SafeFree(cachedir); +} + diff --git a/lib/ts/List.h b/lib/ts/List.h new file mode 100644 index 00000000..a1d756ea --- /dev/null +++ b/lib/ts/List.h @@ -0,0 +1,497 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + List.h + + This file implements singly and doubly linked list templates for + homomorphic lists. + + There are two main data structures defined for each list, a link cell + and a list descriptor. Both are parameterized by template object class. + The link cell and list descriptor are named as follows: + + list type 1-linked list 2-linked list queue + --------- ------------- ------------- ----- + link cell SLink Link Link + list descriptor SLL DLL Queue + + The list descriptor contains state about the lists (for example: head and + tail pointers) and supports list manipulation methods. + + The link cell strings objects together in the list, and is normally part + of the object itself. An SLink only points to the next object. A Link + points both to the previous and the next object in a list. + + The link() method can help find the location of the location of the link + cell within an object, given the location of the link cell in another + object. This is useful when iterating along lists. + + + ****************************************************************************/ + +#ifndef _List_h_ +#define _List_h_ + +#include + +#include "ink_bool.h" +#include "ink_assert.h" +#include "ink_queue.h" +#include "ink_resource.h" +#include "Compatability.h" +#include "defalloc.h" + +// +// Link cell for singly-linked list of objects of type C. +// +template class SLink { + public: + C *next; + SLink() : next(NULL) {}; +}; +#define SLINK(_c,_f) class Link##_##_f : public SLink<_c> { public: \ + static _c *& next_link(_c *c) { return c->_f.next; } \ + }; SLink<_c> _f +#define SLINKM(_c,_m,_f) class Link##_##_m##_##_f : public SLink<_c> { public: \ + static _c *& next_link(_c *c) { return c->_m._f.next; } \ + }; + +// +// Link cell for doubly-linked list of objects of type C. +// +template struct Link : public SLink { + C *prev; + Link() : prev(NULL) {} +}; +#define LINK(_c,_f) class Link##_##_f : public Link<_c> { public: \ + static _c *& next_link(_c *c) { return c->_f.next; } \ + static _c *& prev_link(_c *c) { return c->_f.prev; } \ + }; Link<_c> _f +#define LINKM(_c,_m,_f) class Link##_##_m##_##_f : public Link<_c> { public: \ + static _c *& next_link(_c *c) { return c->_m._f.next; } \ + static _c *& prev_link(_c *c) { return c->_m._f.prev; } \ + }; +#define LINK_FORWARD_DECLARATION(_c,_f) class Link##_##_c##_##_f : public Link<_c> { public: \ + static _c *& next_link(_c *c); \ + static _c *& prev_link(_c *c); \ + }; +#define LINK_DEFINITION(_c,_f) \ + inline _c *& Link##_##_c##_##_f::next_link(_c *c) { return c->_f.next; } \ + inline _c *& Link##_##_c##_##_f::prev_link(_c *c) { return c->_f.prev; } \ + +// +// List descriptor for singly-linked list of objects of type C. +// +template class SLL { + public: + C *head; + bool empty() { return head == NULL; } + void push(C *e); + C *pop(); + void clear() { head = NULL; } + C *& next(C *e) { return L::next_link(e); } + + SLL() : head(NULL) {} + SLL(C *c) : head(c) {} +}; +#define SList(_c, _f) SLL<_c, _c::Link##_##_f> +#define SListM(_c, _m, _ml, _l) SLL<_c, _c::Link##_##_ml##_##_l> +#define forl_LL(_c, _p, _l) for (_c *_p = (_l).head; _p; _p = (_l).next(_p)) + +template inline void +SLL::push(C *e) { + next(e) = head; + head = e; +} + +template inline C * +SLL::pop() { + C *ret = head; + if (ret) { + head = next(ret); + next(ret) = NULL; + } + return ret; +} + +// +// List descriptor for doubly-linked list of objects of type C. +// +template struct DLL { + C *head; + bool empty() { return head == NULL; } + void push(C *e); + C *pop(); + void remove(C *e); + void insert(C *e, C *after); + bool in(C *e) { return head == e || next(e) || prev(e); } + void clear() { head = NULL; } + C *&next(C *e) { return *(C**)&L::next_link(e); } + C *&prev(C *e) { return *(C**)&L::prev_link(e); } + + DLL() : head(NULL) {} +}; +#define DList(_c, _f) DLL<_c, _c::Link##_##_f> +#define DListM(_c, _m, _ml, _l) DLL<_c, _c::Link##_##_ml##_##_l> + +template inline void +DLL::push(C *e) { + if (head) + prev(head) = e; + next(e) = head; + head = e; +} + +template inline void +DLL::remove(C *e) { + if (!head) return; + if (e == head) head = next(e); + if (prev(e)) next(prev(e)) = next(e); + if (next(e)) prev(next(e)) = prev(e); + prev(e) = NULL; + next(e) = NULL; +} + +template inline C * +DLL::pop() { + C *ret = head; + if (ret) { + head = next(ret); + if (head) + prev(head) = NULL; + next(ret) = NULL; + return ret; + } else + return NULL; +} + +template inline void +DLL::insert(C *e, C *after) { + if (!after) { push(e); return; } + prev(e) = after; + next(e) = next(after); + next(after) = e; + if (next(e)) prev(next(e)) = e; +} + +// +// List descriptor for queue of objects of type C. +// +template class Queue : public DLL { + public: + using DLL::head; + C *tail; + void push(C *e); + C *pop(); + void enqueue(C *e); + void in_or_enqueue(C *e); + C *dequeue(); + void remove(C *e); + void insert(C *e, C *after); + void append(Queue q); + void append(DLL q); + void clear() { head = NULL; tail = NULL; } + + Queue() : tail(NULL) {} +}; +#define Que(_c, _f) Queue<_c, _c::Link##_##_f> +#define QueM(_c, _m, _mf, _f) Queue<_c, _c::Link##_##_mf##_##_f> + +template inline void +Queue::push(C *e) { + DLL::push(e); + if (!tail) tail = head; +} + +template inline C * +Queue::pop() { + C *ret = DLL::pop(); + if (!head) tail = NULL; + return ret; +} + +template inline void +Queue::insert(C *e, C *after) { + DLL::insert(e, after); + if (!tail) + tail = head; + else if (tail == after) + tail = e; +} + +template inline void +Queue::remove(C *e) { + if (tail == e) + tail = (C*)this->prev(e); + DLL::remove(e); +} + +template inline void +Queue::append(DLL q) { + C *qtail = q.head; + if (qtail) + while (this->next(qtail)) + qtail = this->next(qtail); + if (!head) { + head = q.head; + tail = qtail; + } else { + if (q.head) { + this->next(tail) = q.head; + this->prev(q.head) = tail; + tail = qtail; + } + } +} + +template inline void +Queue::append(Queue q) { + if (!head) { + head = q.head; + tail = q.tail; + } else { + if (q.head) { + this->next(tail) = q.head; + this->prev(q.head) = tail; + tail = q.tail; + } + } +} + +template inline void +Queue::enqueue(C *e) { + if (tail) + insert(e, tail); + else + push(e); +} + +template inline void +Queue::in_or_enqueue(C *e) { + if (!this->in(e)) enqueue(e); +} + +template inline C * +Queue::dequeue() { + return pop(); +} + +// +// Adds sorting, but requires that elements implement < +// + +template struct SortableQueue: public Queue +{ + using DLL::head; + using Queue::tail; + void sort() { + if (!head) return; + bool clean = false; + while (!clean) { + clean = true; + C *v = head; + C *n = this->next(head); + while (n) { + C *f = this->next(n); + if (*n < *v) { + clean = false; + // swap 'em + if (head == v) + head = n; + if (tail == n) + tail = v; + // fix prev (p) + C *p = this->prev(v); + if (p) { + this->next(p) = n; + this->prev(n) = p; + } else + this->prev(n) = NULL; + // fix follow (f) + if (f) { + this->prev(f) = v; + this->next(v) = f; + } else + this->next(v) = NULL; + // fix interior + this->prev(v) = n; + this->next(n) = v; + } else + v = n; + n = f; + } + } + } +}; +#define SortableQue(_c, _l) SortableQueue<_c, _c::Link##_##_f> + +// +// Adds counting to the Queue +// + +template struct CountQueue : public Queue { + int size; + inline CountQueue(void) : size(0) {} + inline void push(C *e); + inline C *pop(); + inline void enqueue(C *e); + inline C *dequeue(); + inline void remove(C *e); + inline void insert(C *e, C *after); + inline void append(CountQueue &q); + inline void append_clear(CountQueue &q); +}; +#define CountQue(_c, _f) CountQueue<_c, _c::Link##_##_f> +#define CountQueM(_c, _m, _mf, _f) CountQueue<_c, _c::Link##_##_mf##_##_f> + +template inline void +CountQueue::push(C *e) { + Queue::push(e); + size++; +} + +template inline C * +CountQueue::pop() { + C *ret = Queue::pop(); + if (ret) + size--; + return ret; +} + +template inline void +CountQueue::remove(C *e) { + Queue::remove(e); + size--; +} + +template inline void +CountQueue::enqueue(C *e) { + Queue::enqueue(e); + size++; +} + +template inline C * +CountQueue::dequeue() { + return pop(); +} + +template inline void +CountQueue::insert(C *e, C *after) { + Queue::insert(e, after); + size++; +} + +template inline void +CountQueue::append(CountQueue &q) { + Queue::append(q); + size += q.size; +}; + +template inline void +CountQueue::append_clear(CountQueue &q) { + append(q); + q.head = q.tail = 0; + q.size = 0; +} + +// +// List using cons cells +// + +template +struct ConsCell { + C car; + ConsCell *cdr; + ConsCell(C acar, ConsCell *acdr) : car(acar), cdr(acdr) {} + ConsCell(C acar) : car(acar), cdr(NULL) {} + ConsCell(ConsCell *acdr) : cdr(acdr) {} + static void *operator new(size_t size) { return A::alloc(size); } + static void operator delete(void *p, size_t size) { A::free(p); } +}; + +template +struct List { + ConsCell *head; + C first() { if (head) return head->car; else return 0; } + C car() { return first(); } + ConsCell *rest() { if (head) return head->cdr; else return 0; } + ConsCell *cdr() { return rest(); } + void push(C a) { head = new ConsCell(a, head); } + void push() { head = new ConsCell(head); } + C pop() { C a = car(); head = cdr(); return a; } + void clear() { head = NULL; } + void reverse(); + List(C acar) : head(new ConsCell(acar)) {} + List(C a, C b) : head(new ConsCell(a, new ConsCell(b))) {} + List(C a, C b, C c) : head(new ConsCell(a, new ConsCell(b, new ConsCell(c)))) {} + List() : head(0) {} +}; +#define forc_List(_c, _p, _l) if ((_l).head) for (_c *_p = (_l).head; _p; _p = _p->cdr) + +template void +List::reverse() { + ConsCell *n, *t; + for (ConsCell *p = head; p; p = n) { + n = p->cdr; + p->cdr = t; + t = p; + } + head = t; +} + +// +// Atomic lists +// + +template struct AtomicSLL +{ + void push(C * c) { ink_atomiclist_push(&al, c); } + C *pop() { return (C *) ink_atomiclist_pop(&al); } + C *popall() { return (C *) ink_atomiclist_popall(&al); } + bool empty() { return INK_ATOMICLIST_EMPTY(al); } + + /* + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * only if only one thread is doing pops it is possible to have a "remove" + * which only that thread can use as well. + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + C *remove(C * c) { return (C *) ink_atomiclist_remove(&al, c); } + C *head() { return (C *) TO_PTR(FREELIST_POINTER(al.head)); } + C *next(C * c) { return (C *) TO_PTR(c); } + + InkAtomicList al; + + AtomicSLL(); +}; + +#define ASLL(_c, _l) AtomicSLL<_c, _c::Link##_##_l> +#define ASLLM(_c, _m, _ml, _l) AtomicSLL<_c, _c::Link##_##_ml##_##_l> + +template inline AtomicSLL::AtomicSLL() { + ink_atomiclist_init(&al, "AtomicSLL", (uint32_t)(uintptr_t)&L::next_link((C*)0)); +} + +#endif /*_List_h_*/ diff --git a/lib/ts/MMH.cc b/lib/ts/MMH.cc new file mode 100644 index 00000000..6f2bf90f --- /dev/null +++ b/lib/ts/MMH.cc @@ -0,0 +1,577 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include "ink_assert.h" +#include "ink_platform.h" +#include "MMH.h" + +#ifndef USE_MD5_FOR_MMH + +#define MMH_X_SIZE 512 + +/* BUG: INKqa11504: need it be to 64 bits...otherwise it overflows */ +static uint64_t MMH_x[MMH_X_SIZE + 8] = { + 0x3ee18b32, 0x746d0d6b, 0x591be6a3, 0x760bd17f, + 0x363c765d, 0x4bf3d5c5, 0x10f0510a, 0x39a84605, + 0x2282b48f, 0x6903652e, 0x1b491170, 0x1ab8407a, + 0x776b8aa8, 0x5b126ffe, 0x5095db1a, 0x565fe90c, + 0x3ae1f068, 0x73fdf0cb, 0x72f39a81, 0x6a40a4a3, + 0x4ef557fe, 0x360c1a2c, 0x4579b0ea, 0x61dfd174, + 0x269b242f, 0x752d6298, 0x15f10fa3, 0x618b7ab3, + 0x6699171f, 0x488f2c6c, 0x790f8cdb, 0x5ed15565, + 0x04eba3c0, 0x5009ac0b, 0x3a5d6c1f, 0x1a4f7853, + 0x1affabd4, 0x74aace1f, 0x2310b46d, 0x466b611a, + 0x18c5d4a0, 0x7eb9fffe, 0x76098df6, 0x4172f860, + 0x689e3c2f, 0x722cdc29, 0x64548175, 0x28f46721, + 0x58fdf93f, 0x12c2dcee, 0x58cb1327, 0x02d4af27, + 0x4d1c6fcd, 0x72fe572d, 0x7038d366, 0x0bfa1898, + 0x788d2438, 0x1f131f37, 0x25729ee6, 0x635ea6a9, + 0x3b0b5714, 0x6ac759d2, 0x5faf688a, 0x0c2fe571, + 0x7487538e, 0x65491b59, 0x60cd86e4, 0x5d6482d8, + 0x4a59fa77, 0x78439700, 0x56a51f48, 0x360544ae, + 0x6c01b3ef, 0x2228c036, 0x15b7e88b, 0x326e0dd8, + 0x509491af, 0x72d06023, 0x26181f5d, 0x7924c4a4, + 0x70c60bf2, 0x7b5bc151, 0x28e42640, 0x48af0c3e, + 0x009b6301, 0x06dd3366, 0x2ad1eb24, 0x102ce33c, + 0x1e504f5a, 0x5ab4c90f, 0x669ccca1, 0x118d5954, + 0x1a1e4a7c, 0x1807d1f9, 0x525a58d0, 0x2f13ae2d, + 0x17335a52, 0x714eb2f9, 0x1865dfc7, 0x61b64b52, + 0x0dc9e939, 0x4fccde4c, 0x6d5873af, 0x47c62b43, + 0x0fa1d4b0, 0x2f00cdf8, 0x68029083, 0x52645fa6, + 0x4bb37c9b, 0x53d60251, 0x48364566, 0x35b4889b, + 0x46783d34, 0x30c12697, 0x210459a1, 0x36962f2d, + 0x36305d8f, 0x170e9dbd, 0x687c8739, 0x261c14e4, + 0x3cc51cc7, 0x02add945, 0x01a88529, 0x6617aa77, + 0x6be627ca, 0x14c7fc46, 0x46fb3b41, 0x1bffff9e, + 0x1e6c61be, 0x10966c8f, 0x3f69199b, 0x1b5e9e06, + 0x4880890f, 0x055613e6, 0x6c742db5, 0x7be1e15e, + 0x2522e317, 0x41fe3369, 0x2b462f30, 0x605b7e8e, + 0x1c19b868, 0x3fadcb16, 0x781c5e24, 0x1c6b0c08, + 0x499f0bb9, 0x04b0b766, 0x7d6cad1e, 0x097f7d36, + 0x2e02956a, 0x03adc713, 0x4ce950b7, 0x6e57a313, + 0x557badb5, 0x73212afb, 0x3f7f6ed2, 0x0558e3d6, + 0x28376f73, 0x54dac21d, 0x6c3f4771, 0x67147bc8, + 0x5ae9fd88, 0x51ede3c0, 0x1067d134, 0x5246b937, + 0x056e74ed, 0x5d7869b2, 0x62356370, 0x76a0c583, + 0x3defb558, 0x5200dcae, 0x1432a7e8, 0x3ae4ad55, + 0x0c4cca8a, 0x0607c4d7, 0x1944ae2b, 0x726479f0, + 0x558e6035, 0x5ae64061, 0x4e1e9a8a, 0x0cf04d9f, + 0x46ef4a87, 0x0554224f, 0x70d70ab3, 0x03cc954e, + 0x39d0cd57, 0x1b11fb56, 0x62a0e9ee, 0x55888135, + 0x3e93ebeb, 0x29578ee1, 0x0bcb0ef4, 0x529e16af, + 0x165bab64, 0x39ed562e, 0x52c59d67, 0x48c84d29, + 0x0fd0d1c7, 0x795fd395, 0x79a1c4f3, 0x5010c835, + 0x4fbe4ba8, 0x49a597e9, 0x29f017ff, 0x59dde0be, + 0x2c660275, 0x15fcfbf7, 0x1eab540f, 0x38e2cf56, + 0x74608d5c, 0x7cd4b02c, 0x52a115b9, 0x2bdee9ac, + 0x5456c6da, 0x63626453, 0x15279241, 0x19b60519, + 0x508af0e1, 0x2e3ce97b, 0x568710d4, 0x6abb3059, + 0x7897b1a5, 0x17034ff6, 0x2aef7d5e, 0x5a281657, + 0x0fa5d304, 0x76f0a37e, 0x31be0f08, 0x46ce7c20, + 0x563e4e90, 0x31540773, 0x1cdc9c51, 0x10366bfa, + 0x1b6cd03a, 0x615f1540, 0x18c3d6c8, 0x3cb2bf8e, + 0x29bf799c, 0x40b87edb, 0x42c34863, 0x1e9edb40, + 0x64734fe2, 0x3ddf176a, 0x1c458c7f, 0x06138c9f, + 0x5e695e56, 0x02c98403, 0x0474de75, 0x660e1df8, + 0x6df73788, 0x3770f68c, 0x758bb7d5, 0x0763d105, + 0x16e61f16, 0x153974c1, 0x29ded842, 0x1a0d12c3, + 0x599ec61d, 0x05904d54, 0x79e9b0ea, 0x4976da61, + 0x5834243c, 0x67c17d2f, 0x65fbcda0, 0x17bdc554, + 0x465e9741, 0x7a0ee6d5, 0x3b357597, 0x0d1da287, + 0x01211373, 0x04a05de6, 0x5deb5dbd, 0x6d993eb0, + 0x2064ce7c, 0x3011a8c1, 0x36ece6b1, 0x4a0963be, + 0x0cf46ef0, 0x0d53ba44, 0x63260063, 0x187f1d6e, + 0x7e866a7e, 0x4b6885af, 0x254d6d47, 0x715474fd, + 0x6896dcb2, 0x7554eea6, 0x2161bf36, 0x5387f5f8, + 0x5c4bc064, 0x059a7755, 0x7d4307e1, 0x17326e2f, + 0x5e2315c1, 0x14c26eae, 0x1e5cd6f2, 0x352b7ac8, + 0x66591ef3, 0x381e80cd, 0x19b3bfc1, 0x3668946f, + 0x4b6d7d70, 0x20feab7d, 0x1b6340af, 0x356b6cab, + 0x299099dc, 0x295ab8d4, 0x184c8623, 0x134f8e4c, + 0x7caf609c, 0x716d81f9, 0x2e04231f, 0x1dd45301, + 0x43e9fcf9, 0x1c225c06, 0x0994797e, 0x5b3f6006, + 0x1d22dcec, 0x32993108, 0x3f0c2bcc, 0x4d44fbfa, + 0x389de78c, 0x7f8be723, 0x5dab92c1, 0x7866afce, + 0x3bfc7011, 0x4a27d7d3, 0x0c79d05c, 0x268dc4da, + 0x3fe10f84, 0x1f18394d, 0x20b9ba99, 0x312e520a, + 0x64cf2f05, 0x322a7c04, 0x4cc077ce, 0x7218aa35, + 0x550cacb8, 0x5943be47, 0x15b346a8, 0x0d6a1d8e, + 0x3f08a54d, 0x7a6e9807, 0x274f8bbc, 0x6feb2033, + 0x64b10c2b, 0x2cbaa0b7, 0x0db7decc, 0x22b807e3, + 0x10d15c39, 0x6a9b314c, 0x5ff27199, 0x5072b2cd, + 0x4eaf4b49, 0x5a890464, 0x7df0ca60, 0x548e8983, + 0x5e3f0a21, 0x70027683, 0x503e6bf2, 0x47ad6e0d, + 0x77173b26, 0x6dc04878, 0x4d73a573, 0x439b4a1a, + 0x2e6569a7, 0x1630e5de, 0x1be363af, 0x6f5f0e52, + 0x5b266bc3, 0x2f2a51be, 0x204e7e14, 0x1b3314c6, + 0x4472b8f9, 0x4162fb52, 0x72549950, 0x3223f889, + 0x0e655f4a, 0x65c3dce4, 0x04825988, 0x22b41458, + 0x53a4e10d, 0x3e2a66d5, 0x29de3e31, 0x0252fa74, + 0x267fe54f, 0x42d6d8ba, 0x5951218f, 0x73db5791, + 0x618444e4, 0x79abcaa1, 0x0ddcf5c8, 0x2cbed2e6, + 0x73159e0e, 0x7aadc871, 0x10e3f9a4, 0x762e9d65, + 0x2a7138c9, 0x59fe016f, 0x5b6c3ee4, 0x28888205, + 0x695fa5b1, 0x50f92ddd, 0x07eefc3b, 0x42bb693a, + 0x71312191, 0x3653ecbd, 0x1d80c4ed, 0x5a536187, + 0x6a286789, 0x4a1ffbb3, 0x1e976003, 0x5a8c5f29, + 0x2ac83bdb, 0x5ab9cb08, 0x63039928, 0x5a4c04f4, + 0x7b329952, 0x40d40fcb, 0x01810524, 0x2555e83c, + 0x748d0b4f, 0x534f1612, 0x272353f2, 0x6992e1ea, + 0x33cc5e71, 0x5163b55e, 0x29886a7f, 0x7cfb1eae, + 0x330271e0, 0x6f05e91c, 0x35b01e02, 0x64bbc053, + 0x76eb9337, 0x62612f48, 0x044e0af2, 0x1dac022e, + 0x1ca56f0c, 0x0210ef2c, 0x5af7a1a9, 0x2632f2b0, + 0x23d0401c, 0x0c594a46, 0x77582293, 0x297df41b, + 0x4c7b8718, 0x6c48d948, 0x4835e412, 0x74795651, + 0x28ca3506, 0x4071f739, 0x032fdbf2, 0x097f7bc8, + 0x44ced256, 0x47f25cb9, 0x43500684, 0x45481b9a, + 0x5a5ecc82, 0x4fe9ed61, 0x337ee559, 0x556852b9, + 0x0b24b460, 0x696db949, 0x7a2def9d, 0x4fcd5640, + 0x1babd707, 0x5c9254a3, 0x44d26e0d, 0x0e26b8e4, + 0x3b1c3b5c, 0x0078c784, 0x27a7dc96, 0x1d525589, + 0x4384ae38, 0x447b77c3, 0x78488b8c, 0x5eab10f1, + 0x16812737, 0x37cc8efa, 0x219cda83, 0x00bcc48f, + 0x3c667020, 0x492d7eaa, 0x710d06ce, 0x4172c47a, + 0x358098ec, 0x1fff647b, 0x65672792, 0x1a7b927d, + 0x24006275, 0x04e630a0, 0x2f2a9185, 0x5873704b, + 0x0a8c69bc, 0x06b49059, 0x49837c48, 0x4f90a2d0, + 0x29ad7dd7, 0x3674be92, 0x46d5635f, 0x782758a2, + 0x721a2a75, 0x13427ca9, 0x20e03cc9, 0x5f884596, + 0x19dc210f, 0x066c954d, 0x52f43f40, 0x5d9c256f, + 0x7f0acaae, 0x1e186b81, 0x55e9920f, 0x0e4f77b2, + 0x6700ec53, 0x268837c0, 0x554ce08b, 0x4284e695, + 0x2127e806, 0x384cb53b, 0x51076b2f, 0x23f9eb15 +}; + +// We don't need this generator in release. +#ifdef TEST +// generator for above +static void +ink_init_MMH() +{ + srand48(13); // must remain the same! + for (int i = 0; i < MMH_X_SIZE; i++) + MMH_x[i] = lrand48(); +} +#endif /* TEST */ + + +#ifndef __GNUC__ +// these are short < 16 bytes, help by permitting inlining +static inline void +_memcpy(void *dest, const void *src, int nbytes) +{ + for (int i = 0; i < nbytes; i++) + ((char *) dest)[i] = ((char *) src)[i]; +} + +#define memcpy _memcpy +#endif + +int +ink_code_incr_MMH_init(MMH_CTX * ctx) +{ + ctx->buffer_size = 0; + ctx->blocks = 0; + ctx->state[0] = ((uint64_t) MMH_x[MMH_X_SIZE + 0] << 32) + MMH_x[MMH_X_SIZE + 1]; + ctx->state[1] = ((uint64_t) MMH_x[MMH_X_SIZE + 2] << 32) + MMH_x[MMH_X_SIZE + 3]; + ctx->state[2] = ((uint64_t) MMH_x[MMH_X_SIZE + 4] << 32) + MMH_x[MMH_X_SIZE + 5]; + ctx->state[3] = ((uint64_t) MMH_x[MMH_X_SIZE + 6] << 32) + MMH_x[MMH_X_SIZE + 7]; + return 0; +} + +int +ink_code_MMH(unsigned char *input, int len, unsigned char *sixteen_byte_hash) +{ + MMH_CTX ctx; + ink_code_incr_MMH_init(&ctx); + ink_code_incr_MMH_update(&ctx, (const char *) input, len); + ink_code_incr_MMH_final((char *) sixteen_byte_hash, &ctx); + return 0; +} + +static inline void +MMH_update(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) ab; + ctx->state[0] += b[0] * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b[1] * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b[2] * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b[3] * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +static inline void +MMH_updateb1(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) (ab - 1); + uint32_t b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4]; + b0 = (b0 << 8) + (b1 >> 24); + b1 = (b1 << 8) + (b2 >> 24); + b2 = (b2 << 8) + (b3 >> 24); + b3 = (b3 << 8) + (b4 >> 24); + ctx->state[0] += b0 * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b1 * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b2 * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b3 * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +static inline void +MMH_updateb2(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) (ab - 2); + uint32_t b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4]; + b0 = (b0 << 16) + (b1 >> 16); + b1 = (b1 << 16) + (b2 >> 16); + b2 = (b2 << 16) + (b3 >> 16); + b3 = (b3 << 16) + (b4 >> 16); + ctx->state[0] += b0 * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b1 * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b2 * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b3 * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +static inline void +MMH_updateb3(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) (ab - 3); + uint32_t b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4]; + b0 = (b0 << 24) + (b1 >> 8); + b1 = (b1 << 24) + (b2 >> 8); + b2 = (b2 << 24) + (b3 >> 8); + b3 = (b3 << 24) + (b4 >> 8); + ctx->state[0] += b0 * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b1 * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b2 * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b3 * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +static inline void +MMH_updatel1(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) (ab - 1); + uint32_t b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4]; + b0 = (b0 >> 8) + (b1 << 24); + b1 = (b1 >> 8) + (b2 << 24); + b2 = (b2 >> 8) + (b3 << 24); + b3 = (b3 >> 8) + (b4 << 24); + ctx->state[0] += b0 * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b1 * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b2 * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b3 * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +static inline void +MMH_updatel2(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) (ab - 2); + uint32_t b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4]; + b0 = (b0 >> 16) + (b1 << 16); + b1 = (b1 >> 16) + (b2 << 16); + b2 = (b2 >> 16) + (b3 << 16); + b3 = (b3 >> 16) + (b4 << 16); + ctx->state[0] += b0 * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b1 * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b2 * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b3 * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +static inline void +MMH_updatel3(MMH_CTX * ctx, unsigned char *ab) +{ + uint32_t *b = (uint32_t *) (ab - 3); + uint32_t b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4]; + b0 = (b0 >> 24) + (b1 << 8); + b1 = (b1 >> 24) + (b2 << 8); + b2 = (b2 >> 24) + (b3 << 8); + b3 = (b3 >> 24) + (b4 << 8); + ctx->state[0] += b0 * MMH_x[(ctx->blocks + 0) % MMH_X_SIZE]; + ctx->state[1] += b1 * MMH_x[(ctx->blocks + 1) % MMH_X_SIZE]; + ctx->state[2] += b2 * MMH_x[(ctx->blocks + 2) % MMH_X_SIZE]; + ctx->state[3] += b3 * MMH_x[(ctx->blocks + 3) % MMH_X_SIZE]; + ctx->blocks += 4; +} + +int +ink_code_incr_MMH_update(MMH_CTX * ctx, const char *ainput, int input_length) +{ + unsigned char *in = (unsigned char *) ainput; + unsigned char *end = in + input_length; + if (ctx->buffer_size) { + int l = 16 - ctx->buffer_size; + if (input_length >= l) { + memcpy(ctx->buffer + ctx->buffer_size, in, l); + ctx->buffer_size = 0; + in += l; + if (ctx->buffer_size & 0x0f) + return 0; + MMH_update(ctx, ctx->buffer); + } else + goto Lstore; + } + { + // check alignment + int alignment = (int)((intptr_t) in & 0x3); + if (alignment) { +#if defined(_BIG_ENDIAN) +#define big_endian 1 +#elif defined(_LITTLE_ENDIAN) +#define big_endian 0 +#else + unsigned int endian = 1; + int big_endian = !*(char *) &endian; +#endif + if (big_endian) { + if (alignment == 1) { + while (in + 16 <= end) { + MMH_updateb1(ctx, in); + in += 16; + } + } else if (alignment == 2) { + while (in + 16 <= end) { + MMH_updateb2(ctx, in); + in += 16; + } + } else if (alignment == 3) + while (in + 16 <= end) { + MMH_updateb3(ctx, in); + in += 16; + } + } else { + if (alignment == 1) { + while (in + 16 <= end) { + MMH_updatel1(ctx, in); + in += 16; + } + } else if (alignment == 2) { + while (in + 16 <= end) { + MMH_updatel2(ctx, in); + in += 16; + } + } else if (alignment == 3) + while (in + 16 <= end) { + MMH_updatel3(ctx, in); + in += 16; + } + } + } else { + while (in + 16 <= end) { + MMH_update(ctx, in); + in += 16; + } + } + } +Lstore: + if (end - in) { + int oldbs = ctx->buffer_size; + ctx->buffer_size += (int) (end - in); +#ifndef TEST + ink_assert(ctx->buffer_size < 16); +#endif + memcpy(ctx->buffer + oldbs, in, (int) (end - in)); + } + return 0; +} + +#if defined(__GNUC__) +#define _memset memset +#else +// NOT general purpose +inline void +_memset(unsigned char *b, int c, int len) +{ + (void) c; + int o = len & 0x3, i; + for (i = 0; i < o; i++) + b[i] = 0; + for (i = 0; i < (len - o) / 4; i++) + ((uint32_t *) (b + o))[i] = 0; +} +#endif + + +int +ink_code_incr_MMH_final(char *presult, MMH_CTX * ctx) +{ + unsigned int len = ctx->blocks * 4 + ctx->buffer_size; + // pad out to 16 bytes + if (ctx->buffer_size) { + _memset(ctx->buffer + ctx->buffer_size, 0, 16 - ctx->buffer_size); + ctx->buffer_size = 0; + MMH_update(ctx, ctx->buffer); + } + // append length (before padding) + unsigned int *pbuffer = (unsigned int *) ctx->buffer; + pbuffer[1] = pbuffer[2] = pbuffer[3] = pbuffer[0] = len; + MMH_update(ctx, ctx->buffer); + // final phase + uint32_t *b = (uint32_t *) presult; + uint64_t d = (((uint64_t) 1) << 32) + 15; + uint32_t b0 = uint32_t(ctx->state[0] % d); + uint32_t b1 = uint32_t(ctx->state[1] % d); + uint32_t b2 = uint32_t(ctx->state[2] % d); + uint32_t b3 = uint32_t(ctx->state[3] % d); + // scramble the bits, losslessly (reversibly) + b[0] = b0; + b[1] = b1 ^ (b0 >> 24) ^ (b0 << 8); + b[2] = b2 ^ (b1 >> 16) ^ (b1 << 16) + ^ (b0 >> 24) ^ (b0 << 8); + b[3] = b3 ^ (b1 >> 8) ^ (b1 << 24) + ^ (b2 >> 16) ^ (b2 << 16) + ^ (b0 >> 24) ^ (b0 << 8); + + b0 = b[0]; + b1 = b[1]; + b2 = b[2]; + b3 = b[3]; + + b[2] = b2 ^ (b3 >> 24) ^ (b3 << 8); + b[1] = b1 ^ (b2 >> 16) ^ (b2 << 16) + ^ (b3 >> 24) ^ (b3 << 8); + b[0] = b0 ^ (b3 >> 8) ^ (b3 << 24) + ^ (b2 >> 16) ^ (b2 << 16) + ^ (b1 >> 24) ^ (b1 << 8); + return 0; +} + +#ifdef TEST + +#define TEST_COLLISIONS 10000000 + +static int +xxcompar(uint32_t ** x, uint32_t ** y) +{ + for (int i = 0; i < 4; i++) { + if (x[i] > y[i]) + return 1; + if (x[i] < y[i]) + return -1; + } + return 0; +} + +typedef uint32_t i4_t[4]; +i4_t *xxh; +double *xf; + +main() +{ + union + { + unsigned char hash[16]; + uint32_t h[4]; + } h; + + xxh = (i4_t *) malloc(4 * sizeof(uint32_t) * TEST_COLLISIONS); + xf = (double *) malloc(sizeof(double) * TEST_COLLISIONS); + + printf("test collisions\n"); + char *sc1 = "http://npdev:19080/1.6664000000/4000"; + char *sc2 = "http://npdev:19080/1.8666000000/4000"; + char *sc3 = "http://:@npdev/1.6664000000/4000;?"; + char *sc4 = "http://:@npdev/1.8666000000/4000;?"; + ink_code_MMH((unsigned char *) sc1, strlen(sc1), h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + ink_code_MMH((unsigned char *) sc2, strlen(sc2), h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + ink_code_MMH((unsigned char *) sc3, strlen(sc3), h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + ink_code_MMH((unsigned char *) sc4, strlen(sc4), h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + + srand48(time(NULL)); + for (int xx = 0; xx < TEST_COLLISIONS; xx++) { + char xs[256]; + xf[xx] = drand48(); + sprintf(xs, "http://@npdev/%16.14f/4000;?", xf[xx]); + ink_code_MMH((unsigned char *) xs, strlen(xs), (unsigned char *) &xxh[xx]); + } + qsort(xxh, TEST_COLLISIONS, 16, xxcompar); + for (int xy = 0; xy < TEST_COLLISIONS - 1; xy++) { + if (xxh[xy][0] == xxh[xy + 1][0] && + xxh[xy][1] == xxh[xy + 1][1] && xxh[xy][2] == xxh[xy + 1][2] && xxh[xy][3] == xxh[xy + 1][3]) + printf("********** collision %d\n", xy); + } + + unsigned char *s = (unsigned char *) MMH_x; + int l = sizeof(MMH_x); + unsigned char *s1 = (unsigned char *) malloc(l + 3); + s1 += 1; + memcpy(s1, s, l); + unsigned char *s2 = (unsigned char *) malloc(l + 3); + s2 += 2; + memcpy(s2, s, l); + unsigned char *s3 = (unsigned char *) malloc(l + 3); + s3 += 3; + memcpy(s3, s, l); + + printf("test alignment\n"); + ink_code_MMH(s, l, h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + ink_code_MMH(s1, l, h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + ink_code_MMH(s2, l, h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + ink_code_MMH(s3, l, h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + + int i = 0; + MMH_CTX c; + unsigned char *t = s; + printf("test chunking\n"); + ink_code_incr_MMH_init(&c); + for (i = 0; i < 24; i++) { + ink_code_incr_MMH_update(&c, (char *) t, i); + t += i; + } + ink_code_incr_MMH_final((char *) h.hash, &c); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + int q = t - s; + ink_code_MMH(s, q, h.hash); + printf("%X %X %X %X\n", h.h[0], h.h[1], h.h[2], h.h[3]); + + FILE *fp = fopen("/kernel/genunix", "r"); + char x[4096]; + int hist[256]; + memset(hist, 0, sizeof(hist)); + size_t xx; + while (((xx = fread(x, 1, 128, fp)) == 128)) { + ink_code_MMH((unsigned char *) x, 128, h.hash); + hist[h.h[0] & 255]++; + } + for (int z = 0; z < 256; z++) { + printf("%6d ", hist[z]); + if (!(z % 7)) + printf("\n"); + } +} +#endif + +#endif diff --git a/lib/ts/MMH.h b/lib/ts/MMH.h new file mode 100644 index 00000000..c31ed89a --- /dev/null +++ b/lib/ts/MMH.h @@ -0,0 +1,146 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _MMH_h_ +#define _MMH_h_ + +#ifndef USE_MD5_FOR_MMH + +#include "ink_bool.h" +#include "ink_code.h" +#include "ink_port.h" + +struct MMH_CTX +{ + uint64_t state[4]; + unsigned char buffer[32]; + int buffer_size; + int blocks; +}; + +// signed-unsigned-const gratuitous differences brought +// to you by history and the ANSI committee + +int inkcoreapi ink_code_incr_MMH_init(MMH_CTX * context); +int inkcoreapi ink_code_incr_MMH_update(MMH_CTX * context, const char *input, int input_length); +int inkcoreapi ink_code_incr_MMH_final(char *sixteen_byte_hash_pointer, MMH_CTX * context); +int inkcoreapi ink_code_MMH(unsigned char *input, int len, unsigned char *sixteen_byte_hash); + +/** + MMH will return different values on big-endian and little-endian + machines. It can be adapted to return the same values at some additional + cost. + +*/ +struct MMH +{ + uint64_t b[2]; + MMH & operator =(MMH & MMH) + { + b[0] = MMH.b[0]; + b[1] = MMH.b[1]; + return MMH; + } + MMH & loadFromBuffer(char *MMH_buf) + { + int i; + char *s, *d; + + for (i = 0, s = MMH_buf, d = (char *) (&(b[0])); i < 8; i++, *d++ = *s++); + for (i = 0, d = (char *) (&(b[1])); i < 8; i++, *d++ = *s++); + return (*this); + } + MMH & storeToBuffer(char *MMH_buf) { + int i; + char *s, *d; + + for (i = 0, d = MMH_buf, s = (char *) (&(b[0])); i < 8; i++, *d++ = *s++); + for (i = 0, s = (char *) (&(b[1])); i < 8; i++, *d++ = *s++); + return (*this); + } + MMH & operator =(char *MMH) { + return (loadFromBuffer(MMH)); + } + MMH & operator =(unsigned char *MMH) { + return (loadFromBuffer((char *) MMH)); + } + + char *toStr(char *MMH_str) const + { + int i; + char *s, *d; + + for (i = 0, d = MMH_str, s = (char *) (&(b[0])); i < 8; i++, *d++ = *s++); + for (i = 0, s = (char *) (&(b[1])); i < 8; i++, *d++ = *s++); + + return (MMH_str); + } + void encodeBuffer(unsigned char *buffer, int len) + { + unsigned char MMH[16]; + ink_code_MMH(buffer, len, MMH); + *this = MMH; + } + void encodeBuffer(char *buffer, int len) + { + encodeBuffer((unsigned char *) buffer, len); + } + char *str() const + { + return ((char *) b); + } + char *toHexStr(char hex_MMH[33]) + { + return (ink_code_md5_stringify_fast(hex_MMH, str())); + } + uint64_t fold() const + { + return (b[0] ^ b[1]); + } + uint64_t operator[] (int i) const + { + return b[i]; + } + bool operator==(const MMH & MMH) const + { + return b[0] == MMH.b[0] && b[1] == MMH.b[1]; + } + MMH() + { + b[0] = 0; + b[1] = 0; + } +}; + +#else + +#include "INK_MD5.h" +#define MMH INK_MD5 +#define MMH_CTX INK_DIGEST_CTX +#define ink_code_incr_MMH_init ink_code_incr_md5_init +#define ink_code_incr_MMH_update ink_code_incr_md5_update +#define ink_code_incr_MMH_final ink_code_incr_md5_final +#define ink_code_MMH ink_code_md5 + +#endif +#endif diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am new file mode 100644 index 00000000..8e73aaea --- /dev/null +++ b/lib/ts/Makefile.am @@ -0,0 +1,189 @@ +# libts Makefile.am +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +noinst_PROGRAMS = mkdfa CompileParseRules +check_PROGRAMS = test_atomic test_freelist test_arena test_List test_Map test_Vec +TESTS = $(check_PROGRAMS) + +lib_LTLIBRARIES = libtsutil.la + +libtsutil_la_LDFLAGS = -no-undefined -version-info @TS_LIBTOOL_VERSION@ +libtsutil_la_LIBADD = @LIBOBJS@ @LIBPCRE@ @LIBSSL@ @LIBTCL@ @LIBRESOLV@ @LIBRT@ @LIBICONV@ @LIBSOCKET@ @LIBNSL@ @LIBCAP@ -lc + +libtsutil_la_SOURCES = \ + Allocator.cc \ + Allocator.h \ + Arena.cc \ + Arena.h \ + Bitops.cc \ + Bitops.h \ + Compatability.h \ + DAllocator.h \ + Diags.cc \ + Diags.h \ + DynArray.h \ + HostLookup.cc \ + HostLookup.h \ + defalloc.h \ + ink_aiocb.h \ + ink_align.h \ + ink_apidefs.h \ + ink_args.cc \ + ink_args.h \ + ink_assert.cc \ + ink_assert.h \ + ink_atomic.h \ + ink_auth_api.cc \ + ink_auth_api.h \ + ink_base64.cc \ + ink_base64.h \ + ink_bool.h \ + ink_cap.cc ink_cap.h \ + ink_code.cc \ + ink_code.h \ + ink_defs.cc \ + ink_defs.h \ + InkErrno.h \ + ink_error.cc \ + ink_error.h \ + ink_exception.h \ + ink_file.cc \ + ink_file.h \ + ink_hash_table.cc \ + ink_hash_table.h \ + ink_hrtime.cc \ + ink_hrtime.h \ + ink_inet.cc \ + ink_inet.h \ + ink_inout.h \ + ink_isolatin_table.cc \ + ink_isolatin_table.h \ + ink_killall.cc \ + ink_killall.h \ + ink_llqueue.h \ + ink_lockfile.h \ + INK_MD5.h \ + ink_memory.cc \ + ink_memory.h \ + ink_mutex.cc \ + ink_mutex.h \ + ink_platform.h \ + InkPool.h \ + ink_port.h \ + ink_queue.cc \ + ink_queue.h \ + ink_queue_utils.cc \ + ink_rand.cc \ + ink_rand.h \ + ink_res_init.cc \ + ink_res_mkquery.cc \ + ink_resolver.h \ + ink_resource.cc \ + ink_resource.h \ + ink_rwlock.cc \ + ink_rwlock.h \ + ink_sock.cc \ + ink_sock.h \ + ink_sprintf.cc \ + ink_sprintf.h \ + ink_stack_trace.cc \ + ink_stack_trace.h \ + ink_string.cc \ + ink_string++.cc \ + ink_string.h \ + ink_string++.h \ + ink_sys_control.cc \ + ink_sys_control.h \ + ink_syslog.cc \ + ink_syslog.h \ + ink_thread.cc \ + ink_thread.h \ + ink_time.cc \ + ink_time.h \ + inktomi++.h \ + ink_unused.h \ + fastlz.h \ + fastlz.c \ + I_Version.h \ + List.h \ + llqueue.cc \ + lockfile.cc \ + I_Layout.h \ + Layout.cc \ + MatcherUtils.cc \ + MatcherUtils.h \ + MimeTable.cc \ + MimeTable.h \ + MMH.cc \ + MMH.h \ + ParseRules.h \ + ParseRules.cc \ + Ptr.h \ + RawHashTable.cc \ + RawHashTable.h \ + Regex.cc \ + Regex.h \ + Regression.cc \ + Regression.h \ + Resource.cc \ + Resource.h \ + SimpleTokenizer.h \ + TextBuffer.cc \ + TextBuffer.h \ + Tokenizer.cc \ + Tokenizer.h \ + Vec.h \ + Vec.cc \ + Map.h \ + Version.cc + +# Special hacks to generate the parser rules +ParseRules.cc: ParseRulesCType + +ParseRulesCType: CompileParseRules + ./CompileParseRules + +mkdfa_SOURCES = mkdfa.c + +test_atomic_SOURCES = test_atomic.cc +test_atomic_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@ +test_atomic_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ + +test_freelist_SOURCES = test_freelist.cc +test_freelist_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@ +test_freelist_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ + +test_arena_SOURCES = test_arena.cc +test_arena_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@ +test_arena_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ + +test_List_SOURCES = test_List.cc +test_Map_SOURCES = test_Map.cc +test_Map_LDADD = libtsutil.la +test_Vec_SOURCES = test_Vec.cc +test_Vec_LDADD = libtsutil.la + +CompileParseRules_SOURCES = CompileParseRules.cc + +test:: $(TESTS) + for f in $(TESTS) ; do $$f ; done + +#$(foreach F, $(TESTS), $(shell $F)) + +clean-local: + rm -f ParseRulesCType ParseRulesCTypeToLower ParseRulesCTypeToUpper diff --git a/lib/ts/Makefile.in b/lib/ts/Makefile.in new file mode 100644 index 00000000..b0b1bf1c --- /dev/null +++ b/lib/ts/Makefile.in @@ -0,0 +1,1201 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# libts Makefile.am +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = mkdfa$(EXEEXT) CompileParseRules$(EXEEXT) +check_PROGRAMS = test_atomic$(EXEEXT) test_freelist$(EXEEXT) \ + test_arena$(EXEEXT) test_List$(EXEEXT) test_Map$(EXEEXT) \ + test_Vec$(EXEEXT) +subdir = lib/ts +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/ink_autoconf.h.in $(srcdir)/ink_config.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = ink_autoconf.h +CONFIG_CLEAN_FILES = ink_config.h +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libtsutil_la_DEPENDENCIES = @LIBOBJS@ +am_libtsutil_la_OBJECTS = Allocator.lo Arena.lo Bitops.lo Diags.lo \ + HostLookup.lo ink_args.lo ink_assert.lo ink_auth_api.lo \ + ink_base64.lo ink_cap.lo ink_code.lo ink_defs.lo ink_error.lo \ + ink_file.lo ink_hash_table.lo ink_hrtime.lo ink_inet.lo \ + ink_isolatin_table.lo ink_killall.lo ink_memory.lo \ + ink_mutex.lo ink_queue.lo ink_queue_utils.lo ink_rand.lo \ + ink_res_init.lo ink_res_mkquery.lo ink_resource.lo \ + ink_rwlock.lo ink_sock.lo ink_sprintf.lo ink_stack_trace.lo \ + ink_string.lo ink_string++.lo ink_sys_control.lo ink_syslog.lo \ + ink_thread.lo ink_time.lo fastlz.lo llqueue.lo lockfile.lo \ + Layout.lo MatcherUtils.lo MimeTable.lo MMH.lo ParseRules.lo \ + RawHashTable.lo Regex.lo Regression.lo Resource.lo \ + TextBuffer.lo Tokenizer.lo Vec.lo Version.lo +libtsutil_la_OBJECTS = $(am_libtsutil_la_OBJECTS) +libtsutil_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libtsutil_la_LDFLAGS) $(LDFLAGS) -o $@ +PROGRAMS = $(noinst_PROGRAMS) +am_CompileParseRules_OBJECTS = CompileParseRules.$(OBJEXT) +CompileParseRules_OBJECTS = $(am_CompileParseRules_OBJECTS) +CompileParseRules_LDADD = $(LDADD) +am_mkdfa_OBJECTS = mkdfa.$(OBJEXT) +mkdfa_OBJECTS = $(am_mkdfa_OBJECTS) +mkdfa_LDADD = $(LDADD) +am_test_List_OBJECTS = test_List.$(OBJEXT) +test_List_OBJECTS = $(am_test_List_OBJECTS) +test_List_LDADD = $(LDADD) +am_test_Map_OBJECTS = test_Map.$(OBJEXT) +test_Map_OBJECTS = $(am_test_Map_OBJECTS) +test_Map_DEPENDENCIES = libtsutil.la +am_test_Vec_OBJECTS = test_Vec.$(OBJEXT) +test_Vec_OBJECTS = $(am_test_Vec_OBJECTS) +test_Vec_DEPENDENCIES = libtsutil.la +am_test_arena_OBJECTS = test_arena.$(OBJEXT) +test_arena_OBJECTS = $(am_test_arena_OBJECTS) +test_arena_DEPENDENCIES = libtsutil.la +test_arena_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(test_arena_LDFLAGS) $(LDFLAGS) -o $@ +am_test_atomic_OBJECTS = test_atomic.$(OBJEXT) +test_atomic_OBJECTS = $(am_test_atomic_OBJECTS) +test_atomic_DEPENDENCIES = libtsutil.la +test_atomic_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(test_atomic_LDFLAGS) $(LDFLAGS) -o $@ +am_test_freelist_OBJECTS = test_freelist.$(OBJEXT) +test_freelist_OBJECTS = $(am_test_freelist_OBJECTS) +test_freelist_DEPENDENCIES = libtsutil.la +test_freelist_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(test_freelist_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libtsutil_la_SOURCES) $(CompileParseRules_SOURCES) \ + $(mkdfa_SOURCES) $(test_List_SOURCES) $(test_Map_SOURCES) \ + $(test_Vec_SOURCES) $(test_arena_SOURCES) \ + $(test_atomic_SOURCES) $(test_freelist_SOURCES) +DIST_SOURCES = $(libtsutil_la_SOURCES) $(CompileParseRules_SOURCES) \ + $(mkdfa_SOURCES) $(test_List_SOURCES) $(test_Map_SOURCES) \ + $(test_Vec_SOURCES) $(test_arena_SOURCES) \ + $(test_atomic_SOURCES) $(test_freelist_SOURCES) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +TESTS = $(check_PROGRAMS) +lib_LTLIBRARIES = libtsutil.la +libtsutil_la_LDFLAGS = -no-undefined -version-info @TS_LIBTOOL_VERSION@ +libtsutil_la_LIBADD = @LIBOBJS@ @LIBPCRE@ @LIBSSL@ @LIBTCL@ @LIBRESOLV@ @LIBRT@ @LIBICONV@ @LIBSOCKET@ @LIBNSL@ @LIBCAP@ -lc +libtsutil_la_SOURCES = \ + Allocator.cc \ + Allocator.h \ + Arena.cc \ + Arena.h \ + Bitops.cc \ + Bitops.h \ + Compatability.h \ + DAllocator.h \ + Diags.cc \ + Diags.h \ + DynArray.h \ + HostLookup.cc \ + HostLookup.h \ + defalloc.h \ + ink_aiocb.h \ + ink_align.h \ + ink_apidefs.h \ + ink_args.cc \ + ink_args.h \ + ink_assert.cc \ + ink_assert.h \ + ink_atomic.h \ + ink_auth_api.cc \ + ink_auth_api.h \ + ink_base64.cc \ + ink_base64.h \ + ink_bool.h \ + ink_cap.cc ink_cap.h \ + ink_code.cc \ + ink_code.h \ + ink_defs.cc \ + ink_defs.h \ + InkErrno.h \ + ink_error.cc \ + ink_error.h \ + ink_exception.h \ + ink_file.cc \ + ink_file.h \ + ink_hash_table.cc \ + ink_hash_table.h \ + ink_hrtime.cc \ + ink_hrtime.h \ + ink_inet.cc \ + ink_inet.h \ + ink_inout.h \ + ink_isolatin_table.cc \ + ink_isolatin_table.h \ + ink_killall.cc \ + ink_killall.h \ + ink_llqueue.h \ + ink_lockfile.h \ + INK_MD5.h \ + ink_memory.cc \ + ink_memory.h \ + ink_mutex.cc \ + ink_mutex.h \ + ink_platform.h \ + InkPool.h \ + ink_port.h \ + ink_queue.cc \ + ink_queue.h \ + ink_queue_utils.cc \ + ink_rand.cc \ + ink_rand.h \ + ink_res_init.cc \ + ink_res_mkquery.cc \ + ink_resolver.h \ + ink_resource.cc \ + ink_resource.h \ + ink_rwlock.cc \ + ink_rwlock.h \ + ink_sock.cc \ + ink_sock.h \ + ink_sprintf.cc \ + ink_sprintf.h \ + ink_stack_trace.cc \ + ink_stack_trace.h \ + ink_string.cc \ + ink_string++.cc \ + ink_string.h \ + ink_string++.h \ + ink_sys_control.cc \ + ink_sys_control.h \ + ink_syslog.cc \ + ink_syslog.h \ + ink_thread.cc \ + ink_thread.h \ + ink_time.cc \ + ink_time.h \ + inktomi++.h \ + ink_unused.h \ + fastlz.h \ + fastlz.c \ + I_Version.h \ + List.h \ + llqueue.cc \ + lockfile.cc \ + I_Layout.h \ + Layout.cc \ + MatcherUtils.cc \ + MatcherUtils.h \ + MimeTable.cc \ + MimeTable.h \ + MMH.cc \ + MMH.h \ + ParseRules.h \ + ParseRules.cc \ + Ptr.h \ + RawHashTable.cc \ + RawHashTable.h \ + Regex.cc \ + Regex.h \ + Regression.cc \ + Regression.h \ + Resource.cc \ + Resource.h \ + SimpleTokenizer.h \ + TextBuffer.cc \ + TextBuffer.h \ + Tokenizer.cc \ + Tokenizer.h \ + Vec.h \ + Vec.cc \ + Map.h \ + Version.cc + +mkdfa_SOURCES = mkdfa.c +test_atomic_SOURCES = test_atomic.cc +test_atomic_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@ +test_atomic_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +test_freelist_SOURCES = test_freelist.cc +test_freelist_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@ +test_freelist_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +test_arena_SOURCES = test_arena.cc +test_arena_LDADD = libtsutil.la @LIBTHREAD@ @LIBTCL@ @LIBICONV@ @LIBEXECINFO@ +test_arena_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +test_List_SOURCES = test_List.cc +test_Map_SOURCES = test_Map.cc +test_Map_LDADD = libtsutil.la +test_Vec_SOURCES = test_Vec.cc +test_Vec_LDADD = libtsutil.la +CompileParseRules_SOURCES = CompileParseRules.cc +all: ink_autoconf.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/ts/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/ts/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +ink_autoconf.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/ink_autoconf.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status lib/ts/ink_autoconf.h +$(srcdir)/ink_autoconf.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f ink_autoconf.h stamp-h1 +ink_config.h: $(top_builddir)/config.status $(srcdir)/ink_config.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libtsutil.la: $(libtsutil_la_OBJECTS) $(libtsutil_la_DEPENDENCIES) + $(libtsutil_la_LINK) -rpath $(libdir) $(libtsutil_la_OBJECTS) $(libtsutil_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +CompileParseRules$(EXEEXT): $(CompileParseRules_OBJECTS) $(CompileParseRules_DEPENDENCIES) + @rm -f CompileParseRules$(EXEEXT) + $(CXXLINK) $(CompileParseRules_OBJECTS) $(CompileParseRules_LDADD) $(LIBS) +mkdfa$(EXEEXT): $(mkdfa_OBJECTS) $(mkdfa_DEPENDENCIES) + @rm -f mkdfa$(EXEEXT) + $(LINK) $(mkdfa_OBJECTS) $(mkdfa_LDADD) $(LIBS) +test_List$(EXEEXT): $(test_List_OBJECTS) $(test_List_DEPENDENCIES) + @rm -f test_List$(EXEEXT) + $(CXXLINK) $(test_List_OBJECTS) $(test_List_LDADD) $(LIBS) +test_Map$(EXEEXT): $(test_Map_OBJECTS) $(test_Map_DEPENDENCIES) + @rm -f test_Map$(EXEEXT) + $(CXXLINK) $(test_Map_OBJECTS) $(test_Map_LDADD) $(LIBS) +test_Vec$(EXEEXT): $(test_Vec_OBJECTS) $(test_Vec_DEPENDENCIES) + @rm -f test_Vec$(EXEEXT) + $(CXXLINK) $(test_Vec_OBJECTS) $(test_Vec_LDADD) $(LIBS) +test_arena$(EXEEXT): $(test_arena_OBJECTS) $(test_arena_DEPENDENCIES) + @rm -f test_arena$(EXEEXT) + $(test_arena_LINK) $(test_arena_OBJECTS) $(test_arena_LDADD) $(LIBS) +test_atomic$(EXEEXT): $(test_atomic_OBJECTS) $(test_atomic_DEPENDENCIES) + @rm -f test_atomic$(EXEEXT) + $(test_atomic_LINK) $(test_atomic_OBJECTS) $(test_atomic_LDADD) $(LIBS) +test_freelist$(EXEEXT): $(test_freelist_OBJECTS) $(test_freelist_DEPENDENCIES) + @rm -f test_freelist$(EXEEXT) + $(test_freelist_LINK) $(test_freelist_OBJECTS) $(test_freelist_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Allocator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Arena.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Bitops.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompileParseRules.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Diags.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HostLookup.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Layout.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MMH.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MatcherUtils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MimeTable.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ParseRules.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RawHashTable.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Regex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Regression.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Resource.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TextBuffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tokenizer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Vec.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Version.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fastlz.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_args.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_assert.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_auth_api.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_base64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_cap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_code.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_defs.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_hash_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_hrtime.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_inet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_isolatin_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_killall.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_memory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_mutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_queue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_queue_utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_rand.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_res_init.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_res_mkquery.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_resource.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_rwlock.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_sock.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_sprintf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_stack_trace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_string++.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_string.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_sys_control.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_syslog.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_thread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ink_time.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/llqueue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lockfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkdfa.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_List.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Map.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_Vec.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arena.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_atomic.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_freelist.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) ink_autoconf.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) ink_autoconf.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) ink_autoconf.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) ink_autoconf.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) ink_autoconf.h +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-local clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: all check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-local clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Special hacks to generate the parser rules +ParseRules.cc: ParseRulesCType + +ParseRulesCType: CompileParseRules + ./CompileParseRules + +test:: $(TESTS) + for f in $(TESTS) ; do $$f ; done + +#$(foreach F, $(TESTS), $(shell $F)) + +clean-local: + rm -f ParseRulesCType ParseRulesCTypeToLower ParseRulesCTypeToUpper + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/ts/Map.h b/lib/ts/Map.h new file mode 100644 index 00000000..81732dfd --- /dev/null +++ b/lib/ts/Map.h @@ -0,0 +1,937 @@ +/** @file + + A set of Map templates. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _map_H_ +#define _map_H_ + +#include +#include +#include "ink_assert.h" +#include "List.h" +#include "Vec.h" + +#define MAP_INTEGRAL_SIZE (1 << (2)) +#define MAP_INITIAL_SHIFT ((2)+1) +#define MAP_INITIAL_SIZE (1 << MAP_INITIAL_SHIFT) + +typedef const char cchar; + +template +static inline char * +_dupstr(cchar *s, cchar *e = 0) { + int l = e ? e-s : strlen(s); + char *ss = (char*)A::alloc(l+1); + memcpy(ss, s, l); + ss[l] = 0; + return ss; +} + +// Simple direct mapped Map (pointer hash table) and Environment + +template class MapElem { + public: + K key; + C value; + bool operator==(MapElem &e) { return e.key == key; } + operator uintptr_t(void) { return (uintptr_t)(uintptr_t)key; } + MapElem(uintptr_t x) { ink_assert(!x); key = 0; } + MapElem(K akey, C avalue) : key(akey), value(avalue) {} + MapElem(MapElem &e) : key(e.key), value(e.value) {} + MapElem() : key(0) {} +}; + +template class Map : public Vec, A> { + public: + typedef MapElem ME; + typedef Vec PType; + using PType::n; + using PType::i; + using PType::v; + ME *put(K akey, C avalue); + ME *put(K akey); + C get(K akey); + C *getp(K akey); + void get_keys(Vec &keys); + void get_keys_set(Vec &keys); + void get_values(Vec &values); + void map_union(Map &m); + int some_disjunction(Map &m); +}; + +template class HashFns { + public: + static uintptr_t hash(C a); + static int equal(C a, C b); +}; + +template class HashSetFns { + public: + static uintptr_t hash(C a); + static uintptr_t hash(K a); + static int equal(C a, C b); + static int equal(K a, C b); +}; + +template class HashMap : public Map { + public: + using Map::n; + using Map::i; + using Map::v; + using Map::e; + MapElem *get_internal(K akey); + C get(K akey); + MapElem *put(K akey, C avalue); + void get_keys(Vec &keys); + void get_values(Vec &values); +}; + +#define form_Map(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = &(_v).v[0]; \ + ((intptr_t)(qq__##_p) < (_v).n) && ((_p = &(_v).v[(intptr_t)qq__##_p]) || 1); \ + qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1)) \ + if ((_p)->key) + + +template class HashSet : public Vec { + public: + typedef Vec V; + using V::n; + using V::i; + using V::v; + using V::e; + C get(K akey); + C *put( C avalue); +}; + +class StringHashFns { + public: + static uintptr_t hash(cchar *s) { + uintptr_t h = 0; + // 31 changed to 27, to avoid prime2 in vec.cpp + while (*s) h = h * 27 + (unsigned char)*s++; + return h; + } + static int equal(cchar *a, cchar *b) { return !strcmp(a, b); } +}; + +class CaseStringHashFns { + public: + static uintptr_t hash(cchar *s) { + uintptr_t h = 0; + // 31 changed to 27, to avoid prime2 in vec.cpp + while (*s) h = h * 27 + (unsigned char)toupper(*s++); + return h; + } + static int equal(cchar *a, cchar *b) { return !strcasecmp(a, b); } +}; + +class PointerHashFns { + public: + static uintptr_t hash(void *s) { return (uintptr_t)(uintptr_t)s; } + static int equal(void *a, void *b) { return a == b; } +}; + +template class ChainHash : public Map,A> { + public: + using Map,A>::n; + using Map,A>::v; + typedef ConsCell ChainCons; + C put(C c); + C get(C c); + C put_bag(C c); + int get_bag(C c,Vec &v); + int del(C avalue); + void get_elements(Vec &elements); +}; + +template class ChainHashMap : + public Map,A>,A> { + public: + using Map,A>,A>::n; + using Map,A>,A>::v; + MapElem *put(K akey, C avalue); + C get(K akey); + int del(K akey); + MapElem *put_bag(K akey, C c); + int get_bag(K akey, Vec &v); + void get_keys(Vec &keys); + void get_values(Vec &values); +}; + +template +class StringChainHash : public ChainHash { + public: + cchar *canonicalize(cchar *s, cchar *e); + cchar *canonicalize(cchar *s) { return canonicalize(s, s + strlen(s)); } +}; + +template class NBlockHash { + public: + int n; + int i; + C *v; + C e[N]; + + C* end() { return last(); } + int length() { return N * n; } + C *first(); + C *last(); + C put(C c); + C get(C c); + C* assoc_put(C *c); + C* assoc_get(C *c); + int del(C c); + void clear(); + void reset(); + int count(); + void size(int p2); + void copy(const NBlockHash &hh); + void move(NBlockHash &hh); + NBlockHash(); + NBlockHash(NBlockHash &hh) { v = e; copy(hh); } +}; + +/* use forv_Vec on BlockHashes */ + +#define DEFAULT_BLOCK_HASH_SIZE 4 +template class BlockHash : + public NBlockHash {}; +typedef BlockHash StringBlockHash; + +template class Env { + public: + typedef ConsCell EnvCons; + void put(K akey, C avalue); + C get(K akey); + void push(); + void pop(); + void clear() { store.clear(); scope.clear(); } + + Env() {} + Map *, A> store; + List, A> scope; + List *get_bucket(K akey); +}; + +/* IMPLEMENTATION */ + +template inline C +Map::get(K akey) { + MapElem e(akey, (C)0); + MapElem *x = this->set_in(e); + if (x) + return x->value; + return (C)0; +} + +template inline C * +Map::getp(K akey) { + MapElem e(akey, (C)0); + MapElem *x = this->set_in(e); + if (x) + return &x->value; + return 0; +} + +template inline MapElem * +Map::put(K akey, C avalue) { + MapElem e(akey, avalue); + MapElem *x = this->set_in(e); + if (x) { + x->value = avalue; + return x; + } else + return this->set_add(e); +} + +template inline MapElem * +Map::put(K akey) { + MapElem e(akey, 0); + MapElem *x = this->set_in(e); + if (x) + return x; + else + return this->set_add(e); +} + +template inline void +Map::get_keys(Vec &keys) { + for (int i = 0; i < n; i++) + if (v[i].key) + keys.add(v[i].key); +} + +template inline void +Map::get_keys_set(Vec &keys) { + for (int i = 0; i < n; i++) + if (v[i].key) + keys.set_add(v[i].key); +} + +template inline void +Map::get_values(Vec &values) { + for (int i = 0; i < n; i++) + if (v[i].key) + values.set_add(v[i].value); + values.set_to_vec(); +} + +template inline void +Map::map_union(Map &m) { + for (int i = 0; i < m.n; i++) + if (m.v[i].key) + put(m.v[i].key, m.v[i].value); +} + +template inline int +Map::some_disjunction(Map &m) { + for (int i = 0; i < m.n; i++) + if (m.v[i].key && get(m.v[i].key) != m.v[i].value) + return 1; + for (int i = 0; i < n; i++) + if (v[i].key && m.get(v[i].key) != v[i].value) + return 1; + return 0; +} + +template inline void +map_set_add(Map*,A> &m, K akey, C avalue) { + Vec *v = m.get(akey); + if (!v) + m.put(akey, (v = new Vec)); + v->set_add(avalue); +} + +template inline void +map_set_add(Map*,A> &m, K akey, Vec *madd) { + Vec *v = m.get(akey); + if (!v) + m.put(akey, (v = new Vec)); + v->set_union(*madd); +} + +template inline C +HashSet::get(K akey) { + if (!n) + return 0; + if (n <= MAP_INTEGRAL_SIZE) { + for (C *c = v; c < v + n; c++) + if (c) + if (AHashFns::equal(akey, *c)) + return *c; + return 0; + } + uintptr_t h = AHashFns::hash(akey); + h = h % n; + for (int k = h, j = 0; j < i + 3;j++) { + if (!v[k]) + return 0; + else if (AHashFns::equal(akey, v[k])) + return v[k]; + k = (k + open_hash_primes[j]) % n; + } + return 0; +} + +template inline C * +HashSet::put(C avalue) { + if (n < MAP_INTEGRAL_SIZE) { + if (!v) + v = e; + for (int i = 0; i < n; i++) + if (AHashFns::equal(avalue, v[i])) + return &v[i]; + v[n] = avalue; + n++; + return &v[n-1]; + } + if (n > MAP_INTEGRAL_SIZE) { + uintptr_t h = AHashFns::hash(avalue); + h = h % n; + for (int k = h, j = 0; j < i + 3; j++) { + if (!v[k]) { + v[k] = avalue; + return &v[k]; + } + k = (k + open_hash_primes[j]) % n; + } + } else + i = SET_INITIAL_INDEX-1; // will be incremented in set_expand + HashSet vv(*this); + Vec::set_expand(); + for (int i = 0; i < vv.n; i++) + if (vv.v[i]) + put(vv.v[i]); + return put(avalue); +} + +template inline MapElem * +HashMap::get_internal(K akey) { + if (!n) + return 0; + if (n <= MAP_INTEGRAL_SIZE) { + for (MapElem *c = v; c < v + n; c++) + if (c->key) + if (AHashFns::equal(akey, c->key)) + return c; + return 0; + } + uintptr_t h = AHashFns::hash(akey); + h = h % n; + for (int k = h, j = 0; j < i + 3;j++) { + if (!v[k].key) + return 0; + else if (AHashFns::equal(akey, v[k].key)) + return &v[k]; + k = (k + open_hash_primes[j]) % n; + } + return 0; +} + +template inline C +HashMap::get(K akey) { + MapElem *x = get_internal(akey); + if (!x) + return 0; + return x->value; +} + +template inline MapElem * +HashMap::put(K akey, C avalue) { + MapElem *x = get_internal(akey); + if (x) { + x->value = avalue; + return x; + } else { + if (n < MAP_INTEGRAL_SIZE) { + if (!v) + v = e; + v[n].key = akey; + v[n].value = avalue; + n++; + return &v[n-1]; + } + if (n > MAP_INTEGRAL_SIZE) { + uintptr_t h = AHashFns::hash(akey); + h = h % n; + for (int k = h, j = 0; j < i + 3; j++) { + if (!v[k].key) { + v[k].key = akey; + v[k].value = avalue; + return &v[k]; + } + k = (k + open_hash_primes[j]) % n; + } + } else + i = SET_INITIAL_INDEX-1; // will be incremented in set_expand + } + HashMap vv(*this); + Map::set_expand(); + for (int i = 0; i < vv.n; i++) + if (vv.v[i].key) + put(vv.v[i].key, vv.v[i].value); + return put(akey, avalue); +} + +template inline void +HashMap::get_keys(Vec &keys) { Map::get_keys(keys); } + +template inline void +HashMap::get_values(Vec &values) { Map::get_values(values); } + +template C +ChainHash::put(C c) { + uintptr_t h = AHashFns::hash(c); + List *l; + MapElem > e(h, (C)0); + MapElem > *x = this->set_in(e); + if (x) + l = &x->value; + else { + l = &Map, A>::put(h, c)->value; + return l->head->car; + } + forc_List(ChainCons, x, *l) + if (AHashFns::equal(c, x->car)) + return x->car; + l->push(c); + return (C)0; +} + +template C +ChainHash::get(C c) { + uintptr_t h = AHashFns::hash(c); + List empty; + MapElem > e(h, empty); + MapElem > *x = this->set_in(e); + if (!x) + return 0; + List *l = &x->value; + forc_List(ChainCons, x, *l) + if (AHashFns::equal(c, x->car)) + return x->car; + return 0; +} + +template C +ChainHash::put_bag(C c) { + uintptr_t h = AHashFns::hash(c); + List *l; + MapElem > e(h, (C)0); + MapElem > *x = this->set_in(e); + if (x) + l = &x->value; + else { + l = &Map >::put(h, c)->value; + return l->head->car; + } + l->push(c); + return (C)0; +} + +template int +ChainHash::get_bag(C c, Vec &v) { + uintptr_t h = AHashFns::hash(c); + List empty; + MapElem > e(h, empty); + MapElem > *x = this->set_in(e); + if (!x) + return 0; + List *l = &x->value; + forc_List(C, x, *l) + if (AHashFns::equal(c, x->car)) + v.add(x->car); + return v.n; +} + +template void +ChainHash::get_elements(Vec &elements) { + for (int i = 0; i < n; i++) { + List *l = &v[i].value; + forc_List(C, x, *l) + elements.add(x); + } +} + +template int +ChainHash::del(C c) { + uintptr_t h = AHashFns::hash(c); + List *l; + MapElem > e(h, (C)0); + MapElem > *x = this->set_in(e); + if (x) + l = &x->value; + else + return 0; + ConsCell *last = 0; + forc_List(ConsCell, x, *l) { + if (AHashFns::equal(c, x->car)) { + if (!last) + l->head = x->cdr; + else + last->cdr = x->cdr; + A::free(x); + return 1; + } + last = x; + } + return 0; +} + +template MapElem * +ChainHashMap::put(K akey, C avalue) { + uintptr_t h = AHashFns::hash(akey); + List,A> empty; + List,A> *l; + MapElem c(akey, avalue); + MapElem,A> > e(h, empty); + MapElem,A> > *x = this->set_in(e); + if (x) + l = &x->value; + else { + l = &Map,A>,A>::put(h, c)->value; + return &l->head->car; + } + for (ConsCell,A> *p = l->head; p; p = p->cdr) + if (AHashFns::equal(akey, p->car.key)) { + p->car.value = avalue; + return &p->car; + } + l->push(c); + return 0; +} + +template C +ChainHashMap::get(K akey) { + uintptr_t h = AHashFns::hash(akey); + List, A> empty; + MapElem,A> > e(h, empty); + MapElem,A> > *x = this->set_in(e); + if (!x) + return 0; + List,A> *l = &x->value; + if (l->head) + for (ConsCell,A> *p = l->head; p; p = p->cdr) + if (AHashFns::equal(akey, p->car.key)) + return p->car.value; + return 0; +} + +template MapElem * +ChainHashMap::put_bag(K akey, C avalue) { + uintptr_t h = AHashFns::hash(akey); + List,A> empty; + List,A> *l; + MapElem c(akey, avalue); + MapElem,A> > e(h, empty); + MapElem,A> > *x = this->set_in(e); + if (x) + l = &x->value; + else { + l = &Map,A>,A>::put(h, c)->value; + return &l->head->car; + } + for (ConsCell,A> *p = l->head; p; p = p->cdr) + if (AHashFns::equal(akey, p->car.key) && AHashFns::equal_value(avalue, p->car.value)) + return &p->car; + l->push(c); + return 0; +} + +template int +ChainHashMap::get_bag(K akey, Vec &v) { + uintptr_t h = AHashFns::hash(akey); + List,A> empty; + MapElem,A> > e(h, empty); + MapElem,A> > *x = this->set_in(e); + if (!x) + return 0; + List,A> *l = &x->value; + for (ConsCell,A> *p = l->head; p; p = p->cdr) + if (AHashFns::equal(akey, p->car.key)) + return v.add(x->car); + return v.n; +} + +template int +ChainHashMap::del(K akey) { + uintptr_t h = AHashFns::hash(akey); + List,A> empty; + List,A> *l; + MapElem,A> > e(h, empty); + MapElem,A> > *x = this->set_in(e); + if (x) + l = &x->value; + else + return 0; + ConsCell,A> *last = 0; + for (ConsCell,A> *p = l->head; p; p = p->cdr) { + if (AHashFns::equal(akey, p->car.key)) { + if (!last) + l->head = p->cdr; + else + last->cdr = p->cdr; + return 1; + } + last = p; + } + return 0; +} + +template void +ChainHashMap::get_keys(Vec &keys) { + for (int i = 0; i < n; i++) { + List > *l = &v[i].value; + if (l->head) + for (ConsCell,A> *p = l->head; p; p = p->cdr) + keys.add(p->car.key); + } +} + +template void +ChainHashMap::get_values(Vec &values) { + for (int i = 0; i < n; i++) { + List,A> *l = &v[i].value; + if (l->head) + for (ConsCell,A> *p = l->head; p; p = p->cdr) + values.add(p->car.value); + } +} + +template inline cchar * +StringChainHash::canonicalize(cchar *s, cchar *e) { + uintptr_t h = 0; + cchar *a = s; + // 31 changed to 27, to avoid prime2 in vec.cpp + if (e) + while (a != e) h = h * 27 + (unsigned char)*a++; + else + while (*a) h = h * 27 + (unsigned char)*a++; + MapElem > me(h, (char*)0); + MapElem > *x = this->set_in(me); + if (x) { + List *l = &x->value; + typedef ConsCell TT; + forc_List(TT, x, *l) { + a = s; + cchar *b = x->car; + while (1) { + if (!*b) { + if (a == e) + return x->car; + break; + } + if (a >= e || *a != *b) + break; + a++; b++; + } + } + } + s = _dupstr(s, e); + cchar *ss = ChainHash::put(s); + if (ss) + return ss; + return s; +} + +template inline C +Env::get(K akey) { + MapElem *> e(akey, 0); + MapElem *> *x = store.set_in(e); + if (x) + return x->value->first(); + return (C)0; +} + +template inline List * +Env::get_bucket(K akey) { + List *bucket = store.get(akey); + if (bucket) + return bucket; + bucket = new List(); + store.put(akey, bucket); + return bucket; +} + +template inline void +Env::put(K akey, C avalue) { + scope.head->car.push(akey); + get_bucket(akey)->push(avalue); +} + +template inline void +Env::push() { + scope.push(); +} + +template inline void +Env::pop() { + forc_List(EnvCons, e, scope.first()) + get_bucket(e->car)->pop(); +} + +template inline +NBlockHash::NBlockHash() : n(1), i(0) { + memset(&e[0], 0, sizeof(e)); + v = e; +} + +template inline C* +NBlockHash::first() { + return &v[0]; +} + +template inline C* +NBlockHash::last() { + return &v[n * N]; +} + +template inline C +NBlockHash::put(C c) { + int a; + uintptr_t h = AHashFns::hash(c); + C *x = &v[(h % n) * N]; + for (a = 0; a < N; a++) { + if (!x[a]) + break; + if (AHashFns::equal(c, x[a])) + return x[a]; + } + if (a < N) { + x[a] = c; + return (C)0; + } + C *vv = first(), *ve = last(); + C *old_v = v; + i = i + 1; + size(i); + for (;vv < ve; vv++) + if (*vv) + put(*vv); + if (old_v != &e[0]) + A::free(old_v); + return put(c); +} + +template inline void +NBlockHash::size(int p2) { + n = prime2[p2]; + v = (C*)A::alloc(n * sizeof(C) * N); + memset(v, 0, n * sizeof(C) * N); +} + +template inline C +NBlockHash::get(C c) { + if (!n) + return (C)0; + uintptr_t h = AHashFns::hash(c); + C *x = &v[(h % n) * N]; + for (int a = 0; a < N; a++) { + if (!x[a]) + return (C)0; + if (AHashFns::equal(c, x[a])) + return x[a]; + } + return (C)0; +} + +template inline C* +NBlockHash::assoc_get(C *c) { + if (!n) + return (C*)0; + uintptr_t h = AHashFns::hash(*c); + C *x = &v[(h % n) * N]; + int a = 0; + if (c >= x && c < x + N) + a = c - x + 1; + for (; a < N; a++) { + if (!x[a]) + return (C*)0; + if (AHashFns::equal(*c, x[a])) + return &x[a]; + } + return (C*)0; +} + +template inline C* +NBlockHash::assoc_put(C *c) { + int a; + uintptr_t h = AHashFns::hash(*c); + C *x = &v[(h % n) * N]; + for (a = 0; a < N; a++) { + if (!x[a]) + break; + } + if (a < N) { + x[a] = *c; + return &x[a]; + } + x[i % N] = *c; + i++; + return &x[i % N]; +} + +template inline int +NBlockHash::del(C c) { + int a, b; + if (!n) + return 0; + uintptr_t h = AHashFns::hash(c); + C *x = &v[(h % n) * N]; + for (a = 0; a < N; a++) { + if (!x[a]) + return 0; + if (AHashFns::equal(c, x[a])) { + if (a < N - 1) { + for (b = a + 1; b < N; b++) { + if (!x[b]) + break; + } + if (b != a + 1) + x[a] = x[b - 1]; + x[b - 1] = (C)0; + return 1; + } else { + x[N - 1] = (C)0; + return 1; + } + } + } + return 0; +} + +template inline void +NBlockHash::clear() { + if (v && v != e) A::free(v); + v = e; + n = 1; +} + +template inline void +NBlockHash::reset() { + if (v) + memset(v, 0, n * N * sizeof(C)); +} + +template inline int +NBlockHash::count() { + int nelements = 0; + C *l = last(); + for (C *xx = first(); xx < l; xx++) + if (*xx) + nelements++; + return nelements; +} + +template inline void +NBlockHash::copy(const NBlockHash &hh) { + clear(); + n = hh.n; + i = hh.i; + if (hh.v == &hh.e[0]) { + memcpy(e, &hh.e[0], sizeof(e)); + v = e; + } else { + if (hh.v) { + v = (C*)A::alloc(n * sizeof(C) * N); + memcpy(v, hh.v, n * sizeof(C) * N); + } else + v = 0; + } +} + +template inline void +NBlockHash::move(NBlockHash &hh) { + clear(); + n = hh.n; + i = hh.i; + v = hh.v; + if (hh.v == &hh.e[0]) { + memcpy(e, &hh.e[0], sizeof(e)); + v = e; + } + hh.clear(); +} + +void test_map(); + +#endif diff --git a/lib/ts/MatcherUtils.cc b/lib/ts/MatcherUtils.cc new file mode 100644 index 00000000..aa9db031 --- /dev/null +++ b/lib/ts/MatcherUtils.cc @@ -0,0 +1,587 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * MatcherUtils.cc - Various helper routines used in ControlMatcher + * and ReverseProxy + * + * + ****************************************************************************/ + +#include "libts.h" /* MAGIC_EDITING_TAG */ + +// char* readIntoBuffer(const char* file_path, const char* module_name, +// int* read_size_ptr) +// +// Attempts to open and read arg file_path into a buffer allocated +// off the heap (via malloc() ) Returns a pointer to the buffer +// is successful and NULL otherwise. +// +// CALLEE is responsibled for deallocating the buffer via free() +// +char * +readIntoBuffer(char *file_path, const char *module_name, int *read_size_ptr) +{ + + int fd; + struct stat file_info; + char *file_buf; + int read_size = 0; + + if (read_size_ptr != NULL) { + *read_size_ptr = 0; + } + // Open the file for Blocking IO. We will be reading this + // at start up and infrequently afterward + if ((fd = open(file_path, O_RDONLY | _O_ATTRIB_NORMAL)) < 0) { + Error("%s Can not open %s file : %s", module_name, file_path, strerror(errno)); + return NULL; + } + + if (fstat(fd, &file_info) < 0) { + Error("%s Can not stat %s file : %s", module_name, file_path, strerror(errno)); + close(fd); + return NULL; + } + + if (file_info.st_size < 0) { + Error("%s Can not get correct file size for %s file : %" PRId64 "", module_name, file_path, (int64_t) file_info.st_size); + close(fd); + return NULL; + } + // Allocate a buffer large enough to hold the entire file + // File size should be small and this makes it easy to + // do two passes on the file + if ((file_buf = (char *) xmalloc((file_info.st_size + 1))) != NULL) { + // Null terminate the buffer so that string operations will work + file_buf[file_info.st_size] = '\0'; + + read_size = (file_info.st_size > 0) ? read(fd, file_buf, file_info.st_size) : 0; + + // Check to make sure that we got the whole file + if (read_size < 0) { + Error("%s Read of %s file failed : %s", module_name, file_path, strerror(errno)); + xfree(file_buf); + file_buf = NULL; + } else if (read_size < file_info.st_size) { + // We don't want to signal this error on WIN32 because the sizes + // won't match if the file contains any CR/LF sequence. + Error("%s Only able to read %d bytes out %d for %s file", + module_name, read_size, (int) file_info.st_size, file_path); + file_buf[read_size] = '\0'; + } + } else { + Error("%s Insufficient memory to read %s file", module_name, file_path); + } + + if (file_buf && read_size_ptr) { + *read_size_ptr = read_size; + } + + close(fd); + + return file_buf; +} + +// int unescapifyStr(char* buffer) +// +// Unescapifies a URL without a making a copy. +// The passed in string is modified +// +int +unescapifyStr(char *buffer) +{ + char *read = buffer; + char *write = buffer; + char subStr[3]; + + subStr[2] = '\0'; + while (*read != '\0') { + if (*read == '%' && *(read + 1) != '\0' && *(read + 2) != '\0') { + subStr[0] = *(++read); + subStr[1] = *(++read); + *write = (char)strtol(subStr, (char **) NULL, 16); + read++; + write++; + } else if (*read == '+') { + *write = ' '; + write++; + read++; + } else { + *write = *read; + write++; + read++; + } + } + *write = '\0'; + + return (write - buffer); +} + +// char* ExtractIpRange(char* match_str, ip_addr_t* addr1, +// ip_addr_t* addr2) +// +// Attempts to extract either an Ip Address or an IP Range +// from match_str. The range should be two addresses +// separated by a hyphen and no spaces +// +// If the extraction is successful, sets addr1 and addr2 +// to the extracted values (in the case of a single +// address addr2 = addr1) and returns NULL +// +// If the extraction fails, returns a static string +// that describes the reason for the error. +// +const char * +ExtractIpRange(char *match_str, ip_addr_t *addr1, ip_addr_t *addr2) +{ + Tokenizer rangeTok("-/"); + bool mask = false; + int mask_bits; + int mask_val; + int numToks; + ip_addr_t addr1_local; + ip_addr_t addr2_local; + + if (strchr(match_str, '/') != NULL) { + mask = true; + } + // Extract the IP addresses from match data + numToks = rangeTok.Initialize(match_str, SHARE_TOKS); + + if (numToks < 0) { + return "no IP address given"; + } else if (numToks > 2) { + return "malformed IP range"; + } + + addr1_local = htonl(inet_addr(rangeTok[0])); + + if (addr1_local == (ip_addr_t) - 1 && strcmp(rangeTok[0], "255.255.255.255") != 0) { + return "malformed ip address"; + } + // Handle a IP range + if (numToks == 2) { + + if (mask == true) { + // coverity[secure_coding] + if (sscanf(rangeTok[1], "%d", &mask_bits) != 1) { + return "bad mask specification"; + } + + if (!(mask_bits >= 0 && mask_bits <= 32)) { + return "invalid mask specification"; + } + + if (mask_bits == 32) { + mask_val = 0; + } else { + mask_val = 0xffffffff >> mask_bits; + } + + addr2_local = addr1_local | mask_val; + addr1_local = addr1_local & (mask_val ^ 0xffffffff); + + } else { + addr2_local = htonl(inet_addr(rangeTok[1])); + if (addr2_local == (ip_addr_t) - 1 && strcmp(rangeTok[1], "255.255.255.255") != 0) { + return "malformed ip address at range end"; + } + } + + if (addr1_local > addr2_local) { + return "range start greater than range end"; + } + } else { + addr2_local = addr1_local; + } + + *addr1 = addr1_local; + *addr2 = addr2_local; + return NULL; +} + +// char* tokLine(char* buf, char** last) +// +// Similar to strtok_r but only tokenizes on '\n' +// and will return tokens that are empty strings +// +char * +tokLine(char *buf, char **last) +{ + char *start; + char *cur; + + if (buf != NULL) { + start = cur = buf; + *last = buf; + } else { + start = cur = (*last) + 1; + } + + while (*cur != '\0') { + if (*cur == '\n') { + *cur = '\0'; + *last = cur; + return start; + } + cur++; + } + + // Return the last line even if it does + // not end in a newline + if (cur > (*last + 1)) { + *last = cur - 1; + return start; + } + + return NULL; +} + +const char *matcher_type_str[] = { + "invalid", + "host", + "domain", + "ip", + "url_regex", + "host_regex" +}; + +// char* processDurationString(char* str, int* seconds) +// +// Take a duration sting which is composed of +// digits followed by a unit specifier +// w - week +// d - day +// h - hour +// m - min +// s - sec +// +// Trailing digits without a specifier are +// assumed to be seconds +// +// Returns NULL on success and a static +// error string on failure +// +const char * +processDurationString(char *str, int *seconds) +{ + char *s = str; + char *current = str; + char unit; + int tmp; + int multiplier; + int result = 0; + int len; + + if (str == NULL) { + return "Missing time"; + } + + len = strlen(str); + for (int i = 0; i < len; i++) { + if (!ParseRules::is_digit(*current)) { + + // Make sure there is a time to proces + if (current == s) { + return "Malformed time"; + } + + unit = *current; + + switch (unit) { + case 'w': + multiplier = 7 * 24 * 60 * 60; + break; + case 'd': + multiplier = 24 * 60 * 60; + break; + case 'h': + multiplier = 60 * 60; + break; + case 'm': + multiplier = 60; + break; + case 's': + multiplier = 1; + break; + case '-': + return "Negative time not permitted"; + default: + return "Invalid time unit specified"; + } + + *current = '\0'; + + // coverity[secure_coding] + if (sscanf(s, "%d", &tmp) != 1) { + // Really should not happen since everything + // in the string is digit + ink_assert(0); + return "Malformed time"; + } + + result += (multiplier * tmp); + s = current + 1; + + } + current++; + } + + // Read any trailing seconds + if (current != s) { + // coverity[secure_coding] + if (sscanf(s, "%d", &tmp) != 1) { + // Really should not happen since everything + // in the string is digit + ink_assert(0); + return "Malformed time"; + } else { + result += tmp; + } + } + // We rolled over the int + if (result < 0) { + return "Time too big"; + } + + *seconds = result; + return NULL; +} + +const matcher_tags http_dest_tags = { + "dest_host", "dest_domain", "dest_ip", "url_regex", "host_regex", true +}; + +const matcher_tags ip_allow_tags = { + NULL, NULL, "src_ip", NULL, NULL, false +}; + +const matcher_tags socks_server_tags = { + NULL, NULL, "dest_ip", NULL, NULL, false +}; + +// char* parseConfigLine(char* line, matcher_line* p_line, +// const matcher_tags* tags) +// +// Parse out a config file line suitable for passing to +// a ControlMatcher object +// +// If successful, NULL is returned. If unsuccessful, +// a static error string is returned +// +const char * +parseConfigLine(char *line, matcher_line *p_line, const matcher_tags * tags) +{ + enum pState + { + FIND_LABEL, PARSE_LABEL, + PARSE_VAL, START_PARSE_VAL, CONSUME + }; + + pState state = FIND_LABEL; + bool inQuote = false; + char *copyForward = NULL; + char *copyFrom = NULL; + char *s = line; + char *label = NULL; + char *val = NULL; + int num_el = 0; + matcher_type type = MATCH_NONE; + + // Zero out the parsed line structure + memset(p_line, 0, sizeof(matcher_line)); + + if (*s == '\0') { + return NULL; + } + + do { + + switch (state) { + case FIND_LABEL: + if (!isspace(*s)) { + state = PARSE_LABEL; + label = s; + } + s++; + break; + case PARSE_LABEL: + if (*s == '=') { + *s = '\0'; + state = START_PARSE_VAL; + } + s++; + break; + case START_PARSE_VAL: + // Init state needed for parsing values + copyForward = NULL; + copyFrom = NULL; + + if (*s == '"') { + inQuote = true; + val = s + 1; + } else if (*s == '\\') { + inQuote = false; + val = s + 1; + } else { + inQuote = false; + val = s; + + } + + if (inQuote == false && (isspace(*s) || *(s + 1) == '\0')) { + state = CONSUME; + } else { + state = PARSE_VAL; + } + + s++; + break; + case PARSE_VAL: + if (inQuote == true) { + if (*s == '\\') { + // The next character is esacped + // + // To remove the escaped character + // we need to copy + // the rest of the entry over it + // but since we do not know where the + // end is right now, defer the work + // into the future + + if (copyForward != NULL) { + // Perform the prior copy forward + int bytesCopy = s - copyFrom; + memcpy(copyForward, copyFrom, s - copyFrom); + ink_assert(bytesCopy > 0); + + copyForward += bytesCopy; + copyFrom = s + 1; + } else { + copyForward = s; + copyFrom = s + 1; + } + + // Scroll past the escape character + s++; + + // Handle the case that places us + // at the end of the file + if (*s == '\0') { + break; + } + } else if (*s == '"') { + state = CONSUME; + *s = '\0'; + } + } else if ((*s == '\\' && ParseRules::is_digit(*(s + 1))) + || !ParseRules::is_char(*s)) { + // INKqa10511 + // traffic server need to handle unicode characters + // right now ignore the entry + return "Unrecognized encoding scheme"; + } else if (isspace(*s)) { + state = CONSUME; + *s = '\0'; + } + + s++; + + // If we are now at the end of the line, + // we need to consume final data + if (*s == '\0') { + state = CONSUME; + } + break; + case CONSUME: + break; + } + + if (state == CONSUME) { + + // See if there are any quote copy overs + // we've pushed into the future + if (copyForward != NULL) { + int toCopy = (s - 1) - copyFrom; + memcpy(copyForward, copyFrom, toCopy); + *(copyForward + toCopy) = '\0'; + } + + p_line->line[0][num_el] = label; + p_line->line[1][num_el] = val; + type = MATCH_NONE; + + // Check to see if this the primary specifier we are looking for + if (tags->match_ip && strcasecmp(tags->match_ip, label) == 0) { + type = MATCH_IP; + } else if (tags->match_host && strcasecmp(tags->match_host, label) == 0) { + type = MATCH_HOST; + } else if (tags->match_domain && strcasecmp(tags->match_domain, label) == 0) { + type = MATCH_DOMAIN; + } else if (tags->match_regex && strcasecmp(tags->match_regex, label) == 0) { + type = MATCH_REGEX; + } else if (tags->match_host_regex && strcasecmp(tags->match_host_regex, label) == 0) { + type = MATCH_HOST_REGEX; + } + // If this a destination tag, use it + if (type != MATCH_NONE) { + // Check to see if this second destination specifier + if (p_line->type != MATCH_NONE) { + if (tags->dest_error_msg == false) { + return "Muliple Sources Specified"; + } else { + return "Muliple Destinations Specified"; + } + } else { + p_line->dest_entry = num_el; + p_line->type = type; + } + } + num_el++; + + if (num_el > MATCHER_MAX_TOKENS) { + return "Malformed line: Too many tokens"; + } + + state = FIND_LABEL; + } + } while (*s != '\0'); + + p_line->num_el = num_el; + + if (state != CONSUME && state != FIND_LABEL) { + return "Malformed entry"; + } + + if (p_line->type == MATCH_NONE) { + if (tags->dest_error_msg == false) { + return "No source specifier"; + } else { + return "No destination specifier"; + } + } + + return NULL; +} diff --git a/lib/ts/MatcherUtils.h b/lib/ts/MatcherUtils.h new file mode 100644 index 00000000..d341e4c0 --- /dev/null +++ b/lib/ts/MatcherUtils.h @@ -0,0 +1,99 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * MatcherUtils.h - Various helper routines used in ControlMatcher + * and ReverseProxy + * + * + ****************************************************************************/ + +#ifndef _MATCHER_UTILS_H_ +#define _MATCHER_UTILS_H_ + +#include "ParseRules.h" +// Look in MatcherUtils.cc for comments on function usage +char *readIntoBuffer(char *file_path, const char *module_name, int *read_size_ptr); + +int unescapifyStr(char *buffer); + +typedef unsigned long ip_addr_t; +const char *ExtractIpRange(char *match_str, ip_addr_t * addr1, ip_addr_t * addr2); +char *tokLine(char *buf, char **last); + +const char *processDurationString(char *str, int *seconds); + +// The first class types we support matching on +enum matcher_type +{ MATCH_NONE, MATCH_HOST, MATCH_DOMAIN, + MATCH_IP, MATCH_REGEX, MATCH_HOST_REGEX +}; +extern const char *matcher_type_str[]; + +// A parsed config file line +const int MATCHER_MAX_TOKENS = 40; +struct matcher_line +{ + matcher_type type; // dest type + int dest_entry; // entry which specifies the destination + int num_el; // Number of elements + char *line[2][MATCHER_MAX_TOKENS]; // label, value pairs + int line_num; // config file line number + matcher_line *next; // use for linked list +}; + +// Tag set to use to determining primary selector type +struct matcher_tags +{ + const char *match_host; + const char *match_domain; + const char *match_ip; + const char *match_regex; + const char *match_host_regex; + bool dest_error_msg; // wether to use src or destination in any + // errog messages +}; +extern const matcher_tags http_dest_tags; +extern const matcher_tags ip_allow_tags; +extern const matcher_tags socks_server_tags; + +const char *parseConfigLine(char *line, matcher_line * p_line, const matcher_tags * tags); + +// inline void LowerCaseStr(char* str) +// +// Modifies str so all characters are lower +// case +// +static inline void +LowerCaseStr(char *str) +{ + if (!str) + return; + while (*str != '\0') { + *str = ParseRules::ink_tolower(*str); + str++; + } +} + +#endif diff --git a/lib/ts/MimeTable.cc b/lib/ts/MimeTable.cc new file mode 100644 index 00000000..213da4f8 --- /dev/null +++ b/lib/ts/MimeTable.cc @@ -0,0 +1,211 @@ +/** @file + + MimeTableEntry and MimeTable definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" /* MAGIC_EDITING_TAG */ + +MimeTableEntry + MimeTable::m_table[] = { + {"ai", "application/postscript", "8bit", "text"}, + {"aif", "audio/x-aiff", "binary", "sound"}, + {"aifc", "audio/x-aiff", "binary", "sound"}, + {"aiff", "audio/x-aiff", "binary", "sound"}, + {"arj", "application/x-arj-compressed", "binary", "binary"}, + {"au", "audio/basic", "binary", "sound"}, + {"avi", "video/x-msvideo", "binary", "movie"}, + {"bcpio", "application/x-bcpio", "binary", "binary"}, + {"bin", "application/macbinary", "macbinary", "binary"}, + {"c", "text/plain", "7bit", "text"}, + {"cc", "text/plain", "7bit", "text"}, + {"cdf", "application/x-netcdf", "binary", "binary"}, + {"cpio", "application/x-cpio", "binary", "binary"}, + {"csh", "application/x-csh", "7bit", "text"}, + {"doc", "application/msword", "binary", "binary"}, + {"dvi", "application/x-dvi", "binary", "binary"}, + {"eps", "application/postscript", "8bit", "text"}, + {"etx", "text/x-setext", "7bit", "text"}, + {"exe", "application/octet-stream", "binary", "binary"}, + {"f90", "text/plain", "7bit", "text"}, + {"gif", "image/gif", "binary", "image"}, + {"gtar", "application/x-gtar", "binary", "binary"}, + {"gz", "application/x-gzip", "x-gzip", "binary"}, + {"h", "text/plain", "7bit", "text"}, + {"hdf", "application/x-hdf", "binary", "binary"}, + {"hh", "text/plain", "7bit", "text"}, + {"hqx", "application/mac-binhex40", "mac-binhex40", "binary"}, + {"htm", "text/html", "8bit", "text"}, + {"html", "text/html", "8bit", "text"}, + {"ief", "image/ief", "binary", "image"}, + {"jpe", "image/jpeg", "binary", "image"}, + {"jpeg", "image/jpeg", "binary", "image"}, + {"jpg", "image/jpeg", "binary", "image"}, + {"latex", "application/x-latex", "8bit", "text"}, + {"lha", "application/x-lha-compressed", "binary", "binary"}, + {"lsm", "text/plain", "7bit", "text"}, + {"lzh", "application/x-lha-compressed", "binary", "binary"}, + {"m", "text/plain", "7bit", "text"}, + {"man", "application/x-troff-man", "7bit", "text"}, + {"me", "application/x-troff-me", "7bit", "text"}, + {"mif", "application/x-mif", "binary", "binary"}, + {"mime", "www/mime", "8bit", "text"}, + {"mov", "video/quicktime", "binary", "movie"}, + {"movie", "video/x-sgi-movie", "binary", "movie"}, + {"mp2", "audio/mpeg", "binary", "sound"}, + {"mp3", "audio/mpeg", "binary", "sound"}, + {"mpe", "video/mpeg", "binary", "movie"}, + {"mpeg", "video/mpeg", "binary", "movie"}, + {"mpg", "video/mpeg", "binary", "movie"}, + {"ms", "application/x-troff-ms", "7bit", "text"}, + {"msw", "application/msword", "binary", "binary"}, + {"mwrt", "application/macwriteii", "binary", "binary"}, + {"nc", "application/x-netcdf", "binary", "binary"}, + {"oda", "application/oda", "binary", "binary"}, + {"pbm", "image/x-portable-bitmap", "binary", "image"}, + {"pdf", "application/pdf", "binary", "binary"}, + {"pgm", "image/x-portable-graymap", "binary", "image"}, + {"pic", "application/pict", "binary", "image"}, + {"pict", "application/pict", "binary", "image"}, + {"pnm", "image/x-portable-anymap", "binary", "image"}, + {"ppm", "image/x-portable-pixmap", "binary", "image"}, + {"ps", "application/postscript", "8bit", "text"}, + {"qt", "video/quicktime", "binary", "movie"}, + {"ras", "image/cmu-raster", "binary", "image"}, + {"rgb", "image/x-rgb", "binary", "image"}, + {"roff", "application/x-troff", "7bit", "text"}, + {"rpm", "application/x-rpm", "binary", "binary"}, + {"rtf", "application/x-rtf", "7bit", "binary"}, + {"rtx", "text/richtext", "7bit", "text"}, + {"sh", "application/x-sh", "7bit", "text"}, + {"shar", "application/x-shar", "8bit", "text"}, + {"sit", "application/stuffit", "binary", "binary"}, + {"snd", "audio/basic", "binary", "sound"}, + {"src", "application/x-wais-source", "7bit", "text"}, + {"sv4cpio", "application/x-sv4cpio", "binary", "binary"}, + {"sv4crc", "application/x-sv4crc", "binary", "binary"}, + {"t", "application/x-troff", "7bit", "text"}, + {"tar", "application/x-tar", "binary", "binary"}, + {"tcl", "application/x-tcl", "7bit", "text"}, + {"tex", "application/x-tex", "8bit", "text"}, + {"texi", "application/x-texinfo", "7bit", "text"}, + {"texinfo", "application/x-texinfo", "7bit", "text"}, + {"tgz", "application/x-tar", "x-gzip", "binary"}, + {"tif", "image/tiff", "binary", "image"}, + {"tiff", "image/tiff", "binary", "image"}, + {"tr", "application/x-troff", "7bit", "text"}, + {"tsv", "text/tab-separated-values", "7bit", "text"}, + {"txt", "text/plain", "7bit", "text"}, + {"ustar", "application/x-ustar", "binary", "binary"}, + {"wav", "audio/x-wav", "binary", "sound"}, + {"xbm", "image/x-xbitmap", "binary", "image"}, + {"xpm", "image/x-xpixmap", "binary", "image"}, + {"xwd", "image/x-xwindowdump", "binary", "image"}, + {"Z", "application/x-compressed", "x-compress", "binary"}, + {"zip", "application/x-zip-compressed", "zip", "binary"} +}; +int + MimeTable::m_table_size = (sizeof(MimeTable::m_table)) / (sizeof(MimeTable::m_table[0])); +MimeTableEntry +MimeTable::m_unknown = { "unknown", "application/x-unknown-content-type", "binary", "unknown" }; +MimeTable + mimeTable; +//////////////////////////////////////////////////////////////// +// +// class MimeTable +// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +// +// MimeTable::get_entry_path() +// +//////////////////////////////////////////////////////////////// +MimeTableEntry * +MimeTable::get_entry_path(const char *path) +{ + const char *p = strrchr(path, '.'); + MimeTableEntry *e = 0; + + if (p) + e = get_entry(p + 1); + else { + ///////////////////////////////////////// + // file has no extension. make a best // + // guess, or return null for unknown // + ///////////////////////////////////////// + if (ParseRules::strcasestr(path, "index") || + ParseRules::strcasestr(path, "README") || + ParseRules::strcasestr(path, "ls-lR") || + ParseRules::strcasestr(path, "config") || (path[0] == '\0') || (path[strlen(path) - 1] == '/')) + e = get_entry("txt"); + } + if (e == 0) + e = &m_unknown; + + return (e); +} + +//////////////////////////////////////////////////////////////// +// +// MimeTable::get_entry() +// +//////////////////////////////////////////////////////////////// +MimeTableEntry * +MimeTable::get_entry(const char *name) +{ + MimeTableEntry key; + + key.name = name; + + // do a binary search. extensions are unique + int low = 0; + int high = m_table_size - 1; + int mid = ((high - low) / 2) + low; + int found = -1; + + if (!name[0]) + return (0); + + + while (1) { + if (m_table[mid] == key) { + found = mid; + break; + } else if (m_table[mid] < key) { + if (mid == high) { + found = -1; + break; + } else { + low = mid + 1; + mid = ((high - low) / 2) + low; + } + } else { + if (mid == low) { + found = -1; + break; + } else { + high = mid - 1; + mid = ((high - low) / 2) + low; + } + } + } + + return ((found >= 0) ? (&m_table[found]) : 0); +} diff --git a/lib/ts/MimeTable.h b/lib/ts/MimeTable.h new file mode 100644 index 00000000..e7c3c614 --- /dev/null +++ b/lib/ts/MimeTable.h @@ -0,0 +1,75 @@ +/** @file + + MimeTableEntry and MimeTable declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#if !defined (_MimeTable_h_) +#define _MimeTable_h_ + +#include +#include "ink_port.h" +#include "ink_string.h" + +struct MimeTableEntry +{ + const char *name; + const char *mime_type; + const char *mime_encoding; + const char *icon; + + friend int operator ==(const MimeTableEntry & a, const MimeTableEntry & b) + { + return (strcasecmp(a.name, b.name) == 0); + } + friend int operator <(const MimeTableEntry & a, const MimeTableEntry & b) + { + return (strcasecmp(a.name, b.name) < 0); + } + friend int operator >(const MimeTableEntry & a, const MimeTableEntry & b) + { + return (strcasecmp(a.name, b.name) < 0); + } +}; + +class MimeTable +{ +public: + MimeTable() + { + } + ~MimeTable() + { + } + + MimeTableEntry *get_entry_path(const char *path); + MimeTableEntry *get_entry(const char *name); + +private: + static MimeTableEntry m_table[]; + static int m_table_size; + static MimeTableEntry m_unknown; + +private: + MimeTable(const MimeTable &); + MimeTable & operator =(const MimeTable &); +}; +extern MimeTable mimeTable; +#endif diff --git a/lib/ts/ParseRules.cc b/lib/ts/ParseRules.cc new file mode 100644 index 00000000..ba6ab7b9 --- /dev/null +++ b/lib/ts/ParseRules.cc @@ -0,0 +1,178 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************** -*- Mod: C++ -*- ****************************** + + ParseRules.h -- + + + ****************************************************************************/ + +#include "libts.h" /* MAGIC_EDITING_TAG */ + +const unsigned int parseRulesCType[256] = { +#include "ParseRulesCType" +}; +const char parseRulesCTypeToUpper[256] = { +#include "ParseRulesCTypeToUpper" +}; +const char parseRulesCTypeToLower[256] = { +#include "ParseRulesCTypeToLower" +}; + +unsigned char * +ParseRules::scan_while(unsigned char *ptr, unsigned int n, uint32_t bitmask) +{ + unsigned int i; + uint32_t *wptr; + unsigned char *align_ptr; + uintptr_t f_bytes, b_bytes, words, align_off; + + align_off = ((uintptr_t) ptr & 3); + align_ptr = (unsigned char *) (((uintptr_t) ptr) & ~3); + + f_bytes = (align_off ? 4 - align_off : 0); + + words = (n - f_bytes) >> 2; + + if (words == 0) { + for (i = 0; i < n; i++) + if (!is_type(ptr[i], bitmask)) + return (&ptr[i]); + } else { + wptr = ((uint32_t *) align_ptr) + (align_off ? 1 : 0); + switch (align_off) { + case 1: + if (!is_type(align_ptr[1], bitmask)) + return (&ptr[1]); + case 2: + if (!is_type(align_ptr[2], bitmask)) + return (&ptr[2]); + case 3: + if (!is_type(align_ptr[3], bitmask)) + return (&ptr[3]); + break; + default: + break; + } + + b_bytes = n - ((words << 2) + f_bytes); + + for (i = 0; i < words; i++) { + uint32_t word = wptr[i]; + uint32_t result = (is_type(((word >> 0) & 0xFF), bitmask) & + is_type(((word >> 8) & 0xFF), bitmask) & + is_type(((word >> 16) & 0xFF), bitmask) & is_type(((word >> 24) & 0xFF), bitmask)); + if (result == 0) { + unsigned char *cptr = (unsigned char *) &(wptr[i]); + if (!is_type(cptr[0], bitmask)) + return (&cptr[0]); + if (!is_type(cptr[1], bitmask)) + return (&cptr[1]); + if (!is_type(cptr[2], bitmask)) + return (&cptr[2]); + return (&cptr[3]); + } + } + + align_ptr = (unsigned char *) &(wptr[words]); + + switch (b_bytes) { + case 1: + if (!is_type(align_ptr[0], bitmask)) + return (&align_ptr[0]); + break; + case 2: + if (!is_type(align_ptr[0], bitmask)) + return (&align_ptr[0]); + if (!is_type(align_ptr[1], bitmask)) + return (&align_ptr[1]); + break; + case 3: + if (!is_type(align_ptr[0], bitmask)) + return (&align_ptr[0]); + if (!is_type(align_ptr[1], bitmask)) + return (&align_ptr[1]); + if (!is_type(align_ptr[2], bitmask)) + return (&align_ptr[2]); + break; + default: + break; + } + } + return 0; +} + + +void +ParseRules::ink_tolower_buffer(char *ptr, unsigned int n) +{ + unsigned int i; + + if (n < 8) { + for (i = 0; i < n; i++) + ptr[i] = ParseRules::ink_tolower(ptr[i]); + } else { + uintptr_t fpad = 4 - ((uintptr_t) ptr & 3); + uintptr_t words = (n - fpad) >> 2; + uintptr_t bpad = n - fpad - (words << 2); + + switch (fpad) { + case 3: + *ptr = ParseRules::ink_tolower(*ptr); + ++ptr; + case 2: + *ptr = ParseRules::ink_tolower(*ptr); + ++ptr; + case 1: + *ptr = ParseRules::ink_tolower(*ptr); + ++ptr; + default: + break; + } + + uint32_t *wptr = (uint32_t *) ptr; + for (i = 0; i < words; i++) { + uint32_t word = *wptr; + ((unsigned char *) &word)[0] = ParseRules::ink_tolower(((unsigned char *) &word)[0]); + ((unsigned char *) &word)[1] = ParseRules::ink_tolower(((unsigned char *) &word)[1]); + ((unsigned char *) &word)[2] = ParseRules::ink_tolower(((unsigned char *) &word)[2]); + ((unsigned char *) &word)[3] = ParseRules::ink_tolower(((unsigned char *) &word)[3]); + *wptr++ = word; + } + + switch (bpad) { + case 3: + *ptr = ParseRules::ink_tolower(*ptr); + ++ptr; + case 2: + *ptr = ParseRules::ink_tolower(*ptr); + ++ptr; + case 1: + *ptr = ParseRules::ink_tolower(*ptr); + ++ptr; + default: + break; + } + } +} diff --git a/lib/ts/ParseRules.h b/lib/ts/ParseRules.h new file mode 100644 index 00000000..136017e9 --- /dev/null +++ b/lib/ts/ParseRules.h @@ -0,0 +1,1021 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#if !defined (_ParseRules_h_) +#define _ParseRules_h_ + +#include "ink_bool.h" +#include "ink_port.h" +#include "ink_unused.h" + +#include "Resource.h" +#include + +#include "ink_apidefs.h" + +typedef unsigned int CTypeResult; + +// Set this to 0 to disable SI +// decimal multipliers +#define USE_SI_MULTILIERS 1 + +#define is_char_BIT (1 << 0) +#define is_upalpha_BIT (1 << 1) +#define is_loalpha_BIT (1 << 2) +#define is_alpha_BIT (1 << 3) +#define is_digit_BIT (1 << 4) +#define is_ctl_BIT (1 << 5) +#define is_ws_BIT (1 << 6) +#define is_hex_BIT (1 << 7) +#define is_pchar_BIT (1 << 8) +#define is_extra_BIT (1 << 9) +#define is_safe_BIT (1 << 10) +#define is_unsafe_BIT (1 << 11) +#define is_national_BIT (1 << 12) +#define is_reserved_BIT (1 << 13) +#define is_unreserved_BIT (1 << 14) +#define is_punct_BIT (1 << 15) +#define is_end_of_url_BIT (1 << 16) +#define is_tspecials_BIT (1 << 17) +#define is_spcr_BIT (1 << 18) +#define is_splf_BIT (1 << 19) +#define is_wslfcr_BIT (1 << 20) +#define is_eow_BIT (1 << 21) +#define is_token_BIT (1 << 22) +#define is_wildmat_BIT (1 << 23) +#define is_sep_BIT (1 << 24) +#define is_empty_BIT (1 << 25) +#define is_alnum_BIT (1 << 26) +#define is_space_BIT (1 << 27) +#define is_control_BIT (1 << 28) +#define is_mime_sep_BIT (1 << 29) +#define is_http_field_name_BIT (1 << 30) +/* shut up the DEC compiler */ +#define is_http_field_value_BIT (((CTypeResult)1) << 31) + +extern ink_undoc_liapi const CTypeResult parseRulesCType[]; +inkcoreapi extern const char parseRulesCTypeToUpper[]; +inkcoreapi extern const char parseRulesCTypeToLower[]; + +class ParseRules +{ +public: + ParseRules(); + + //////////////////////////// + // whitespace definitions // + //////////////////////////// + + enum + { + CHAR_SP = 32, /* space */ + CHAR_HT = 9, /* horizontal tab */ + CHAR_LF = 10, /* line feed */ + CHAR_VT = 11, /* vertical tab */ + CHAR_NP = 12, /* new page */ + CHAR_CR = 13 /* carriage return */ + }; + + ///////////////////// + // character tests // + ///////////////////// + + static CTypeResult is_type(char c, uint32_t bit); + + static CTypeResult is_char(char c); // ASCII 0-127 + static CTypeResult is_upalpha(char c); // A-Z + static CTypeResult is_loalpha(char c); // a-z + static CTypeResult is_alpha(char c); // A-Z,a-z + static CTypeResult is_digit(char c); // 0-9 + static CTypeResult is_ctl(char c); // ASCII 0-31,127 (includes ws) + static CTypeResult is_hex(char c); // 0-9,A-F,a-f + static CTypeResult is_ws(char c); // SP,HT + static CTypeResult is_cr(char c); // CR + static CTypeResult is_lf(char c); // LF + static CTypeResult is_spcr(char c); // SP,CR + static CTypeResult is_splf(char c); // SP,LF + static CTypeResult is_wslfcr(char c); // SP,HT,LF,CR + static CTypeResult is_tspecials(char c); // HTTP chars that need quoting + static CTypeResult is_token(char c); // token (not CTL or specials) + static CTypeResult is_extra(char c); // !,*,QUOT,(,),COMMA + static CTypeResult is_safe(char c); // [$-_.+] + static CTypeResult is_unsafe(char c); // SP,DBLQUOT,#,%,<,> + static CTypeResult is_national(char c); // {,},|,BACKSLASH,^,~,[,],` + static CTypeResult is_reserved(char c); // :,/,?,:,@,&,= + static CTypeResult is_unreserved(char c); // alpha,digit,safe,extra,nat. + static CTypeResult is_punct(char c); // !"#$%&'()*+,-./:;<>=?@_{}|~ + static CTypeResult is_end_of_url(char c); // NUL,CR,SP + static CTypeResult is_eow(char c); // NUL,CR,LF + static CTypeResult is_wildmat(char c); // \,*,?,[ + static CTypeResult is_sep(char c); // NULL,COMMA,':','!',wslfcr + static CTypeResult is_empty(char c); // wslfcr,# + static CTypeResult is_alnum(char c); // 0-9,A-Z,a-z + static CTypeResult is_space(char c); // ' ' HT,VT,NP,CR,LF + static CTypeResult is_control(char c); // 0-31 127 + static CTypeResult is_mime_sep(char c); // ()<>,;\"/[]?{} \t + static CTypeResult is_http_field_name(char c); // not : or mime_sep except for @ + static CTypeResult is_http_field_value(char c); // not CR, LF, comma, or " + + ////////////////// + // string tests // + ////////////////// + + static CTypeResult is_escape(const char *seq); // % + static CTypeResult is_uchar(const char *seq); // starts unresrvd or is escape + static CTypeResult is_pchar(const char *seq); // uchar,:,@,&,=,+ (see code) + + /////////////////// + // unimplemented // + /////////////////// + + //static CTypeResult is_comment(const char * str); + //static CTypeResult is_ctext(const char * str); + + //////////////// + // operations // + //////////////// + + static CTypeResult strncasecmp_eow(const char *s1, const char *s2, int n); + static const char *strcasestr(const char *s1, const char *s2); + static int strlen_eow(const char *s); + static const char *strstr_eow(const char *s1, const char *s2); + + static char ink_toupper(char c); + static char ink_tolower(char c); + static void ink_tolower_buffer(char *ptr, unsigned int n); + static const char *memchr(const char *s, char c, int max_length); + static const char *strchr(const char *s, char c); + + static unsigned char *scan_while(unsigned char *ptr, unsigned int n, uint32_t bitmask); + +private: + ParseRules(const ParseRules &); + ParseRules & operator =(const ParseRules &); +}; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * + * inline functions definitions + * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +inline CTypeResult +ParseRules::is_type(char c, uint32_t bitmask) +{ + return (parseRulesCType[(unsigned char) c] & bitmask); +} + +inline CTypeResult +ParseRules::is_char(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_char_BIT); +#else + return ((c & 0x80) == 0); +#endif +} + +inline CTypeResult +ParseRules::is_upalpha(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_upalpha_BIT); +#else + return (c >= 'A' && c <= 'Z'); +#endif +} + +inline CTypeResult +ParseRules::is_loalpha(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_loalpha_BIT); +#else + return (c >= 'a' && c <= 'z'); +#endif +} + +inline CTypeResult +ParseRules::is_alpha(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_alpha_BIT); +#else + return (is_upalpha(c) || is_loalpha(c)); +#endif +} + +inline CTypeResult +ParseRules::is_digit(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_digit_BIT); +#else + return (c >= '0' && c <= '9'); +#endif +} + +inline CTypeResult +ParseRules::is_alnum(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_alnum_BIT); +#else + return (is_alpha(c) || is_digit(c)); +#endif +} + +inline CTypeResult +ParseRules::is_ctl(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_ctl_BIT); +#else + return ((!(c & 0x80) && c <= 31) || c == 127); +#endif +} + +inline CTypeResult +ParseRules::is_ws(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_ws_BIT); +#else + return (c == CHAR_SP || c == CHAR_HT); +#endif +} + +inline CTypeResult +ParseRules::is_hex(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_hex_BIT); +#else + return ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')); +#endif +} + +inline CTypeResult +ParseRules::is_cr(char c) +{ + return (c == CHAR_CR); +} + +inline CTypeResult +ParseRules::is_lf(char c) +{ + return (c == CHAR_LF); +} + +inline CTypeResult +ParseRules::is_splf(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_splf_BIT); +#else + return (c == CHAR_SP || c == CHAR_LF); +#endif +} + +inline CTypeResult +ParseRules::is_spcr(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_spcr_BIT); +#else + return (c == CHAR_SP || c == CHAR_CR); +#endif +} + +inline CTypeResult +ParseRules::is_wslfcr(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_wslfcr_BIT); +#else + return ParseRules::is_ws(c) || ParseRules::is_splf(c) || ParseRules::is_spcr(c); +#endif +} + +inline CTypeResult +ParseRules::is_extra(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_extra_BIT); +#else + switch (c) { + case '!': + case '*': + case '\'': + case '(': + case ')': + case ',': + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_safe(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_safe_BIT); +#else + return (c == '$' || c == '-' || c == '_' || c == '.' || c == '+'); +#endif +} + +inline CTypeResult +ParseRules::is_unsafe(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_unsafe_BIT); +#else + if (is_ctl(c)) + return (true); + + switch (c) { + case ' ': + case '\"': + case '#': + case '%': + case '<': + case '>': + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_reserved(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_reserved_BIT); +#else + switch (c) { + case ';': + case '/': + case '?': + case ':': + case '@': + case '&': + case '=': + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_national(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_national_BIT); +#else + switch (c) { + case '{': + case '}': + case '|': + case '\\': + case '^': + case '~': + case '[': + case ']': + case '`': + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_unreserved(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_unreserved_BIT); +#else + return (is_alpha(c) || is_digit(c) || is_safe(c) || is_extra(c) || is_national(c)); +#endif +} + +inline CTypeResult +ParseRules::is_punct(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_punct_BIT); +#else + switch (c) { + case '!': + case '"': + case '#': + case '%': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case '-': + case '.': + case '/': + case ':': + case ';': + case '<': + case '=': + case '>': + case '?': + case '@': + case '[': + case '\\': + case ']': + case '^': + case '_': + case '`': + case '{': + case '|': + case '}': + case '~': + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_end_of_url(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_end_of_url_BIT); +#else + return (c == '\0' || c == '\n' || c == ' ' || ParseRules::is_ctl(c) + ); +#endif +} + +inline CTypeResult +ParseRules::is_escape(const char *seq) +{ + return (seq[0] == '%' && is_hex(seq[1]) && is_hex(seq[2])); +} + +inline CTypeResult +ParseRules::is_uchar(const char *seq) +{ + return (is_unreserved(seq[0]) || is_escape(seq)); +} + +// +// have to cheat on this one +// +inline CTypeResult +ParseRules::is_pchar(const char *seq) +{ +#ifndef COMPILE_PARSE_RULES + if (*seq != '%') + return (parseRulesCType[(uint8_t)*seq] & is_pchar_BIT); + else + return is_hex(seq[1]) && is_hex(seq[2]); +#else +#if defined(THIS_IS_THE_ORIGINAL_CODE) + if (is_uchar(seq)) + return (true); + + switch (seq[0]) { + case ':': + case '@': + case '&': + case '=': + case '+': + return (true); + } + return (false); +#else + if (is_unreserved(*seq)) + return (true); + + switch (seq[0]) { + case ':': + case '@': + case '&': + case '=': + case '+': + return (true); + } + return (false); +#endif +#endif +} + +inline CTypeResult +ParseRules::is_tspecials(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_tspecials_BIT); +#else + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + case CHAR_SP: + case CHAR_HT: + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_token(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_token_BIT); +#else + return (is_char(c) && !(is_ctl(c) || is_tspecials(c))); +#endif +} + +inline char +ParseRules::ink_toupper(char c) +{ +#ifndef COMPILE_PARSE_RULES + return parseRulesCTypeToUpper[(unsigned char) c]; +#else + int up_case = c; + const int up_case_diff = 'a' - 'A'; + + if (c >= 'a' && c <= 'z') { + up_case = c - up_case_diff; + } + return (up_case); +#endif +} + +inline char +ParseRules::ink_tolower(char c) +{ +#ifndef COMPILE_PARSE_RULES + return parseRulesCTypeToLower[(unsigned char) c]; +#else + int lo_case = c; + const int lo_case_diff = 'a' - 'A'; + + if (c >= 'A' && c <= 'Z') { + lo_case = c + lo_case_diff; + } + return (lo_case); +#endif +} + +inline CTypeResult +ParseRules::is_eow(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_eow_BIT); +#else + return (c == '\0' || c == '\r' || c == '\n'); +#endif +} + +inline CTypeResult +ParseRules::is_wildmat(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_wildmat_BIT); +#else + return (c == '*' || c == '?' || c == '[' || c == '\\'); +#endif +} + +inline CTypeResult +ParseRules::is_sep(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_sep_BIT); +#else + return (!c || c == ',' || c == ':' || c == '!' || is_wslfcr(c)); +#endif +} + +inline CTypeResult +ParseRules::is_empty(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_empty_BIT); +#else + return (c == '#' || is_wslfcr(c)); +#endif +} + +inline CTypeResult +ParseRules::is_space(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_space_BIT); +#else + switch (c) { + case CHAR_SP: + case CHAR_HT: + case CHAR_LF: + case CHAR_VT: + case CHAR_NP: + case CHAR_CR: + return (true); + } + return (false); +#endif +} + +inline CTypeResult +ParseRules::is_control(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_control_BIT); +#else + if (((unsigned char) c) < 32 || ((unsigned char) c) == 127) + return true; + return false; +#endif +} + +inline CTypeResult +ParseRules::is_mime_sep(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_mime_sep_BIT); +#else + if ((c == '(') || (c == ')') || (c == '<') || (c == '>') || (c == '@') || + (c == ',') || (c == ';') || (c == '\\') || (c == '\"') || + (c == '/') || (c == '[') || (c == ']') || (c == '?') || (c == '{') || (c == '}') || (c == ' ') || (c == '\t')) + return true; + return false; +#endif +} + +inline CTypeResult +ParseRules::is_http_field_name(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (parseRulesCType[(unsigned char) c] & is_http_field_name_BIT); +#else + if ((c == ':') || (is_mime_sep(c) && (c != '@'))) + return false; + return true; +#endif +} + +inline CTypeResult +ParseRules::is_http_field_value(char c) +{ +#ifndef COMPILE_PARSE_RULES + return (CTypeResult) (parseRulesCType[(unsigned char) c] & is_http_field_value_BIT); +#else + switch (c) { + case CHAR_CR: + case CHAR_LF: + case '\"': + case ',': + return false; + } + return true; +#endif +} + +////////////////////////////////////////////////////////////////////////////// +// +// inline CTypeResult ParseRules::strncasecmp_eol(s1, s2, count) +// +// This wacky little function compares if two strings and match +// (case-insensitively) up to characters long, stopping not only +// at the end of string ('\0'), but also at end of line (CR or LF). +// +////////////////////////////////////////////////////////////////////////////// + +inline CTypeResult +ParseRules::strncasecmp_eow(const char *s1, const char *s2, int count) +{ + for (int i = 0; i < count; i++) { + const char &a = s1[i]; + const char &b = s2[i]; + + /////////////////////////////////////////////////////////////// + // if they are different; only match if both are terminators // + /////////////////////////////////////////////////////////////// + if (ink_tolower(a) != ink_tolower(b)) + return (is_eow(a) && is_eow(b)); + } + return (true); +} + +////////////////////////////////////////////////////////////////////////////// +// +// strlen_eow() +// +// return the length of a string +////////////////////////////////////////////////////////////////////////////// +inline int +ParseRules::strlen_eow(const char *s) +{ + for (int i = 0; true; i++) { + if (is_eow(s[i])) + return (i); + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// strstr_eow() +// +// This function is the same as strstr(), except that it accepts strings +// that are terminated with '\r', '\n' or null. +// It returns a pointer to the first occurance of s2 within s1 (or null). +////////////////////////////////////////////////////////////////////////////// +inline const char * +ParseRules::strstr_eow(const char *s1, const char *s2) +{ + int i1; + + int s2_len = strlen_eow(s2); + + for (i1 = 0; !is_eow(s1[i1]); i1++) + if (ink_tolower(s1[i1]) == ink_tolower(s2[0])) + if (strncasecmp_eow(&s1[i1], &s2[0], s2_len)) + return (&s1[i1]); + + return (0); +} + +inline const char * +ParseRules::strcasestr(const char *s1, const char *s2) +{ + int i1; + + size_t s2_len = strlen(s2); + + for (i1 = 0; s1[i1] != '\0'; i1++) + if (ink_tolower(s1[i1]) == ink_tolower(s2[0])) + if (strncasecmp_eow(&s1[i1], &s2[0], (int) s2_len)) + return (&s1[i1]); + + return (0); +} + +inline const char * +ParseRules::memchr(const char *s, char c, int max_length) +{ + for (int i = 0; i < max_length; i++) + if (s[i] == c) + return (&s[i]); + return (0); +} + +inline const char * +ParseRules::strchr(const char *s, char c) +{ + for (int i = 0; s[i] != '\0'; i++) + if (s[i] == c) + return (&s[i]); + return (0); +} + +static inline int +ink_get_hex(char c) +{ + if (ParseRules::is_digit(c)) + return (int) (c - '0'); + c = ParseRules::ink_tolower(c); + return (int) ((c - 'a') + 10); +} + +static inline int +ink_atoi(const char *str) +{ + int num = 0; + int negative = 0; + + while (*str && ParseRules::is_wslfcr(*str)) + str += 1; + + if (unlikely(str[0] == '0' && str[1] == 'x')) { + str += 2; + while (*str && ParseRules::is_hex(*str)) + num = (num << 4) + ink_get_hex(*str++); + } else { + if (unlikely(*str == '-')) { + negative = 1; + str += 1; + } + + /* + NOTE: we first compute the value as negative then correct the + sign back to positive. This enables us to correctly parse MININT. + */ + while (*str && ParseRules::is_digit(*str)) + num = (num * 10) - (*str++ - '0'); +#if USE_SI_MULTILIERS + if (*str) { + if (*str == 'K') + num = num * (1 << 10); + else if (*str == 'M') + num = num * (1 << 20); + else if (*str == 'G') + num = num * (1 << 30); + } +#endif + + if (!negative) + num = -num; + } + + return num; +} + +static inline int +ink_atoi(const char *str, int len) +{ + int num = 0; + int negative = 0; + + while (len > 0 && *str && ParseRules::is_wslfcr(*str)) { + str += 1; + len--; + } + + if (len <= 1) + return 0; + + if (unlikely(str[0] == '0' && len > 1 && str[1] == 'x')) { + str += 2; + while (len > 0 && *str && ParseRules::is_hex(*str)) { + num = (num << 4) + ink_get_hex(*str++); + len--; + } + } else { + if (unlikely(*str == '-')) { + negative = 1; + str += 1; + } + + /* + NOTE: we first compute the value as negative then correct the + sign back to positive. This enables us to correctly parse MININT. + */ + while (len > 0 && *str && ParseRules::is_digit(*str)) { + num = (num * 10) - (*str++ - '0'); + len--; + } +#if USE_SI_MULTILIERS + if (len > 0 && *str) { + if (*str == 'K') + num = num * (1 << 10); + else if (*str == 'M') + num = num * (1 << 20); + else if (*str == 'G') + num = num * (1 << 30); + } +#endif + + if (!negative) + num = -num; + } + return num; +} + +static inline unsigned int +ink_atoui(const char *str) +{ + unsigned int num = 0; + + while (*str && ParseRules::is_wslfcr(*str)) + str += 1; + + if (unlikely(str[0] == '0' && str[1] == 'x')) { + str += 2; + while (*str && ParseRules::is_hex(*str)) + num = (num << 4) + ink_get_hex(*str++); + } else { + while (*str && ParseRules::is_digit(*str)) + num = (num * 10) + (*str++ - '0'); +#if USE_SI_MULTILIERS + if (*str) { + if (*str == 'K') + num = num * (1 << 10); + else if (*str == 'M') + num = num * (1 << 20); + else if (*str == 'G') + num = num * (1 << 30); + } +#endif + } + return num; +} + +static inline int64_t +ink_atoi64(const char *str) +{ + int64_t num = 0; + int negative = 0; + + while (*str && ParseRules::is_wslfcr(*str)) + str += 1; + + if (unlikely(str[0] == '0' && str[1] == 'x')) { + str += 2; + while (*str && ParseRules::is_hex(*str)) + num = (num << 4) + ink_get_hex(*str++); + } else { + if (unlikely(*str == '-')) { + negative = 1; + str += 1; + } + + /* + NOTE: we first compute the value as negative then correct the + sign back to positive. This enables us to correctly parse MININT. + */ + while (*str && ParseRules::is_digit(*str)) + num = (num * 10) - (*str++ - '0'); +#if USE_SI_MULTILIERS + if (*str) { + if (*str == 'K') + num = num * (1LL << 10); + else if (*str == 'M') + num = num * (1LL << 20); + else if (*str == 'G') + num = num * (1LL << 30); + else if (*str == 'T') + num = num * (1LL << 40); + } +#endif + if (!negative) + num = -num; + } + return num; +} + +static inline uint64_t +ink_atoui64(const char *str) +{ + uint64_t num = 0; + + while (*str && ParseRules::is_wslfcr(*str)) + str += 1; + + if (unlikely(str[0] == '0' && str[1] == 'x')) { + str += 2; + while (*str && ParseRules::is_hex(*str)) + num = (num << 4) + ink_get_hex(*str++); + } else { + while (*str && ParseRules::is_digit(*str)) + num = (num * 10) + (*str++ - '0'); +#if USE_SI_MULTILIERS + if (*str) { + if (*str == 'K') + num = num * (1LL << 10); + else if (*str == 'M') + num = num * (1LL << 20); + else if (*str == 'G') + num = num * (1LL << 30); + else if (*str == 'T') + num = num * (1LL << 40); + } +#endif + } + return num; +} + +#endif /* #if !defined (_ParseRules_h_) */ diff --git a/lib/ts/Ptr.h b/lib/ts/Ptr.h new file mode 100644 index 00000000..ddce333b --- /dev/null +++ b/lib/ts/Ptr.h @@ -0,0 +1,417 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************** -*- Mod: C++ -*- ****************************** + + Atmic and non-atomic smart pointers. + + Note: it would have been nice to have one 'Ptr' class, but the + templating system on some compilers is so broken that it cannot + correctly compile Ptr without downcasting the m_ptr object to + a RefCountObj. + + + ****************************************************************************/ +#if !defined (_Ptr_h_) +#define _Ptr_h_ + +#include "ink_atomic.h" + +//////////////////////////////////////////////////////////////////////// +// +// class NonAtomicRefCountObj +// prototypical class for reference counting +// +//////////////////////////////////////////////////////////////////////// +class NonAtomicRefCountObj +{ +public: + NonAtomicRefCountObj():m_refcount(0) + { + return; + } + NonAtomicRefCountObj(const NonAtomicRefCountObj & s):m_refcount(0) + { + (void) s; + return; + } + virtual ~ NonAtomicRefCountObj() { + return; + } + NonAtomicRefCountObj & operator =(const NonAtomicRefCountObj & s) { + (void) s; + return (*this); + } + + int refcount_inc(); + int refcount_dec(); + int refcount() const; + + virtual void free() + { + delete this; + } + + volatile int m_refcount; +}; + +inline int +NonAtomicRefCountObj::refcount_inc() +{ + return ++m_refcount; +} + +#define NONATOMIC_REF_COUNT_OBJ_REFCOUNT_INC(_x) (_x)->refcount_inc() + +inline int +NonAtomicRefCountObj::refcount_dec() +{ + return --m_refcount; +} + +#define NONATOMIC_REF_COUNT_OBJ_REFCOUNT_DEC(_x) (_x)->refcount_dec() + +inline int +NonAtomicRefCountObj::refcount() const +{ + return m_refcount; +} + + + +//////////////////////////////////////////////////////////////////////// +// +// class NonAtomicPtr +// +//////////////////////////////////////////////////////////////////////// +template class NonAtomicPtr { +public: + NonAtomicPtr(T * ptr = 0); + NonAtomicPtr(const NonAtomicPtr &); + ~NonAtomicPtr(); + + void clear(); + NonAtomicPtr &operator =(const NonAtomicPtr &); + NonAtomicPtr &operator =(T *); + + operator T *() const + { + return (m_ptr); + } + T *operator ->() const + { + return (m_ptr); + } + T & operator *() const + { + return (*m_ptr); + } + + int operator ==(const T * p) + { + return (m_ptr == p); + } + int operator ==(const NonAtomicPtr &p) + { + return (m_ptr == p.m_ptr); + } + int operator !=(const T * p) + { + return (m_ptr != p); + } + int operator !=(const NonAtomicPtr &p) + { + return (m_ptr != p.m_ptr); + } + + NonAtomicRefCountObj *_ptr() + { + return (NonAtomicRefCountObj *) m_ptr; + } + + T *m_ptr; +}; + +//////////////////////////////////////////////////////////////////////// +// +// inline functions definitions +// +//////////////////////////////////////////////////////////////////////// +template inline NonAtomicPtr::NonAtomicPtr(T * ptr /* = 0 */ ) +: +m_ptr(ptr) +{ + if (m_ptr) + _ptr()->refcount_inc(); + return; +} + +template inline NonAtomicPtr::NonAtomicPtr(const NonAtomicPtr &src) +: +m_ptr(src.m_ptr) +{ + if (m_ptr) + _ptr()->refcount_inc(); + return; +} + +template inline NonAtomicPtr::~NonAtomicPtr() +{ + if ((m_ptr) && _ptr()->refcount_dec() == 0) { + _ptr()->free(); + } + return; +} + +template inline NonAtomicPtr &NonAtomicPtr::operator =(T * p) +{ + T *temp_ptr = m_ptr; + + if (m_ptr == p) + return (*this); + + m_ptr = p; + + if (m_ptr != 0) { + _ptr()->refcount_inc(); + } + + if ((temp_ptr) && ((NonAtomicRefCountObj *) temp_ptr)->refcount_dec() == 0) { + ((NonAtomicRefCountObj *) temp_ptr)->free(); + } + + return (*this); +} +template inline void NonAtomicPtr::clear() +{ + if (m_ptr) { + if (!((NonAtomicRefCountObj *) m_ptr)->refcount_dec()) + ((NonAtomicRefCountObj *) m_ptr)->free(); + m_ptr = NULL; + } +} +template inline NonAtomicPtr &NonAtomicPtr::operator =(const NonAtomicPtr &src) +{ + return (operator =(src.m_ptr)); +} + + +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +////// ATOMIC VERSIONS +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// + +struct ForceVFPTToTop +{ + virtual ~ ForceVFPTToTop() + { + } +}; + + +//////////////////////////////////////////////////////////////////////// +// +// class RefCountObj +// prototypical class for reference counting +// +//////////////////////////////////////////////////////////////////////// +class RefCountObj: public ForceVFPTToTop +{ +public: + RefCountObj():m_refcount(0) + { + } + RefCountObj(const RefCountObj & s):m_refcount(0) + { + (void) s; + return; + } + virtual ~ RefCountObj() { + } + RefCountObj & operator =(const RefCountObj & s) { + (void) s; + return (*this); + } + + int refcount_inc(); + int refcount_dec(); + int refcount() const; + + virtual void free() + { + delete this; + } + + volatile int m_refcount; +}; + +inline int +RefCountObj::refcount_inc() +{ + return ink_atomic_increment((int *) &m_refcount, 1) + 1; +} + +#define REF_COUNT_OBJ_REFCOUNT_INC(_x) (_x)->refcount_inc() + +inline int +RefCountObj::refcount_dec() +{ + return ink_atomic_increment((int *) &m_refcount, -1) - 1; +} + +#define REF_COUNT_OBJ_REFCOUNT_DEC(_x) (_x)->refcount_dec() + +inline int +RefCountObj::refcount() const +{ + return m_refcount; +} + + +//////////////////////////////////////////////////////////////////////// +// +// class Ptr +// +//////////////////////////////////////////////////////////////////////// +template class Ptr { +public: + Ptr(T * p = 0); + Ptr(const Ptr &); + ~Ptr(); + + void clear(); + Ptr &operator =(const Ptr &); + Ptr &operator =(T *); + + T * to_ptr() { + if (m_ptr && m_ptr->m_refcount == 1) { + T * ptr = m_ptr; + m_ptr = 0; + ptr->m_refcount = 0; + return ptr; + } + return 0; + } + operator T *() const + { + return (m_ptr); + } + T *operator ->() const + { + return (m_ptr); + } + T & operator *() const + { + return (*m_ptr); + } + + int operator ==(const T * p) + { + return (m_ptr == p); + } + int operator ==(const Ptr &p) + { + return (m_ptr == p.m_ptr); + } + int operator !=(const T * p) + { + return (m_ptr != p); + } + int operator !=(const Ptr &p) + { + return (m_ptr != p.m_ptr); + } + + RefCountObj *_ptr() + { + return (RefCountObj *) m_ptr; + } + + T *m_ptr; +}; + +//////////////////////////////////////////////////////////////////////// +// +// inline functions definitions +// +//////////////////////////////////////////////////////////////////////// +template inline Ptr::Ptr(T * ptr /* = 0 */ ) +: +m_ptr(ptr) +{ + if (m_ptr) + _ptr()->refcount_inc(); + return; +} + +template inline Ptr::Ptr(const Ptr &src) +: +m_ptr(src.m_ptr) +{ + if (m_ptr) + _ptr()->refcount_inc(); + return; +} + +template inline Ptr::~Ptr() +{ + if ((m_ptr) && _ptr()->refcount_dec() == 0) { + _ptr()->free(); + } + return; +} + +template inline Ptr &Ptr::operator =(T * p) +{ + T *temp_ptr = m_ptr; + + if (m_ptr == p) + return (*this); + + m_ptr = p; + + if (m_ptr != 0) { + _ptr()->refcount_inc(); + } + + if ((temp_ptr) && ((RefCountObj *) temp_ptr)->refcount_dec() == 0) { + ((RefCountObj *) temp_ptr)->free(); + } + + return (*this); +} +template inline void Ptr::clear() +{ + if (m_ptr) { + if (!((RefCountObj *) m_ptr)->refcount_dec()) + ((RefCountObj *) m_ptr)->free(); + m_ptr = NULL; + } +} +template inline Ptr &Ptr::operator =(const Ptr &src) +{ + return (operator =(src.m_ptr)); +} + +#endif diff --git a/lib/ts/RawHashTable.cc b/lib/ts/RawHashTable.cc new file mode 100644 index 00000000..04a487b0 --- /dev/null +++ b/lib/ts/RawHashTable.cc @@ -0,0 +1,33 @@ +/** @file + + C++ wrapper around libts hash tables + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + These C++ RawHashTables are a C++ wrapper around libts hash tables. + They expose an interface very analogous to ink_hash_table, for better + or for worse. See HashTable for a more C++-oriented hash table. + +*/ + +#include "RawHashTable.h" +#include "ink_unused.h" + diff --git a/lib/ts/RawHashTable.h b/lib/ts/RawHashTable.h new file mode 100644 index 00000000..529f7248 --- /dev/null +++ b/lib/ts/RawHashTable.h @@ -0,0 +1,400 @@ +/** @file + + C++ wrapper around libts hash tables + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + These C++ RawHashTables are a C++ wrapper around libts hash tables. + They expose an interface very analogous to ink_hash_table, for better + or for worse. See HashTable for a more C++-oriented hash table. + +*/ + +#ifndef _RawHashTable_h_ +#define _RawHashTable_h_ + +#include "libts.h" + +#include "ink_apidefs.h" + +////////////////////////////////////////////////////////////////////////////// +// +// Constants and Type Definitions +// +////////////////////////////////////////////////////////////////////////////// + +typedef enum +{ + RawHashTable_KeyType_String = InkHashTableKeyType_String, + RawHashTable_KeyType_Word = InkHashTableKeyType_Word +} RawHashTable_KeyType; + +typedef InkHashTableKey RawHashTable_Key; +typedef InkHashTableValue RawHashTable_Value; +typedef InkHashTableEntry RawHashTable_Binding; +typedef InkHashTableIteratorState RawHashTable_IteratorState; + +////////////////////////////////////////////////////////////////////////////// +// +// The RawHashTable Class +// +////////////////////////////////////////////////////////////////////////////// + +class RawHashTable +{ +private: + InkHashTable * ht; + RawHashTable_KeyType key_type; + bool deallocate_values_on_destruct; + +public: + inkcoreapi RawHashTable(RawHashTable_KeyType key_type, bool deallocate_values_on_destruct = false); + virtual ~ RawHashTable(); + + // + // these are the simplest accessor functions + // + + bool getValue(RawHashTable_Key key, RawHashTable_Value * value_ptr); + void setValue(RawHashTable_Key key, RawHashTable_Value value_ptr); + bool isBound(RawHashTable_Key key); + bool unbindKey(RawHashTable_Key key); + void replaceString(char *key, char *string); + + // + // these functions allow you to manipulate the (key,value) bindings directly + // + + RawHashTable_Binding *getCurrentBinding(RawHashTable_Key key); + RawHashTable_Binding *getOrCreateBinding(RawHashTable_Key key, bool * was_new = NULL); + + void setBindingValue(RawHashTable_Binding * binding, RawHashTable_Value value); + RawHashTable_Key getKeyFromBinding(RawHashTable_Binding * binding); + RawHashTable_Value getValueFromBinding(RawHashTable_Binding * binding); + + // + // these functions allow you to iterate through RawHashTable bindings + // + + RawHashTable_Binding *firstBinding(RawHashTable_IteratorState * state_ptr); + RawHashTable_Binding *nextBinding(RawHashTable_IteratorState * state_ptr); +}; + +////////////////////////////////////////////////////////////////////////////// +// +// Inline Methods +// +////////////////////////////////////////////////////////////////////////////// + +/** + This routine gets the value associated with key. If the key has a + binding, the value is stored through value_ptr and true is returned. If + the key DOES NOT have a binding, false is returned. + +*/ +inline bool +RawHashTable::getValue(RawHashTable_Key key, RawHashTable_Value * value_ptr) +{ + int is_bound; + + is_bound = ink_hash_table_lookup(ht, (InkHashTableKey) key, (InkHashTableValue *) value_ptr); + return (is_bound ? true : false); +} + +/** + This routine sets the value associated with key to the value. If + a value is previously bound to the key, the previous value is left + dangling. The caller is responsible to freeing any previous binding + values needing freeing before calling setValue. + + If the key has a binding, the value is stored through value_ptr and + true is returned. If the key DOES NOT have a binding, false is returned. + +*/ +inline void +RawHashTable::setValue(RawHashTable_Key key, RawHashTable_Value value) +{ + ink_hash_table_insert(ht, (InkHashTableKey) key, (InkHashTableValue) value); +} + +/** + This routine sets the value associated with key to the value pointed to + by value_ptr. If a value is previously bound to the key, the previous + value is left dangling. The caller is responsible to freeing any + previous value before setValue. + + If the key has a binding, the value is stored through value_ptr and + true is returned. If the key DOES NOT have a binding, false is returned. + +*/ +inline bool +RawHashTable::isBound(RawHashTable_Key key) +{ + int status = ink_hash_table_isbound(ht, (InkHashTableKey) key); + return (status ? true : false); +} + +/** + This routine removes any association for key from the hash table. If + data was bound to key, the binding will be deleted, but the value will + not be deallocated. The caller is responsible to freeing any previous + value before unbindKey. + + @return true if the key was previously bound, false otherwise. + +*/ +inline bool +RawHashTable::unbindKey(RawHashTable_Key key) +{ + int status; + + status = ink_hash_table_delete(ht, (InkHashTableKey) key); + return (status ? true : false); +} + +/** + This rather specialized routine binds a malloc-allocated string value + to the key, freeing any previous value. The key must be a string, + and the hash table must have been constructed as having key_type + RawHashTable_KeyType_String. + +*/ +inline void +RawHashTable::replaceString(char *key, char *string) +{ +// if (key_type != RawHashTable_KeyType_String) +// { +// throw BadKeyType(); +// } + + ink_hash_table_replace_string(ht, key, string); +} + +/** + This function looks up a binding for key in the hash table, and returns + a pointer to the binding data structure directly inside the hash table, + or NULL if there is no binding. + +*/ +inline RawHashTable_Binding * +RawHashTable::getCurrentBinding(RawHashTable_Key key) +{ + InkHashTableEntry *he_ptr; + + he_ptr = ink_hash_table_lookup_entry(ht, (InkHashTableKey) key); + return ((RawHashTable_Binding *) he_ptr); +} + +/** + This function looks up a binding for key in the hash table, creates + a binding if one doesn't exist, and returns a pointer to the binding + data structure directly inside the hash table. + + If was_new is not NULL, true is stored through was_new. If no binding + previously existed, false is stored through was_new if a binding + previously existed. + +*/ +inline RawHashTable_Binding * +RawHashTable::getOrCreateBinding(RawHashTable_Key key, bool * was_new) +{ + int _was_new; + InkHashTableEntry *he_ptr; + + he_ptr = ink_hash_table_get_entry(ht, (InkHashTableKey) key, &_was_new); + *was_new = (_was_new ? true : false); + return ((RawHashTable_Binding *) he_ptr); +} + +/** + This function looks up a binding for key in the hash table, creates + a binding if one doesn't exist, and returns a pointer to the binding + data structure directly inside the hash table. + + If was_new is not NULL, true is stored through was_new. If no binding + previously existed, false is stored through was_new if a binding + previously existed. + +*/ +inline void +RawHashTable::setBindingValue(RawHashTable_Binding * binding, RawHashTable_Value value) +{ + ink_hash_table_set_entry(ht, (InkHashTableEntry *) binding, (InkHashTableValue) value); +} + +/** + This function takes a binding and extracts the key. + +*/ +inline RawHashTable_Key +RawHashTable::getKeyFromBinding(RawHashTable_Binding * binding) +{ + InkHashTableKey ht_key; + + ht_key = ink_hash_table_entry_key(ht, (InkHashTableEntry *) binding); + return ((RawHashTable_Key) ht_key); +} + +/** + This function takes a binding and extracts the value. + +*/ +inline RawHashTable_Value +RawHashTable::getValueFromBinding(RawHashTable_Binding * binding) +{ + InkHashTableValue ht_value; + + ht_value = ink_hash_table_entry_value(ht, (InkHashTableEntry *) binding); + return ((RawHashTable_Value) ht_value); +} + +/** + This function takes a hash table, initializes an interator data + structure to point to the first binding in the hash table, and returns + the first binding, or NULL if there are none. + +*/ +inline RawHashTable_Binding * +RawHashTable::firstBinding(RawHashTable_IteratorState * state_ptr) +{ + InkHashTableEntry *he_ptr; + + he_ptr = ink_hash_table_iterator_first(ht, (InkHashTableIteratorState *) state_ptr); + return ((RawHashTable_Binding *) he_ptr); +} + +inline +RawHashTable::RawHashTable(RawHashTable_KeyType akey_type, bool adeallocate_values_on_destruct) +{ + RawHashTable::key_type = akey_type; + RawHashTable::deallocate_values_on_destruct = adeallocate_values_on_destruct; + ht = ink_hash_table_create((InkHashTableKeyType) key_type); +} + +inline +RawHashTable::~ +RawHashTable() +{ + if (deallocate_values_on_destruct) + ink_hash_table_destroy_and_free_values(ht); + else + ink_hash_table_destroy(ht); +} + +/** + This function takes a hash table and a pointer to iterator state, + and advances to the next binding in the hash table, if any. If there + in a next binding, a pointer to the binding is returned, else NULL. + +*/ +inline RawHashTable_Binding * +RawHashTable::nextBinding(RawHashTable_IteratorState * state_ptr) +{ + InkHashTableEntry *he_ptr; + + he_ptr = ink_hash_table_iterator_next(ht, (InkHashTableIteratorState *) state_ptr); + return ((RawHashTable_Binding *) he_ptr); +} + +////////////////////////////////////////////////////////////////////////////// +// +// The RawHashTableIter Class +// +////////////////////////////////////////////////////////////////////////////// + +class RawHashTableIter +{ +public: + RawHashTableIter(RawHashTable & ht); + ~RawHashTableIter(); + + RawHashTable_Value & operator ++(); // get next + RawHashTable_Value & operator () () const; // get current + operator const void *() const; // is valid + + RawHashTable_Value & value() const; // get current value + const char *key() const; // get current key + + +private: + RawHashTable & m_ht; + RawHashTable_Binding *m_currentBinding; + RawHashTable_IteratorState m_hashIterState; +}; + +////////////////////////////////////////////////////////////////////////////// +// +// Inline Methods +// +////////////////////////////////////////////////////////////////////////////// + +inline RawHashTable_Value & +RawHashTableIter::operator () () +const +{ + return (m_currentBinding->clientData); +} + +inline RawHashTable_Value & +RawHashTableIter::operator ++() +{ + m_currentBinding = m_ht.nextBinding(&m_hashIterState); + return (m_currentBinding->clientData); +} + +inline +RawHashTableIter::operator const void *() +const +{ + return ((m_currentBinding != 0) ? this : 0); +} + +inline + RawHashTable_Value & +RawHashTableIter::value() const +{ + return (m_currentBinding->clientData); +} + +inline const char * +RawHashTableIter::key() const +{ + return (m_currentBinding->key.string); +} + +inline +RawHashTableIter::RawHashTableIter(RawHashTable & ht) + : +m_ht(ht), +m_currentBinding(0) +{ + m_currentBinding = m_ht.firstBinding(&m_hashIterState); + return; +} + +inline +RawHashTableIter::~ +RawHashTableIter() +{ + return; +} + +#endif /*_RawHashTable_h_*/ diff --git a/lib/ts/Regex.cc b/lib/ts/Regex.cc new file mode 100644 index 00000000..27cd12cb --- /dev/null +++ b/lib/ts/Regex.cc @@ -0,0 +1,146 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "Regex.h" + +DFA::~DFA() +{ + dfa_pattern * p = _my_patterns; + dfa_pattern * t = p; + + while(p) { + if (p->_pe) + pcre_free(p->_pe); + if (p->_re) + pcre_free(p->_re); + if(p->_p) + ink_free(p->_p); + t = p->_next; + ink_free(p); + p = t; + } +} + +dfa_pattern * +DFA::build(const char *pattern, REFlags flags) +{ + const char *error; + int erroffset; + dfa_pattern* ret; + + ret = (dfa_pattern*) ink_malloc(sizeof(dfa_pattern)); + ret->_p = NULL; + + if (flags & RE_CASE_INSENSITIVE) + ret->_re = pcre_compile(pattern, PCRE_CASELESS|PCRE_ANCHORED, &error, &erroffset, NULL); + else + ret->_re = pcre_compile(pattern, PCRE_ANCHORED, &error, &erroffset, NULL); + + if (error) { + ink_free(ret); + return NULL; + } + + ret->_pe = pcre_study(ret->_re, 0, &error); + + if (error) { + ink_free(ret); + return NULL; + } + + ret->_idx = 0; + ret->_p = ink_strndup(pattern,strlen(pattern)); + ret->_next = NULL; + return ret; +} + +int DFA::compile(const char *pattern, REFlags flags) { + _my_patterns = build(pattern,flags); + if (_my_patterns) + return 0; + else + return -1; +} + +int +DFA::compile(const char **patterns, int npatterns, REFlags flags) +{ + const char *pattern; + dfa_pattern *ret = NULL; + dfa_pattern *end = NULL; + int i; + //char buf[128]; + + for (i = 0; i < npatterns; i++) { + pattern = patterns[i]; + //snprintf(buf,128,"%s",pattern); + ret = build(pattern,flags); + if (!ret) { + continue; + } + + if (!_my_patterns) { + _my_patterns = ret; + _my_patterns->_next = NULL; + _my_patterns->_idx = i; + } + else { + end = _my_patterns; + while( end->_next ) { + end = end->_next; + } + end->_next = ret; //add to end + ret->_idx = i; + } + + } + + return 0; +} + +int +DFA::match(const char *str) +{ + return match(str,strlen(str)); +} + +int +DFA::match(const char *str, int length) +{ + int rc; + int ovector[30]; + //int wspace[20]; + dfa_pattern * p = _my_patterns; + + while(p) { + rc = pcre_exec(p->_re, p->_pe, str, length , 0, 0, ovector, 30/*,wspace,20*/); + if (rc > 0) { + return p->_idx; + } + p = p->_next; + } + + return -1; +} + diff --git a/lib/ts/Regex.h b/lib/ts/Regex.h new file mode 100644 index 00000000..12aaffb9 --- /dev/null +++ b/lib/ts/Regex.h @@ -0,0 +1,67 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __TS_REGEX_H__ +#define __TS_REGEX_H__ + +#ifdef HAVE_PCRE_PCRE_H +#include +#else +#include +#endif + + +enum REFlags +{ + RE_CASE_INSENSITIVE = 1 +}; + +typedef struct __pat { + int _idx; + pcre *_re; + pcre_extra *_pe; + char *_p; + __pat * _next; +} dfa_pattern; + +class DFA +{ +public: + DFA():_my_patterns(0) { + } + + ~DFA(); + + int compile(const char *pattern, REFlags flags = (REFlags) 0); + int compile(const char **patterns, int npatterns, REFlags flags = (REFlags) 0); + dfa_pattern * build(const char *pattern, REFlags flags = (REFlags) 0); + + int match(const char *str); + int match(const char *str, int length); + +private: + dfa_pattern * _my_patterns; +}; + + +#endif /* __TS_REGEX_H__ */ diff --git a/lib/ts/Regression.cc b/lib/ts/Regression.cc new file mode 100644 index 00000000..d67e01df --- /dev/null +++ b/lib/ts/Regression.cc @@ -0,0 +1,209 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/**************************************************************************** + + Regression.cc + + + ****************************************************************************/ + +#include "libts.h" +#include "Regression.h" + +static RegressionTest *test = NULL; +static RegressionTest *exclusive_test = NULL; + +RegressionTest *RegressionTest::current = 0; +int RegressionTest::ran_tests = 0; +DFA RegressionTest::dfa; +int regression_level = 0; +int RegressionTest::final_status = REGRESSION_TEST_PASSED; + +char * +regression_status_string(int status) +{ + return (char *) (status == REGRESSION_TEST_NOT_RUN ? "NOT_RUN" : + (status == REGRESSION_TEST_PASSED ? "PASSED" : + (status == REGRESSION_TEST_INPROGRESS ? "INPROGRESS" : "FAILED"))); +} + +RegressionTest::RegressionTest(const char *name_arg, TestFunction * function_arg, int aopt) +{ + name = name_arg; + function = function_arg; + status = REGRESSION_TEST_NOT_RUN; + printed = 0; + opt = aopt; + + if (opt == REGRESSION_OPT_EXCLUSIVE) { + if (exclusive_test) + this->next = exclusive_test; + exclusive_test = this; + } else { + if (test) + this->next = test; + test = this; + } +} + +static inline int +start_test(RegressionTest * t) +{ + ink_debug_assert(t->status == REGRESSION_TEST_NOT_RUN); + t->status = REGRESSION_TEST_INPROGRESS; + fprintf(stderr, "REGRESSION TEST %s started\n", t->name); + (*t->function) (t, regression_level, &t->status); + int tresult = t->status; + if (tresult != REGRESSION_TEST_INPROGRESS) { + fprintf(stderr, " REGRESSION_RESULT %s:%*s %s\n", t->name, + 40 - (int)strlen(t->name), " ", regression_status_string(tresult)); + t->printed = 1; + } + return tresult; +} + +int +RegressionTest::run(char *atest) +{ + if (atest) + dfa.compile(atest); + else + dfa.compile(".*"); + fprintf(stderr, "REGRESSION_TEST initialization begun\n"); + // start the non exclusive tests + for (RegressionTest * t = test; t; t = t->next) { + if ((dfa.match(t->name) >= 0)) { + int res = start_test(t); + if (res == REGRESSION_TEST_FAILED) + final_status = REGRESSION_TEST_FAILED; + } + } + current = exclusive_test; + return run_some(); +} + +int +RegressionTest::run_some() +{ + + if (current->status == REGRESSION_TEST_INPROGRESS) + return REGRESSION_TEST_INPROGRESS; + else if (current->status != REGRESSION_TEST_NOT_RUN) { + if (!current->printed) { + current->printed = true; + fprintf(stderr, " REGRESSION_RESULT %s:%*s %s\n", current->name, + 40 - (int)strlen(current->name), " ", regression_status_string(current->status)); + } + current = current->next; + } + for (; current; current = current->next) { + if ((dfa.match(current->name) >= 0)) { + int res = start_test(current); + if (res == REGRESSION_TEST_INPROGRESS) + return res; + if (res == REGRESSION_TEST_FAILED) + final_status = REGRESSION_TEST_FAILED; + } + } + return REGRESSION_TEST_INPROGRESS; +} + +int +RegressionTest::check_status() +{ + int status = REGRESSION_TEST_PASSED; + if (current) { + status = run_some(); + if (!current) + return status; + } + RegressionTest *t = test; + int exclusive = 0; + +check_test_list: + while (t) { + if ((t->status == REGRESSION_TEST_PASSED || t->status == REGRESSION_TEST_FAILED) && !t->printed) { + t->printed = true; + fprintf(stderr, " REGRESSION_RESULT %s:%*s %s\n", t->name, + 40 - (int)strlen(t->name), " ", regression_status_string(t->status)); + } + + switch (t->status) { + case REGRESSION_TEST_FAILED: + final_status = REGRESSION_TEST_FAILED; + break; + case REGRESSION_TEST_INPROGRESS: + printf("Regression test(%s) still in progress\n", t->name); + status = REGRESSION_TEST_INPROGRESS; + break; + default: + break; + } + t = t->next; + } + if (!exclusive) { + exclusive = 1; + t = exclusive_test; + goto check_test_list; + } + + return (status == REGRESSION_TEST_INPROGRESS) ? REGRESSION_TEST_INPROGRESS : final_status; +} + +int +rprintf(RegressionTest *t, const char *format, ...) +{ + int l; + char buffer[8192]; + char format2[8192]; + snprintf(format2, sizeof(format2), "RPRINT %s: %s", t->name, format); + va_list ap; + va_start(ap, format); + l = ink_bvsprintf(buffer, format2, ap); + va_end(ap); + fputs(buffer, stderr); + return (l); +} + +int +rperf(RegressionTest *t, const char *tag, double val) +{ + int l; + char format2[8192]; + l = snprintf(format2, sizeof(format2), "RPERF %s.%s %f\n", t->name, tag, val); + fputs(format2, stderr); + return (l); +} + +REGRESSION_TEST(Regression) (RegressionTest * t, int atype, int *status) { + (void) t; + (void) atype; + rprintf(t, "regression test\n"); + rperf(t, "speed", 100.0); + if (!test) + *status = REGRESSION_TEST_FAILED; + else + *status = REGRESSION_TEST_PASSED; +} diff --git a/lib/ts/Regression.h b/lib/ts/Regression.h new file mode 100644 index 00000000..afcc9a23 --- /dev/null +++ b/lib/ts/Regression.h @@ -0,0 +1,111 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _Regression_h +#define _Regression_h + +#include "libts.h" +#include "Regex.h" + +// Each module should provide one or more regression tests +// +// An example: +// +// REGRESSION_TEST(Addition)(RegressionTest *t, int atype, int *pstatus) { +// if (atype < REGRESSION_TEST_NIGHTLY) { // to expensive to do more than nightly +// *pstatus = REGRESSION_TEST_NOT_RUN; +// return; +// } +// if (1 + 1 != 2) { +// rprintf(t, "drat, 1+1 isn't 2??"); +// *pstatus = REGRESSION_TEST_FAILED; +// } else +// *pstatus = REGRESSION_TEST_PASSED; +// } + + +// status values +#define REGRESSION_TEST_PASSED 1 +#define REGRESSION_TEST_INPROGRESS 0 // initial value +#define REGRESSION_TEST_FAILED -1 +#define REGRESSION_TEST_NOT_RUN -2 + +// regression types +#define REGRESSION_TEST_NONE 0 +#define REGRESSION_TEST_QUICK 1 +#define REGRESSION_TEST_NIGHTLY 2 +#define REGRESSION_TEST_EXTENDED 3 + // use only for testing TS error handling! +#define REGRESSION_TEST_FATAL 4 + +// regression options +#define REGRESSION_OPT_EXCLUSIVE (1 << 0) + +struct RegressionTest; + +typedef void TestFunction(RegressionTest * t, int type, int *status); + +struct RegressionTest +{ + const char *name; + TestFunction *function; + RegressionTest *next; + int status; + int printed; + int opt; + + RegressionTest(const char *name_arg, TestFunction * function_arg, int aopt); + + static int final_status; + static int ran_tests; + static DFA dfa; + static RegressionTest *current; + static int run(char *name = NULL); + static int run_some(); + static int check_status(); +}; + +#define REGRESSION_TEST(_f) \ +void RegressionTest_##_f(RegressionTest * t, int atype, int *pstatus); \ +RegressionTest regressionTest_##_f(#_f,&RegressionTest_##_f, 0);\ +void RegressionTest_##_f + +#define EXCLUSIVE_REGRESSION_TEST(_f) \ +void RegressionTest_##_f(RegressionTest * t, int atype, int *pstatus); \ +RegressionTest regressionTest_##_f(#_f,&RegressionTest_##_f, REGRESSION_OPT_EXCLUSIVE);\ +void RegressionTest_##_f + +int rprintf(RegressionTest * t, const char *format, ...); +int rperf(RegressionTest *t, const char *tag, double val); +char *regression_status_string(int status); + +extern int regression_level; + +#define SignalError(_buf, _already) \ +{ \ + if(_already == false) pmgmt->signalManager(MGMT_SIGNAL_CONFIG_ERROR, _buf); \ + _already = true; \ + Warning(_buf); \ +} \ + +#endif /* _Regression_h */ diff --git a/lib/ts/Resource.cc b/lib/ts/Resource.cc new file mode 100644 index 00000000..1b4b0504 --- /dev/null +++ b/lib/ts/Resource.cc @@ -0,0 +1,66 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include + +#include "ink_port.h" +#include "Resource.h" + + + +#if defined(TRACK_MEMORY) + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ +void *operator +new(size_t size) +{ + return xmalloc((unsigned int) size); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void operator +delete(void *p) +{ + _xfree(p); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ +void *operator new[] (size_t size) +{ + return xmalloc((unsigned int) size); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void operator delete[] (void *p) +{ + _xfree(p); +} + +#endif /* TRACK_MEMORY */ diff --git a/lib/ts/Resource.h b/lib/ts/Resource.h new file mode 100644 index 00000000..945b3fc6 --- /dev/null +++ b/lib/ts/Resource.h @@ -0,0 +1,63 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __RESOURCE_H__ +#define __RESOURCE_H__ + + +#include +#include "ink_resource.h" + +#ifdef TRACK_MEMORY + +#define NEW(mem) _xtrack_helper (mem, RES_MEM_PATH) + +#if defined(__SUNPRO_CC) && (__SUNPRO_CC >= 0x500) +void *operator +new(size_t) +throw(std::bad_alloc); +void operator +delete(void *) +throw(); +#else +extern void *operator new(size_t size); +extern void operator delete(void *p); +#endif + +#if !defined(__SUNPRO_CC) && !defined (_WIN64) +extern void *operator new[] (size_t size); +extern void operator delete[] (void *p); +#endif + +template static inline T * +_xtrack_helper(T * ptr, const char *path) +{ + return (T *) _xtrack(ptr, path); +} + +#else + +#define NEW(mem) mem + +#endif +#endif /* __RESOURCE_H__ */ diff --git a/lib/ts/SimpleTokenizer.h b/lib/ts/SimpleTokenizer.h new file mode 100644 index 00000000..5ca1b062 --- /dev/null +++ b/lib/ts/SimpleTokenizer.h @@ -0,0 +1,293 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _SIMPLE_TOKENIZER_H_ +#define _SIMPLE_TOKENIZER_H_ + +#include +#include +#include +#include "ink_bool.h" +#include "ink_resource.h" + +/*----------------------------------------------------------------------------- + SimpleTokenizer + + This class provides easy token parsing from an input string. It supports: + + 1- ignoring (or not) of null fields + 2- left whitespace trimming + 3- right whitespace trimming + 4- escaping the delimiter character with a user defined escape character + + The class has two constructors, one that defines the input string, + and another one that does not. If the latter is used, then the + setString method should be used to set the data string. + + Both constructors set the delimiter, the operation mode (which + defines bullets 1-3 above), and the escape character. + + The available methods are: + + void setString(char *s) + sets the data string to s. The mode specified upon construction of the + tokenizer determines whether s is copied or not. + + char *getNext() + returns the next token, or NULL if there are no more tokens. This method + uses the delimiter specified upon object construction. + + char *getNext(char delimiter) + similar to getNext(), but allows the user to change the delimiter (just for + this call). + + char *getNext(int count) + get the next count tokens as a single token (ignoring the delimiters in + between). + + char *getNext(char delimiter, int count) + this is similar to getNext(int count) but allows user to specify the + delimiter. + + IMPORTANT: the char pointers returned by the SimpleTokenizer are valid + ONLY during the lifetime of the object. The copy of the input string + is destroyed by the object's destructor. + + char *getRest() + returns the rest of the tokens all together. Advances pointer so a + subsequent call to getNext returns NULL; + + char *peekAtRestOfString() + returns the rest of the input string, but DOES NOT advance pointer so a + subsequent call to getNext does return the next token (if there is still + one). + + size_t getNumTokensRemaining() + returns the number of tokens remaining in the string (using the delimiter + specified upon object construction). + + size_t getNumTokensRemaining(char delimiter) + similar to the above, but allows the user to change the delimiter (just for + this call). + + Note that multiple delimiters are not supported (more than one per call). + + examples: + + SimpleTokenizer tok("one two\\ and\\ three four: five : six"); + tok.getNumTokensRemaining() --> 5 note calculation is done assuming + space is the delimiter + tok.getNext() -> "one" + tok.getNext() -> "two and three" + tok.getNext(':') -> "four" + tok.peekAtRestOfString() -> " five : six" + tok.getNext(':') -> "five" + + SimpleTokenizer tok(", with null fields ,,,", ',', + CONSIDER_NULL_FIELDS | KEEP_WHITESPACE); + tok.getNext() -> "" + tok.getNext() -> " with null fields " + tok.getNumTokensRemaining() -> 3 + + ---------------------------------------------------------------------------*/ + +class SimpleTokenizer +{ +public: + + // by default, null fields are disregarded, whitespace is trimmed left + // and right, and input string is copied (not overwritten) + // + enum + { + CONSIDER_NULL_FIELDS = 1, + KEEP_WHITESPACE_LEFT = 2, + KEEP_WHITESPACE_RIGHT = 4, + KEEP_WHITESPACE = KEEP_WHITESPACE_LEFT + KEEP_WHITESPACE_RIGHT, + OVERWRITE_INPUT_STRING = 8 + }; + + SimpleTokenizer(char delimiter = ' ', int mode = 0, char escape = '\\') + : _data(0), _delimiter(delimiter), _mode(mode), _escape(escape), _start(0), _length(0) + { } + +SimpleTokenizer(char *s, char delimiter = ' ', int mode = 0, char escape = '\\') + : _data(0), _delimiter(delimiter), _mode(mode), _escape(escape) + { + setString(s); + } + + ~SimpleTokenizer() { + _clearData(); + } + + void setString(char *s) + { + _clearData(); + + _start = 0; + _length = strlen(s); + _data = (_mode & OVERWRITE_INPUT_STRING ? s : xstrdup(s)); + + // to handle the case where there is a null field at the end of the + // input string, we replace the null character at the end of the + // string with the delimiter (and consider the string to be one + // character larger). + // + _data[_length++] = _delimiter; + }; + char *getNext(int count = 1) { + return _getNext(_delimiter, false, count); + }; + char *getNext(char delimiter, int count = 1) { + return _getNext(delimiter, false, count); + } + char *getRest() + { + // there can't be more than _length tokens, so we get the rest + // of the tokens by requesting _length of them + // + return _getNext(_delimiter, false, _length); + } + size_t getNumTokensRemaining() + { + return _getNumTokensRemaining(_delimiter); + }; + size_t getNumTokensRemaining(char delimiter) + { + return _getNumTokensRemaining(delimiter); + }; + char *peekAtRestOfString() + { + _data[_length - 1] = 0; + return (_start < _length ? &_data[_start] : &_data[_length - 1]); + } + +private: + + char *_data; // a pointer to the input data itself, + // or to a copy of it + char _delimiter; // the token delimiter + int _mode; // flags that determine the + // mode of operation + char _escape; // the escape character + size_t _start; // pointer to the start of the next + // token + size_t _length; // the length of _data + + void _clearData() + { + if (_data && !(_mode & OVERWRITE_INPUT_STRING)) { + free(_data); + } + } + + char *_getNext(char delimiter, bool countOnly = false, int numTokens = 1) { + char *next = NULL; + + if (_start < _length) { + // set start + // + bool hasEsc = false; // escape character seen + while (_start < _length && + ((!(_mode & CONSIDER_NULL_FIELDS) && + (_data[_start] == delimiter && + !(_start && + (_data[_start - 1] == _escape ? (hasEsc = true) : 0)))) || + (!(_mode & KEEP_WHITESPACE_LEFT) && isspace(_data[_start])))) { + ++_start; + } + + if (_start < _length) // data still available + { + // update the extra delimiter just in case the function + // is called with a different delimiter from the previous one + // + _data[_length - 1] = delimiter; + + next = &_data[_start]; + + // set end + // + size_t end = _start; + int delimCount = 0; + while (end < _length && + (_data[end] != delimiter || + (end && (_data[end - 1] == _escape ? (hasEsc = true) : 0)) || + ((++delimCount < numTokens) && (end < _length - 1)))) { + ++end; + } + + _start = end + 1; + + // there can be delimiters at the end if the number of tokens + // requested is larger than 1, remove them if the + // CONSIDER_NULL_FIELDS flag is not set + // + if (!(_mode & CONSIDER_NULL_FIELDS)) { + while (_data[--end] == delimiter); + ++end; + } + + if (!(_mode & KEEP_WHITESPACE_RIGHT)) { + while (isspace(_data[--end])); + ++end; + } + + if (!countOnly) { + _data[end] = 0; + + // remove escape characters only if the number of + // delimiters is one + // + if (hasEsc && delimCount == 1) { + int numEscape = 0, i = 0; + while (next[i]) { + if (next[i] == _escape) { + ++numEscape; + } else { + next[i - numEscape] = next[i]; + } + ++i; + } + _data[end - numEscape] = 0; + } + } + } + } + return next; + }; + + size_t _getNumTokensRemaining(char delimiter) + { + size_t startSave = _start; // save current position + size_t count = 0; + while (_getNext(delimiter, true)) { + ++count; + }; + _start = startSave; + return count; + }; +}; + +#endif diff --git a/lib/ts/TestHttpHeader.cc b/lib/ts/TestHttpHeader.cc new file mode 100644 index 00000000..cda3c6e5 --- /dev/null +++ b/lib/ts/TestHttpHeader.cc @@ -0,0 +1,216 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************** -*- Mod: C++ -*- ****************************** + + TestHeaderTokenizer.cc -- + Created On : Mon Jan 20 11:48:10 1997 + + + ****************************************************************************/ +#include "HttpHeaderTokenizer.h" +#include "ink_assert.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +static void +add_field(HttpHeader * h, const char *name, const char *value) +{ + h->m_header_fields.set_raw_header_field(name, value); +} + +///////////////////////////////////////////////////////////// +// +// test_add_fields() +// +///////////////////////////////////////////////////////////// +static void +test_add_fields(HttpHeader * h) +{ + char long_accept_header[2048]; + memset(long_accept_header, 'B', sizeof(long_accept_header)); + long_accept_header[sizeof(long_accept_header) - 1] = '\0'; + add_field(h, "Accept", long_accept_header); + add_field(h, "Accept", "image/gif"); + add_field(h, "Accept", "image/x-xbitmap"); + add_field(h, "Accept", "image/jpeg"); + add_field(h, "Accept", "image/pjpeg"); + add_field(h, "Accept", "*/*"); + add_field(h, "Set-Cookie", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + add_field(h, "Set-Cookie", "1234567890987654321"); + return; +} + +///////////////////////////////////////////////////////////// +// +// test_hacked_http_header_field() +// +///////////////////////////////////////////////////////////// +static void +test_hacked_http_header_field() +{ + HttpHackedMultiValueRawHeaderField f; + +#define ADD_FIELD(s) f.add(s, sizeof(s)) + ADD_FIELD("image/gif"); + ADD_FIELD("image/x-xbitmap"); + ADD_FIELD("image/jpeg"); + ADD_FIELD("image/pjpeg"); + ADD_FIELD("*/*"); +#undef ADD_FIELD + + int count = f.get_count(); + cout << "count = " << count << endl; + int length = 0; + for (int i = 0; i < count; i++) { + cout << "Accept: " << f.get(i, &length) << endl; + cout << "(length = " << length << ")" << endl; + } + return; +} + +///////////////////////////////////////////////////////////// +// +// test_url_parse() +// +///////////////////////////////////////////////////////////// +void +test_url_parse(const char *url_string) +{ + URL url(url_string, strlen(url_string)); + char buf[4096]; + + url.dump(buf, sizeof(buf)); + + cout << buf << endl; + + return; +} + +///////////////////////////////////////////////////////////// +// +// test_url() +// +///////////////////////////////////////////////////////////// +void +test_url() +{ + test_url_parse("http://charm.example.com "); + test_url_parse + ("http://webchat16.wbs.net:6666?private=herbalessences&color=4&volume=0&tagline=&picture=&home_page=hi@there.&ignore=edheldinruth+taz0069+speezman&back=&Room=Hot_Tub&handle=cagou67&mu=893e159ef7fe0ddb022c655cc1c30abd33d4ae6d90d22f8a&last_read_para=&npo=&fsection=input&chatmode=push&reqtype=input&InputText=Sweetie%2C+do+you+have+time+to+go+to+a+private+room..if+not+I%27m+just+going+to+have+to+change+to+normal+mode...let+me+know%3F%3F/"); + + return; +} + +///////////////////////////////////////////////////////////// +// +// test_header_tokenizer() +// +// message_type HTTP_MESSAGE_TYPE_REQUEST or HTTP_MESSAGE_TYPE_RESPONSE +///////////////////////////////////////////////////////////// +void +test_header_tokenizer_run(const char *buf, HttpMessageType_t message_type) +{ + HttpHeaderTokenizer tokenizer; + HttpHeader header; + int bytes_used; + + tokenizer.start(&header, message_type, false); + + tokenizer.run(buf, strlen(buf), true, &bytes_used); + + cout << header << endl; + + return; +} + +void +test_header_tokenizer() +{ + test_header_tokenizer_run + ("GET http://webchat16.wbs.net:6666?private=herbalessences&color=4&volume=0&tagline=&picture=&home_page=hi@there.&ignore=edheldinruth+taz0069+speezman&back=&Room=Hot_Tub&handle=cagou67&mu=893e159ef7fe0ddb022c655cc1c30abd33d4ae6d90d22f8a&last_read_para=&npo=&fsection=input&chatmode=push&reqtype=input&InputText=Sweetie%2C+do+you+have+time+to+go+to+a+private+room..if+not+I%27m+just+going+to+have+to+change+to+normal+mode...let+me+know%3F%3F/ HTTP/1.0\r\n", + HTTP_MESSAGE_TYPE_REQUEST); + + return; +} + +///////////////////////////////////////////////////////////// +// +// TestHttpHeader() +// +///////////////////////////////////////////////////////////// +void +TestHttpHeader() +{ + HttpHeader h; + h.m_message_type = HTTP_MESSAGE_TYPE_REQUEST; + h.m_method = HTTP_METHOD_GET; + h.m_version = HttpVersion(1, 0); + + test_add_fields(&h); + + cout << h << endl; + + cout << "concatenated accept" << endl; + char accept_buf[4000]; + h.m_header_fields.get_comma_separated_accept_value(accept_buf, sizeof(accept_buf)); + cout << accept_buf << endl; + + int l; + cout << "first accept" << endl; + cout << h.m_header_fields.m_accept.get(0, &l) << endl; + + + char buf[4096]; + int marshal_length = h.marshal(buf, sizeof(buf)); + + HttpHeader h1; + h1.unmarshal(buf, marshal_length); + + cout << "unmarshalled: " << endl; + cout << h1 << endl; + + cout << "test url parser:" << endl; + test_url(); + + cout << "test_header_tokenizer:" << endl; + test_header_tokenizer(); + + return; +} diff --git a/lib/ts/TextBuffer.cc b/lib/ts/TextBuffer.cc new file mode 100644 index 00000000..8f088760 --- /dev/null +++ b/lib/ts/TextBuffer.cc @@ -0,0 +1,218 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +#include "libts.h" +#include "TextBuffer.h" + +/**************************************************************************** + * + * TextBuffer.cc - A self-expanding buffer, primarly meant for strings + * + * + * + ****************************************************************************/ + +textBuffer::textBuffer(int size) +{ + bufferStart = NULL; + nextAdd = NULL; + currentSize = spaceLeft = 0; + if (size > 0) { + + // Insitute a minimum size + if (size < 1024) { + size = 1024; + } + + bufferStart = (char *) xmalloc(size); + if (bufferStart != NULL) { + nextAdd = bufferStart; + currentSize = size; + spaceLeft = size - 1; // Leave room for a terminator; + nextAdd[0] = '\0'; + } + } +} + +textBuffer::~textBuffer() +{ + xfree(bufferStart); +} + +// void textBuffer::reUse() +// +// Sets the text buffer for reuse by repositioning the +// ptrs to beginning of buffer. The buffer space is +// reused +void +textBuffer::reUse() +{ + if (bufferStart != NULL) { + nextAdd = bufferStart; + spaceLeft = currentSize - 1; + nextAdd[0] = '\0'; + } +} + +// int textBuffer::copyFrom(void*,int num_bytes) +// +// +// Copy N bytes (determined by num_bytes) on to the +// end of the buffer. +// +// Returns the number of bytes copies or +// -1 if there was insufficient memory +int +textBuffer::copyFrom(const void *source, int num_bytes) +{ + + // Get more space if necessary + if (spaceLeft < num_bytes) { + if (enlargeBuffer(num_bytes) == -1) { + return -1; + } + } + + memcpy(nextAdd, source, num_bytes); + spaceLeft -= num_bytes; + + nextAdd += num_bytes; + nextAdd[0] = '\0'; + + return num_bytes; +} + +// textBuffer::enlargeBuffer(int n) +// +// Enlarge the buffer so at least at N +// bytes are free in the buffer. +// +// Always enlarges by a power of two. +// +// Returns -1 if insufficient memory, +// zero otherwise +int +textBuffer::enlargeBuffer(int N) +{ + int addedSize = currentSize; + int newSize = currentSize * 2; + char *newSpace; + + if (spaceLeft < N) { + + while (addedSize < N) { + addedSize += newSize; + newSize *= 2; + } + + newSpace = (char *) xrealloc(bufferStart, newSize); + if (newSpace != NULL) { + nextAdd = newSpace + (unsigned int) (nextAdd - bufferStart); + bufferStart = newSpace; + spaceLeft += addedSize; + currentSize = newSize; + } else { + // Out of Memory, Sigh + return -1; + } + } + + return 0; +} + +// int textBuffer::rawReadFromFile +// +// - Issues a single read command on the file descriptor or handle +// passed in and reads in raw data (not assumed to be text, no +// string terminators added). +// - Cannot read from file descriptor on win32 because the win32 +// read() function replaces CR-LF with LF if the file is not +// opened in binary mode. +int +textBuffer::rawReadFromFile(int fd) +{ + int readSize; + + // Check to see if we have got a resonable amount of space left in our + // buffer, if not try to get somemore + if (spaceLeft < 4096) { + if (enlargeBuffer(4096) == -1) { + return -1; + } + } + + readSize = read(fd, nextAdd, spaceLeft - 1); + + if (readSize == 0) { //EOF + return 0; + } else if (readSize < 0) { + // Error on read + return readSize; + } else { + nextAdd = nextAdd + readSize; + spaceLeft -= readSize; + return readSize; + } +} + +// int textBuffer::readFromFD(int fd) +// +// Issues a single read command on the file +// descritor passed in. Attempts to read a minimum of +// 512 bytes from file descriptor passed. +int +textBuffer::readFromFD(int fd) +{ + int readSize; + + // Check to see if we have got a resonable amount of space left in our + // buffer, if not try to get somemore + if (spaceLeft < 512) { + if (enlargeBuffer(512) == -1) { + return -1; + } + } + + readSize = read(fd, nextAdd, spaceLeft - 1); + + if (readSize == 0) { + // Socket is empty so we are done + return 0; + } else if (readSize < 0) { + // Error on read + return readSize; + } else { + nextAdd = nextAdd + readSize; + nextAdd[0] = '\0'; + spaceLeft -= readSize + 1; + return readSize; + } +} + +char * +textBuffer::bufPtr() +{ + return bufferStart; +} diff --git a/lib/ts/TextBuffer.h b/lib/ts/TextBuffer.h new file mode 100644 index 00000000..35e729ae --- /dev/null +++ b/lib/ts/TextBuffer.h @@ -0,0 +1,61 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _TEXT_BUFFER +#define _TEXT_BUFFER + +/**************************************************************************** + * + * TextBuffer.h - A self-expanding buffer, primarly meant for strings + * + * + * + ****************************************************************************/ + +#include "ink_platform.h" +#include "ink_apidefs.h" + +class textBuffer +{ +public: + inkcoreapi textBuffer(int size); + inkcoreapi ~ textBuffer(); + int rawReadFromFile(int fd); + int readFromFD(int fd); + inkcoreapi int copyFrom(const void *, int num_bytes); + void reUse(); + inkcoreapi char *bufPtr(); + int spaceUsed() + { + return (int) (nextAdd - bufferStart); + }; +private: + textBuffer(const textBuffer &); + int enlargeBuffer(int N); + int currentSize; + int spaceLeft; + char *bufferStart; + char *nextAdd; +}; + +#endif diff --git a/lib/ts/Tokenizer.cc b/lib/ts/Tokenizer.cc new file mode 100644 index 00000000..f6a442ae --- /dev/null +++ b/lib/ts/Tokenizer.cc @@ -0,0 +1,372 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************/ +#include "ink_platform.h" +#include "ink_unused.h" +#include "Tokenizer.h" +#include "ink_bool.h" +#include "ink_assert.h" +#include "ink_resource.h" + +/**************************************************************************** + * + * Tokenizer.cc - A string tokenzier + * + * + * + ****************************************************************************/ /* MAGIC_EDITING_TAG */ + +Tokenizer::Tokenizer(const char *StrOfDelimiters) +{ + int length; + + if (StrOfDelimiters == NULL) { + strOfDelimit = NULL; + } else { + length = (int) (strlen(StrOfDelimiters) + 1); + strOfDelimit = new char[length]; + memcpy(strOfDelimit, StrOfDelimiters, length); + } + + memset(&start_node, 0, sizeof(tok_node)); + + numValidTokens = 0; + maxTokens = -1; + options = 0; + + add_node = &start_node; + add_index = 0; +} + +Tokenizer::~Tokenizer() +{ + bool root = true; + tok_node *cur = &start_node;; + tok_node *next = NULL; + + if (strOfDelimit != NULL) { + delete[]strOfDelimit; + } + + while (cur != NULL) { + + if (options & COPY_TOKS) { + for (int i = 0; i < TOK_NODE_ELEMENTS; i++) { + if (cur->el[i] != NULL) { + xfree(cur->el[i]); + } + } + } + + next = cur->next; + if (root == false) { + xfree(cur); + } else { + root = false; + } + cur = next; + } +} + +int +Tokenizer::Initialize(const char *str) +{ + return Initialize((char *) str, COPY_TOKS); +} + +inline int +Tokenizer::isDelimiter(char c) +{ + int i = 0; + + while (strOfDelimit[i] != '\0') { + if (c == strOfDelimit[i]) { + return 1; + } + i++; + } + + return 0; +} + +int +Tokenizer::Initialize(char *str, int opt) +{ + char *strStart; + int priorCharWasDelimit = 1; + char *tokStart = NULL; + int tok_count = 0; + bool max_limit_hit = false; + + // We can't depend on ReUse() being called so just do it + // if the object needs it + if (numValidTokens > 0) { + ReUse(); + } + + strStart = str; + + if (!(opt & (COPY_TOKS | SHARE_TOKS))) { + opt = opt | COPY_TOKS; + } + options = opt; + + // Make sure that both options are not set + ink_assert(!((opt & COPY_TOKS) && (opt & SHARE_TOKS))); + + + str = strStart; + priorCharWasDelimit = 1; + + tok_count = 0; + tokStart = str; + + while (*str != '\0') { + + // Check to see if we've run to maxToken limit + if (tok_count + 1 == maxTokens) { + max_limit_hit = true; + break; + } + // There two modes for collecting tokens + // + // Mode 1: Every delimiter creates a token + // even if some of those tokens + // are zero length + // + // Mode2: Every token has some data + // in it which means we + // to skip past repeated delimiters + if (options & ALLOW_EMPTY_TOKS) { + if (isDelimiter(*str)) { + addToken(tokStart, (int) (str - tokStart)); + tok_count++; + tokStart = str + 1; + priorCharWasDelimit = 1; + } else { + priorCharWasDelimit = 0; + } + str++; + } else { + if (isDelimiter(*str)) { + if (priorCharWasDelimit == 0) { + // This is a word end, so add it + addToken(tokStart, (int) (str - tokStart)); + tok_count++; + } + priorCharWasDelimit = 1; + } else { + if (priorCharWasDelimit == 1) { + // This is the start of a new token + tokStart = str; + } + priorCharWasDelimit = 0; + } + str++; + } + } + + // Check to see if we stoped due to a maxToken limit + if (max_limit_hit == true) { + + if (options & ALLOW_EMPTY_TOKS) { + + // Go till either we hit a delimiter or we've + // come to the end of the string, then + // set for copying + for (; *str != '\0' && !isDelimiter(*str); str++); + priorCharWasDelimit = 0; + + } else { + + // First, skip the delimiters + for (; *str != '\0' && isDelimiter(*str); str++); + + // If there are only delimiters remaining, bail and set + // so that we do not add the empty token + if (*str == '\0') { + priorCharWasDelimit = 1; + } else { + // There is stuff to copy for the last token + tokStart = str; + priorCharWasDelimit = 0; + + // Advance until the end of the string + for (; *str != '\0'; str++); + + // Now back off all trailing delimiters + for (; isDelimiter(*(str - 1)); str--); + } + } + } + // Check to see if we got the last token. We will + // only have gotten it if the string ended with a delimiter + if (priorCharWasDelimit == 0) { + // We did not get it + addToken(tokStart, (int) (str - tokStart)); + tok_count++; + } + + numValidTokens = tok_count; + return tok_count; +} + + +void +Tokenizer::addToken(char *startAddr, int length) +{ + char *add_ptr; + if (options & SHARE_TOKS) { + startAddr[length] = '\0'; + add_ptr = startAddr; + } else { + add_ptr = (char *) xmalloc(length + 1); + memcpy(add_ptr, startAddr, length); + add_ptr[length] = '\0'; + } + + add_node->el[add_index] = add_ptr; + + add_index++; + + // Check to see if we are out of elements after + // adding this one. If we are change add_node + // to point to next tok_node, creating one + // if there is not a next one + if (add_index >= TOK_NODE_ELEMENTS) { + if (add_node->next == NULL) { + add_node->next = (tok_node *) xmalloc(sizeof(tok_node)); + memset(add_node->next, 0, sizeof(tok_node)); + } + add_node = add_node->next; + add_index = 0; + } +} + + +const char * +Tokenizer::operator[] (int index) +{ + tok_node * + cur_node = &start_node; + int + cur_start = 0; + if (index >= numValidTokens) { + return NULL; + } else { + while (cur_start + TOK_NODE_ELEMENTS <= index) { + cur_node = cur_node->next; + ink_assert(cur_node != NULL); + cur_start += TOK_NODE_ELEMENTS; + } + return cur_node->el[index % TOK_NODE_ELEMENTS]; + } +} + +int +Tokenizer::getNumber() +{ + return numValidTokens; +} + +const char * +Tokenizer::iterFirst(tok_iter_state * state) +{ + state->node = &start_node; + state->index = -1; + return iterNext(state); +} + +const char * +Tokenizer::iterNext(tok_iter_state * state) +{ + tok_node *node = state->node;; + int index = state->index; + + index++; + if (index >= TOK_NODE_ELEMENTS) { + node = node->next; + if (node == NULL) { + return NULL; + } else { + index = 0; + } + } + + if (node->el[index] != NULL) { + state->node = node; + state->index = index; + return node->el[index]; + } else { + return NULL; + } +} + + + +void +Tokenizer::Print() +{ + tok_node *cur_node = &start_node; + int node_index = 0; + int count = 0; + + while (cur_node != NULL) { + + if (cur_node->el[node_index] != NULL) { + printf("Token %d : |%s|\n", count, cur_node->el[node_index]); + count++; + } else { + return; + } + + node_index++; + if (node_index >= TOK_NODE_ELEMENTS) { + cur_node = cur_node->next; + node_index = 0; + } + } +} + +void +Tokenizer::ReUse() +{ + tok_node *cur_node = &start_node; + + while (cur_node != NULL) { + if (options & COPY_TOKS) { + for (int i = 0; i < TOK_NODE_ELEMENTS; i++) { + if (cur_node->el[i] != NULL) { + xfree(cur_node->el[i]); + } + } + } + memset(cur_node->el, 0, sizeof(char *) * TOK_NODE_ELEMENTS); + cur_node = cur_node->next; + } + + numValidTokens = 0; + add_node = &start_node; + add_index = 0; +} diff --git a/lib/ts/Tokenizer.h b/lib/ts/Tokenizer.h new file mode 100644 index 00000000..fdc99c55 --- /dev/null +++ b/lib/ts/Tokenizer.h @@ -0,0 +1,163 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************/ + +#ifndef _TOKENIZER_H_ +#define _TOKENIZER_H_ + +/**************************************************************************** + * + * Tokenizer.h - A string tokenzier + * + * + * + ****************************************************************************/ + +/********************************************************** + * class Tokenizer + * + * Tokenizes a string, and then allows array like access + * + * The delimiters are determined by the string passed to the + * the constructor. + * + * There are three memory options. + * SHARE_TOKS - this modifies the original string passed in + * through Intialize() and shares its space. NULLs + * are inserted into string after each token. Choosing + * this option means the user is reponsible for not + * deallocating the string storage before deallocating + * the tokenizer object + * COPY_TOKS - this option copies the orginial string and + * leaves the original unchanged. The deallocation of the + * original string and the deallocation of the Tokenizer + * object are now independent. + * Note: If neither SHARE_TOKS or COPY_TOKS is selected, COPY_TOKS + * is the default + * ALLOW_EMPTY_TOKENS: If multiple delimiters appear next to each + * other, each delimiter creates a token someof which + * will be zero length. The default is to skip repeated + * delimiters + * + * Tokenizer(const char* StrOfDelimit) - a string that contains + * the delimiters for tokenizing. This string is copied. + * + * Intialize(char* str, TokenizerOpts opt) - Submits a string + * to be tokenized according to the memory options listed above + * + * ReUse() - Allows the object to be reused for a new string + * After ReUse() is called, Initialize() can be called safely + * again + * + * operator[index] - returns a pointer to the number token given + * by index. If index > numTokens-1, NULL is returned. + * Because of way tokens are stored, this is O(n) operation + * It is very fast though for the first 16 tokens and + * is intended to be used on a small number of tokens + * + * iterFirst(tok_iter_state* state) - Returns the first + * token and intializes state argument for subsequent + * calls to iterNext. If no tokens exist, NULL is + * returned + * + * iterNext(tok_iter_state* state) - Returns the next token after + * what arg state returned next last time. Returns NULL if no + * more tokens exists. + * + * Note: To iterate through a list using operator[] takes O(n^2) time + * Using iterFirst, iterNext the running time is O(n), so use + * the iteration where possible + * + * getNumber() - returns the number of tokens + * + * setMaxTokens() - sets the maximum number of tokens. Once maxTokens + * is reached, delimiters are ignored and the + * last token is rest of the string. Negative numbers + * mean no limit on the number of tokens + * + * getMaxTokens() - returns maxTokens. Negative number mean no limit + * + * Print() - Debugging method to print out the tokens + * + *******************************************************************/ + +#include "ink_apidefs.h" + +#define COPY_TOKS 1 << 0 +#define SHARE_TOKS 1 << 1 +#define ALLOW_EMPTY_TOKS 1 << 2 + +#define TOK_NODE_ELEMENTS 16 +struct tok_node +{ + char *el[TOK_NODE_ELEMENTS]; + tok_node *next; +}; + +struct tok_iter_state +{ + tok_node *node; + int index; +}; + + + +class Tokenizer +{ +public: + inkcoreapi Tokenizer(const char *StrOfDelimiters); + inkcoreapi ~ Tokenizer(); + int Initialize(char *str, int opt); + inkcoreapi int Initialize(const char *str); // Automatically sets option to copy + const char *operator [] (int index); + void setMaxTokens(int max) + { + maxTokens = max; + }; + int getMaxTokens() + { + return maxTokens; + }; + int getNumber(); + void Print(); // Debugging print out + inkcoreapi const char *iterFirst(tok_iter_state * state); + inkcoreapi const char *iterNext(tok_iter_state * state); +private: + Tokenizer & operator=(const Tokenizer &); + Tokenizer(const Tokenizer &); + int isDelimiter(char c); + void addToken(char *startAddr, int length); + void ReUse(); + char *strOfDelimit; + tok_node start_node; + int numValidTokens; + int maxTokens; + int options; + + // State about where to add the next token + tok_node *add_node; + int add_index; +}; + +#endif diff --git a/lib/ts/Vec.cc b/lib/ts/Vec.cc new file mode 100644 index 00000000..a9d24ed7 --- /dev/null +++ b/lib/ts/Vec.cc @@ -0,0 +1,203 @@ +/* -*-Mode: c++;-*- + Various vector related code. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* UnionFind after Tarjan */ + +#include +#include "Vec.h" + +uintptr_t prime2[] = { + 1, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, + 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 2097143, + 4194301, 8388593, 16777213, 33554393, 67108859, 134217689, + 268435399, 536870909 +}; + +// primes generated with map_mult.c +uintptr_t open_hash_primes[256] = { +0x02D4AF27, 0x1865DFC7, 0x47C62B43, 0x35B4889B, 0x210459A1, 0x3CC51CC7, 0x02ADD945, 0x0607C4D7, +0x558E6035, 0x0554224F, 0x5A281657, 0x1C458C7F, 0x7F8BE723, 0x20B9BA99, 0x7218AA35, 0x64B10C2B, +0x548E8983, 0x5951218F, 0x7AADC871, 0x695FA5B1, 0x40D40FCB, 0x20E03CC9, 0x55E9920F, 0x554CE08B, +0x7E78B1D7, 0x7D965DF9, 0x36A520A1, 0x1B0C6C11, 0x33385667, 0x2B0A7B9B, 0x0F35AE23, 0x0BD608FB, +0x2284ADA3, 0x6E6C0687, 0x129B3EED, 0x7E86289D, 0x1143C24B, 0x1B6C7711, 0x1D87BB41, 0x4C7E635D, +0x67577999, 0x0A0113C5, 0x6CF085B5, 0x14A4D0FB, 0x4E93E3A7, 0x5C87672B, 0x67F3CA17, 0x5F944339, +0x4C16DFD7, 0x5310C0E3, 0x2FAD1447, 0x4AFB3187, 0x08468B7F, 0x49E56C51, 0x6280012F, 0x097D1A85, +0x34CC9403, 0x71028BD7, 0x6DEDC7E9, 0x64093291, 0x6D78BB0B, 0x7A03B465, 0x2E044A43, 0x1AE58515, +0x23E495CD, 0x46102A83, 0x51B78A59, 0x051D8181, 0x5352CAC9, 0x57D1312B, 0x2726ED57, 0x2E6BC515, +0x70736281, 0x5938B619, 0x0D4B6ACB, 0x44AB5E2B, 0x0029A485, 0x002CE54F, 0x075B0591, 0x3EACFDA9, +0x0AC03411, 0x53B00F73, 0x2066992D, 0x76E72223, 0x55F62A8D, 0x3FF92EE1, 0x17EE0EB3, 0x5E470AF1, +0x7193EB7F, 0x37A2CCD3, 0x7B44F7AF, 0x0FED8B3F, 0x4CC05805, 0x7352BF79, 0x3B61F755, 0x523CF9A3, +0x1AAFD219, 0x76035415, 0x5BE84287, 0x6D598909, 0x456537E9, 0x407EA83F, 0x23F6FFD5, 0x60256F39, +0x5D8EE59F, 0x35265CEB, 0x1D4AD4EF, 0x676E2E0F, 0x2D47932D, 0x776BB33B, 0x6DE1902B, 0x2C3F8741, +0x5B2DE8EF, 0x686DDB3B, 0x1D7C61C7, 0x1B061633, 0x3229EA51, 0x7FCB0E63, 0x5F22F4C9, 0x517A7199, +0x2A8D7973, 0x10DCD257, 0x41D59B27, 0x2C61CA67, 0x2020174F, 0x71653B01, 0x2FE464DD, 0x3E7ED6C7, +0x164D2A71, 0x5D4F3141, 0x5F7BABA7, 0x50E1C011, 0x140F5D77, 0x34E80809, 0x04AAC6B3, 0x29C42BAB, +0x08F9B6F7, 0x461E62FD, 0x45C2660B, 0x08BF25A7, 0x5494EA7B, 0x0225EBB7, 0x3C5A47CF, 0x2701C333, +0x457ED05B, 0x48CDDE55, 0x14083099, 0x7C69BDAB, 0x7BF163C9, 0x41EE1DAB, 0x258B1307, 0x0FFAD43B, +0x6601D767, 0x214DBEC7, 0x2852CCF5, 0x0009B471, 0x190AC89D, 0x5BDFB907, 0x15D4E331, 0x15D22375, +0x13F388D5, 0x12ACEDA5, 0x3835EA5D, 0x2587CA35, 0x06756643, 0x487C6F55, 0x65C295EB, 0x1029F2E1, +0x10CEF39D, 0x14C2E415, 0x444825BB, 0x24BE0A2F, 0x1D2B7C01, 0x64AE3235, 0x5D2896E5, 0x61BBBD87, +0x4A49E86D, 0x12C277FF, 0x72C81289, 0x5CF42A3D, 0x332FF177, 0x0DAECD23, 0x6000ED1D, 0x203CDDE1, +0x40C62CAD, 0x19B9A855, 0x782020C3, 0x6127D5BB, 0x719889A7, 0x40E4FCCF, 0x2A3C8FF9, 0x07411C7F, +0x3113306B, 0x4D7CA03F, 0x76119841, 0x54CEFBDF, 0x11548AB9, 0x4B0748EB, 0x569966B1, 0x45BC721B, +0x3D5A376B, 0x0D8923E9, 0x6D95514D, 0x0F39A367, 0x2FDAD92F, 0x721F972F, 0x42D0E21D, 0x5C5952DB, +0x7394D007, 0x02692C55, 0x7F92772F, 0x025F8025, 0x34347113, 0x560EA689, 0x0DCC21DF, 0x09ECC7F5, +0x091F3993, 0x0E0B52AB, 0x497CAA55, 0x0A040A49, 0x6D8F0CC5, 0x54F41609, 0x6E0CB8DF, 0x3DCB64C3, +0x16C365CD, 0x6D6B9FB5, 0x02B9382B, 0x6A5BFAF1, 0x1669D75F, 0x13CFD4FD, 0x0FDF316F, 0x21F3C463, +0x6FC58ABF, 0x04E45BE7, 0x1911225B, 0x28CD1355, 0x222084E9, 0x672AD54B, 0x476FC267, 0x6864E16D, +0x20AEF4FB, 0x603C5FB9, 0x55090595, 0x1113B705, 0x24E38493, 0x5291AF97, 0x5F5446D9, 0x13A6F639, +0x3D501313, 0x37E02017, 0x236B0ED3, 0x60F246BF, 0x01E02501, 0x2D2F66BD, 0x6BF23609, 0x16729BAF +}; + +// binary search over intervals +static int +i_find(Intervals *i, int x) { + ink_assert(i->n); + int l = 0, h = i->n; + Lrecurse: + if (h <= l + 2) { + if (h <= l) + return -(l + 1); + if (x < i->v[l] || x > i->v[l + 1]) + return -(l + 1); + return h; + } + int m = (((h - l) / 4) * 2) + l; + if (x > i->v[m + 1]) { + l = m; + goto Lrecurse; + } + if (x < i->v[m]) { + h = m; + goto Lrecurse; + } + return (l + 1); +} + +int +Intervals::in(int x) { + if (!n) + return 0; + if (i_find(this, x) > 0) + return 1; + return 0; +} + +// insert into interval with merge +void +Intervals::insert(int x) { + if (!n) { + add(x); + add(x); + return; + } + int l = i_find(this, x); + if (l > 0) + return; + l = -l - 1; + + if (x > v[l + 1]) { + if (x == v[l + 1] + 1) { + v[l + 1]++; + goto Lmerge; + } + l += 2; + if (l < n) { + if (x == v[l] - 1) { + v[l]--; + goto Lmerge; + } + } + goto Lmore; + } else { + ink_assert(x < v[l]); + if (x == v[l] - 1) { + v[l]--; + goto Lmerge; + } + if (!l) + goto Lmore; + l -= 2; + if (x == v[l + 1] + 1) { + v[l + 1]++; + goto Lmerge; + } + } + Lmore: + fill(n + 2); + if (n - 2 - l > 0) + memmove(v + l + 2, v + l, sizeof(int) * (n - 2 - l)); + v[l] = x; + v[l+1] = x; + return; + Lmerge: + if (l) { + if (v[l] - v[l-1] < 2) { + l -= 2; + goto Ldomerge; + } + } + if (l < n - 2) { + if (v[l + 2] - v[l + 1] < 2) + goto Ldomerge; + } + return; + Ldomerge: + memmove(v + l + 1, v + l + 3, sizeof(int) * (n - 3 - l)); + n -= 2; + goto Lmerge; +} + +void +UnionFind::size(int s) { + int nn = n; + fill(s); + for (int i = nn; i < n; i++) + v[i] = -1; +} + +int +UnionFind::find(int n) { + int i, t; + for (i = n; v[i] >= 0; i = v[i]); + while (v[n] >= 0) { + t = n; + n = v[n]; + v[t] = i; + } + return i; +} + +void +UnionFind::unify(int n, int m) { + n = find(n); + m = find(m); + if (n != m) { + if (v[m] < v[n]) { + v[m] += (v[n] - 1); + v[n] = m; + } else { + v[n] += (v[m] - 1); + v[m] = n; + } + } +} diff --git a/lib/ts/Vec.h b/lib/ts/Vec.h new file mode 100644 index 00000000..879fe174 --- /dev/null +++ b/lib/ts/Vec.h @@ -0,0 +1,816 @@ +/** @file + + Vector and Set templates with qsort. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _vec_H_ +#define _vec_H_ + +#include +#include +#include +#include +#include "defalloc.h" +#include "ink_assert.h" + +// Simple Vector class, also supports open hashed sets + +#define VEC_INTEGRAL_SHIFT_DEFAULT 2 /* power of 2 (1 << VEC_INTEGRAL_SHIFT)*/ +#define VEC_INTEGRAL_SIZE (1 << (S)) +#define VEC_INITIAL_SHIFT ((S)+1) +#define VEC_INITIAL_SIZE (1 << VEC_INITIAL_SHIFT) + +#define SET_LINEAR_SIZE 4 /* must be <= than VEC_INTEGRAL_SIZE */ +#define SET_INITIAL_INDEX 2 + +template // S must be a power of 2 +class Vec { + public: + int n; + int i; // size index for sets, reserve for vectors + C *v; + C e[VEC_INTEGRAL_SIZE]; + + Vec(); + Vec(const Vec &vv); + Vec(const C c); + ~Vec(); + + C &operator[](int i) const { return v[i]; } + + C get(int i); + void add(C a); + void push_back(C a) { add(a); } // std::vector name + int add_exclusive(C a); + C& add(); + C pop(); + void reset(); + void clear(); + void free(); + void free_and_clear(); + void delete_and_clear(); + void set_clear(); + C *set_add(C a); + void set_remove(C a); // expensive, use BlockHash for cheaper remove + C *set_add_internal(C a); + int set_union(Vec &v); + int set_intersection(Vec &v); + int some_intersection(Vec &v); + int some_disjunction(Vec &v); + int some_difference(Vec &v); + void set_intersection(Vec &v, Vec &result); + void set_disjunction(Vec &v, Vec &result); + void set_difference(Vec &v, Vec &result); + int set_count(); + int count(); + C *in(C a); + C *set_in(C a); + C first_in_set(); + C *set_in_internal(C a); + void set_expand(); + int index(C a); + void set_to_vec(); + void vec_to_set(); + void move(Vec &v); + void copy(const Vec &v); + void fill(int n); + void append(const Vec &v); + void prepend(const Vec &v); + void remove_index(int index); + void remove(C a) { int i = index(a); if (i>=0) remove_index(i); } + C& insert(int index); + void insert(int index, Vec &vv); + void insert(int index, C a); + void push(C a) { insert(0, a); } + void reverse(); + void reserve(int n); + C* end() const { return v + n; } + C &first() const { return v[0]; } + C &last() const { return v[n-1]; } + Vec& operator=(Vec &v) { this->copy(v); return *this; } + int length () const { return n; } + // vector::size() intentionally not implemented because it should mean "bytes" not count of elements + int write(int fd); + int read(int fd); + void qsort(bool (*lt)(C,C)); + + // private: + void move_internal(Vec &v); + void copy_internal(const Vec &v); + void add_internal(C a); + C& add_internal(); + void addx(); +}; + +// c -- class, p -- pointer to elements of v, v -- vector +#define forv_Vec(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = (_v).v[0]; \ + ((intptr_t)(qq__##_p) < (_v).length()) && ((_p = (_v).v[(intptr_t)qq__##_p]) || 1); qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1)) +#define for_Vec(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, _p = (_v).v[0]; \ + ((intptr_t)(qq__##_p) < (_v).length()) && ((_p = (_v).v[(intptr_t)qq__##_p]) || 1); qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1)) +#define forvp_Vec(_c, _p, _v) if ((_v).n) for (_c *qq__##_p = (_c*)0, *_p = &(_v).v[0]; \ + ((intptr_t)(qq__##_p) < (_v).length()) && ((_p = &(_v).v[(intptr_t)qq__##_p]) || 1); qq__##_p = (_c*)(((intptr_t)qq__##_p) + 1)) + +template class Accum { public: + Vec asset; + Vec asvec; + void add(C c) { if (asset.set_add(c)) asvec.add(c); } + void add(Vec v) { for (int i = 0; i < v.n; i++) if (v.v[i]) add(v.v[i]); } + void clear() { asset.clear(); asvec.clear(); } +}; + +// Intervals store sets in interval format (e.g. [1..10][12..12]). +// Inclusion test is by binary search on intervals. +// Deletion is not supported +class Intervals : public Vec { + public: + void insert(int n); + int in(int n); +}; + +// UnionFind supports fast unify and finding of +// 'representitive elements'. +// Elements are numbered from 0 to N-1. +class UnionFind : public Vec { + public: + // set number of elements, initialized to singletons, may be called repeatedly to increase size + void size(int n); + // return representitive element + int find(int n); + // unify the sets containing the two elements + void unify(int n, int m); +}; + +extern uintptr_t prime2[]; +extern uintptr_t open_hash_primes[256]; + +/* IMPLEMENTATION */ + +template inline +Vec::Vec() : n(0), i(0), v(0) { + memset(&e[0], 0, sizeof(e)); +} + +template inline +Vec::Vec(const Vec &vv) { + copy(vv); +} + +template inline +Vec::Vec(C c) { + n = 1; + i = 0; + v = &e[0]; + e[0] = c; +} + +template inline C +Vec::get(int i) { + if (i < n && i >= 0) + return v[i]; + else + return 0; +} + +template inline void +Vec::add(C a) { + if (n & (VEC_INTEGRAL_SIZE-1)) + v[n++] = a; + else if (!v) + (v = e)[n++] = a; + else + add_internal(a); +} + +template inline C& +Vec::add() { + C *ret; + if (n & (VEC_INTEGRAL_SIZE-1)) + ret = &v[n++]; + else if (!v) + ret = &(v = e)[n++]; + else + ret = &add_internal(); + return *ret; +} + +template inline C +Vec::pop() { + if (!n) + return 0; + n--; + C ret = v[n]; + if (!n) + clear(); + return ret; +} + +template inline void +Vec::set_clear() { + memset(v, 0, n * sizeof(C)); +} + +template inline C * +Vec::set_add(C a) { + if (n < SET_LINEAR_SIZE) { + for (C *c = v; c < v + n; c++) + if (*c == a) + return 0; + add(a); + return &v[n-1]; + } + if (n == SET_LINEAR_SIZE) { + Vec vv(*this); + clear(); + for (C *c = vv.v; c < vv.v + vv.n; c++) + set_add_internal(*c); + } + return set_add_internal(a); +} + +template void +Vec::set_remove(C a) { + Vec tmp; + tmp.move(*this); + for (C *c = tmp.v; c < tmp.v + tmp.n; c++) + if (*c != a) + set_add(a); +} + +template inline int +Vec::count() { + int x = 0; + for (C *c = v; c < v + n; c++) + if (*c) + x++; + return x; +} + +template inline C* +Vec::in(C a) { + for (C *c = v; c < v + n; c++) + if (*c == a) + return c; + return NULL; +} + +template inline int +Vec::add_exclusive(C a) { + if (!in(a)) { + add(a); + return 1; + } else + return 0; +} + +template inline C * +Vec::set_in(C a) { + if (n <= SET_LINEAR_SIZE) + return in(a); + return set_in_internal(a); +} + +template inline C +Vec::first_in_set() { + for (C *c = v; c < v + n; c++) + if (*c) + return *c; + return 0; +} + +template inline int +Vec::index(C a) { + for (C *c = v; c < v + n; c++) + if (*c == a) + return c - v; + return -1; +} + +template inline void +Vec::move_internal(Vec &vv) { + n = vv.n; + i = vv.i; + if (vv.v == &vv.e[0]) { + memcpy(e, &vv.e[0], sizeof(e)); + v = e; + } else + v = vv.v; +} + +template inline void +Vec::move(Vec &vv) { + move_internal(vv); + vv.v = 0; + vv.clear(); +} + +template inline void +Vec::copy(const Vec &vv) { + n = vv.n; + i = vv.i; + if (vv.v == &vv.e[0]) { + memcpy(e, &vv.e[0], sizeof(e)); + v = e; + } else { + if (vv.v) + copy_internal(vv); + else + v = 0; + } +} + +template inline void +Vec::fill(int nn) { + for (int i = n; i < nn; i++) + add() = 0; +} + +template inline void +Vec::append(const Vec &vv) { + for (C *c = vv.v; c < vv.v + vv.n; c++) + if (*c != 0) + add(*c); +} + +template inline void +Vec::prepend(const Vec &vv) { + if (vv.n) { + int oldn = n; + fill(n + vv.n); + if (oldn) + memmove(&v[vv.n], &v[0], oldn * sizeof(v[0])); + memcpy(&v[0], vv.v, vv.n * sizeof(v[0])); + } +} + +template void +Vec::add_internal(C a) { + addx(); + v[n++] = a; +} + +template C& +Vec::add_internal() { + addx(); + return v[n++]; +} + +template C * +Vec::set_add_internal(C c) { + int j, k; + if (n) { + uintptr_t h = (uintptr_t)c; + h = h % n; + for (k = h, j = 0; j < i + 3; j++) { + if (!v[k]) { + v[k] = c; + return &v[k]; + } else if (v[k] == c) + return 0; + k = (k + open_hash_primes[j]) % n; + } + } + Vec vv; + vv.move_internal(*this); + set_expand(); + if (vv.v) + set_union(vv); + return set_add(c); +} + +template C * +Vec::set_in_internal(C c) { + int j, k; + if (n) { + uintptr_t h = (uintptr_t)c; + h = h % n; + for (k = h, j = 0; j < i + 3; j++) { + if (!v[k]) + return 0; + else if (v[k] == c) + return &v[k]; + k = (k + open_hash_primes[j]) % n; + } + } + return 0; +} + +template int +Vec::set_union(Vec &vv) { + int changed = 0; + for (int i = 0; i < vv.n; i++) + if (vv.v[i]) + changed = set_add(vv.v[i]) || changed; + return changed; +} + +template int +Vec::set_intersection(Vec &vv) { + Vec tv; + tv.move(*this); + int changed = 0; + for (int i = 0; i < tv.n; i++) + if (tv.v[i]) { + if (vv.set_in(tv.v[i])) + set_add(tv.v[i]); + else + changed = 1; + } + return changed; +} + +template int +Vec::some_intersection(Vec &vv) { + for (int i = 0; i < n; i++) + if (v[i]) + if (vv.set_in(v[i])) + return 1; + return 0; +} + +template int +Vec::some_disjunction(Vec &vv) { + for (int i = 0; i < n; i++) + if (v[i]) + if (!vv.set_in(v[i])) + return 1; + for (int i = 0; i < vv.n; i++) + if (vv.v[i]) + if (!set_in(vv.v[i])) + return 1; + return 0; +} + +template void +Vec::set_intersection(Vec &vv, Vec &result) { + for (int i = 0; i < n; i++) + if (v[i]) + if (vv.set_in(v[i])) + result.set_add(v[i]); +} + +template void +Vec::set_disjunction(Vec &vv, Vec &result) { + for (int i = 0; i < n; i++) + if (v[i]) + if (!vv.set_in(v[i])) + result.set_add(v[i]); + for (int i = 0; i < vv.n; i++) + if (vv.v[i]) + if (!set_in(vv.v[i])) + result.set_add(vv.v[i]); +} + +template void +Vec::set_difference(Vec &vv, Vec &result) { + for (int i = 0; i < n; i++) + if (v[i]) + if (!vv.set_in(v[i])) + result.set_add(v[i]); +} + +template int +Vec::some_difference(Vec &vv) { + for (int i = 0; i < n; i++) + if (v[i]) + if (!vv.set_in(v[i])) + return 1; + return 0; +} + +template int +Vec::set_count() { + int x = 0; + for (int i = 0; i < n; i++) + if (v[i]) + x++; + return x; +} + +template void +Vec::set_to_vec() { + C *x = &v[0], *y = x; + for (; y < v + n; y++) { + if (*y) { + if (x != y) + *x = *y; + x++; + } + } + if (i) { + i = prime2[i]; // convert set allocation to reserve + if (i - n > 0) + memset(&v[n], 0, (i - n) * (sizeof(C))); + } else { + i = 0; + if (v == &e[0] && VEC_INTEGRAL_SIZE - n > 0) + memset(&v[n], 0, (VEC_INTEGRAL_SIZE - n) * (sizeof(C))); + } +} + +template void +Vec::vec_to_set() { + Vec vv; + vv.move(*this); + for (C *c = vv.v; c < vv.v + vv.n; c++) + set_add(*c); +} + +template void +Vec::remove_index(int index) { + if (n > 1) + memmove(&v[index], &v[index+1], (n - 1 - index) * sizeof(v[0])); + n--; + if (n <= 0) + v = e; +} + +template void +Vec::insert(int index, C a) { + add(); + memmove(&v[index+1], &v[index], (n - index - 1) * sizeof(C)); + v[index] = a; +} + +template void +Vec::insert(int index, Vec &vv) { + fill(n + vv.n); + memmove(&v[index+vv.n], &v[index], (n - index - 1) * sizeof(C)); + for (int x = 0; x < vv.n; x++) + v[index + x] = vv[x]; +} + +template C & +Vec::insert(int index) { + add(); + memmove(&v[index+1], &v[index], (n - index - 1) * sizeof(C)); + memset(&v[index], 0, sizeof(C)); + return v[index]; +} + +template void +Vec::reverse() { + for (int i = 0; i < n/2; i++) { + C *s = &v[i], *e = &v[n - 1 - i]; + C t; + memcpy(&t, s, sizeof(t)); + memcpy(s, e, sizeof(t)); + memcpy(e, &t, sizeof(t)); + } +} + +template void +Vec::copy_internal(const Vec &vv) { + int l = n, nl = (1 + VEC_INITIAL_SHIFT); + l = l >> VEC_INITIAL_SHIFT; + while (l) { l = l >> 1; nl++; } + nl = 1 << nl; + v = (C*)A::alloc(nl * sizeof(C)); + memcpy(v, vv.v, n * sizeof(C)); + memset(v + n, 0, (nl - n) * sizeof(C)); + if (i > n) // reset reserve + i = 0; +} + +template void +Vec::set_expand() { + if (!n) + i = SET_INITIAL_INDEX; + else + i = i + 1; + n = prime2[i]; + v = (C*)A::alloc(n * sizeof(C)); + memset(v, 0, n * sizeof(C)); +} + +template inline void +Vec::reserve(int x) { + if (x <= n) + return; + int xx = 1 << VEC_INITIAL_SHIFT; + while (xx < x) xx *= 2; + i = xx; + void *vv = (void*)v; + v = (C*)A::alloc(i * sizeof(C)); + if (vv && n) + memcpy(v, vv, n * sizeof(C)); + memset(&v[n], 0, (i-n) * sizeof(C)); + if (vv && vv != e) + A::free(vv); +} + +template inline void +Vec::addx() { + if (!v) { + v = e; + return; + } + if (v == e) { + v = (C*)A::alloc(VEC_INITIAL_SIZE * sizeof(C)); + memcpy(v, &e[0], n * sizeof(C)); + ink_assert(n < VEC_INITIAL_SIZE); + memset(&v[n], 0, (VEC_INITIAL_SIZE - n) * sizeof(C)); + } else { + if ((n & (n-1)) == 0) { + int nl = n * 2; + if (nl <= i) + return; + else + i = 0; + void *vv = (void*)v; + v = (C*)A::alloc(nl * sizeof(C)); + memcpy(v, vv, n * sizeof(C)); + memset(&v[n], 0, n * sizeof(C)); + A::free(vv); + } + } +} + +template inline void +Vec::free() { + if (v && v != e) A::free(v); +} + +template inline void +Vec::reset() { + v = NULL; + n = 0; + i = 0; +} + +template inline void +Vec::clear() { + if (v && v != e) A::free(v); + reset(); +} + +template inline void +Vec::free_and_clear() { + for (int x = 0; x < n; x++) + if (v[x]) + A::free(v[x]); + clear(); +} + +template inline void +Vec::delete_and_clear() { + for (int x = 0; x < n; x++) + if (v[x]) + delete v[x]; + clear(); +} + +template +inline Vec::~Vec() { + if (v && v != e) A::free(v); +} + +template +inline int marshal_size(Vec &v) { + int l = sizeof(int) * 2; + for (int x = 0; x < v.n; x++) + l += ::marshal_size(v.v[x]); + return l; +} + +template +inline int marshal(Vec &v, char *buf) { + char *x = buf; + *(int*)x = v.n; x += sizeof(int); + *(int*)x = v.i; x += sizeof(int); + for (int i = 0; i < v.n; i++) + x += ::marshal(v.v[i], x); + return x - buf; +} + +template +inline int unmarshal(Vec &v, char *buf) { + char *x = buf; + v.n = *(int*)x; x += sizeof(int); + v.i = *(int*)x; x += sizeof(int); + if (v.n) { + v.v = (C*)A::alloc(sizeof(C) * v.n); + memset(v.v, 0, sizeof(C) * v.n); + } else + v.v = v.e; + for (int i = 0; i < v.n; i++) + x += ::unmarshal(v.v[i], x); + return x - buf; +} + +template +inline int Vec::write(int fd) { + int r = 0, t = 0; + if ((r = ::write(fd, this, sizeof(*this))) < 0) return r; t += r; + if ((r = ::write(fd, v, n * sizeof(C))) < 0) return r; t += r; + return t; +} + +template +inline int Vec::read(int fd) { + int r = 0, t = 0; + if ((r = ::read(fd, this, sizeof(*this))) < 0) return r; t += r; + v = (C*)A::alloc(sizeof(C) * n); + memset(v, 0, sizeof(C) * n); + if ((r = ::read(fd, v, n * sizeof(C))) < 0) return r; t += r; + return t; +} + +template +inline void qsort_Vec(C *left, C *right, bool (*lt)(C,C)) { + Lagain: + if (right - left < 5) { + for (C *y = right - 1; y > left; y--) { + for (C *x = left; x < y; x++) { + if (lt(x[1],x[0])) { + C t = x[0]; + x[0] = x[1]; + x[1] = t; + } + } + } + } else { + C *i = left + 1, *j = right - 1; + C x = *left; + for (;;) { + while (lt(x,*j)) j--; + while (i < j && lt(*i,x)) i++; + if (i >= j) break; + C t = *i; + *i = *j; + *j = t; + i++; j--; + } + if (j == right - 1) { + *left = *(right - 1); + *(right - 1) = x; + right--; + goto Lagain; + } + if (left < j) qsort_Vec(left, j + 1, lt); + if (j + 2 < right) qsort_Vec(j + 1, right, lt); + } +} + +template +inline void qsort_VecRef(C *left, C *right, bool (*lt)(C&,C&)) { + Lagain: + if (right - left < 5) { + for (C *y = right - 1; y > left; y--) { + for (C *x = left; x < y; x++) { + if (lt(x[1],x[0])) { + C t = x[0]; + x[0] = x[1]; + x[1] = t; + } + } + } + } else { + C *i = left + 1, *j = right - 1; + C x = *left; + for (;;) { + while (lt(x,*j)) j--; + while (i < j && lt(*i,x)) i++; + if (i >= j) break; + C t = *i; + *i = *j; + *j = t; + i++; j--; + } + if (j == right - 1) { + *left = *(right - 1); + *(right - 1) = x; + right--; + goto Lagain; + } + if (left < j) qsort_VecRef(left, j + 1, lt); + if (j + 2 < right) qsort_VecRef(j + 1, right, lt); + } +} + +template +inline void Vec::qsort(bool (*lt)(C,C)) { + if (n) + qsort_Vec(&v[0], end(), lt); +} + +void test_vec(); + +#endif diff --git a/lib/ts/Version.cc b/lib/ts/Version.cc new file mode 100644 index 00000000..6f6015f4 --- /dev/null +++ b/lib/ts/Version.cc @@ -0,0 +1,110 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +#include "libts.h" + +AppVersionInfo::AppVersionInfo() +{ + defined = 0; + ink_strncpy(PkgStr, "?", sizeof(PkgStr)); + ink_strncpy(AppStr, "?", sizeof(AppStr)); + ink_strncpy(VersionStr, "?", sizeof(VersionStr)); + ink_strncpy(BldNumStr, "?", sizeof(BldNumStr)); + ink_strncpy(BldTimeStr, "?", sizeof(BldTimeStr)); + ink_strncpy(BldDateStr, "?", sizeof(BldDateStr)); + ink_strncpy(BldMachineStr, "?", sizeof(BldMachineStr)); + ink_strncpy(BldPersonStr, "?", sizeof(BldPersonStr)); + ink_strncpy(BldCompileFlagsStr, "?", sizeof(BldCompileFlagsStr)); + ink_strncpy(FullVersionInfoStr, "?", sizeof(FullVersionInfoStr)); + // coverity[uninit_member] +} + + +void +AppVersionInfo::setup(const char *pkg_name, const char *app_name, const char *app_version, + const char *build_date, const char *build_time, const char *build_machine, + const char *build_person, const char *build_cflags) +{ + char month_name[8]; + int year, month, day, hour, minute, second; + + static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" + }; + + // coverity[secure_coding] + sscanf(build_time, "%d:%d:%d", &hour, &minute, &second); + // coverity[secure_coding] + sscanf(build_date, "%3s %d %d", month_name, &day, &year); + + for (month = 0; month < 11; month++) { + if (strcasecmp(months[month], month_name) == 0) + break; + } + + /////////////////////////////////////////// + // now construct the version information // + /////////////////////////////////////////// + ink_strncpy(PkgStr, pkg_name, sizeof(PkgStr)); + ink_strncpy(AppStr, app_name, sizeof(AppStr)); + snprintf(VersionStr, sizeof(VersionStr), "%s", app_version); + snprintf(BldNumStr, sizeof(BldNumStr), "%d%d%d", month, day, hour); + snprintf(BldTimeStr, sizeof(BldTimeStr), "%s", build_time); + snprintf(BldDateStr, sizeof(BldDateStr), "%s", build_date); + snprintf(BldMachineStr, sizeof(BldMachineStr), "%s", build_machine); + snprintf(BldPersonStr, sizeof(BldPersonStr), "%s", build_person); + snprintf(BldCompileFlagsStr, sizeof(BldCompileFlagsStr), "%s", build_cflags); + + snprintf(FullVersionInfoStr, sizeof(FullVersionInfoStr), + "%s - %s - %s - (build # %d%d%d on %s at %s)", + PkgStr, AppStr, VersionStr, month, day, hour, build_date, build_time); + + ///////////////////////////////////////////////////////////// + // the manager doesn't like empty strings, so prevent them // + ///////////////////////////////////////////////////////////// + if (PkgStr[0] == '\0') + ink_strncpy(PkgStr, "?", sizeof(PkgStr)); + if (AppStr[0] == '\0') + ink_strncpy(AppStr, "?", sizeof(AppStr)); + if (VersionStr[0] == '\0') + ink_strncpy(VersionStr, "?", sizeof(VersionStr)); + if (BldNumStr[0] == '\0') + ink_strncpy(BldNumStr, "?", sizeof(BldNumStr)); + if (BldTimeStr[0] == '\0') + ink_strncpy(BldTimeStr, "?", sizeof(BldTimeStr)); + if (BldDateStr[0] == '\0') + ink_strncpy(BldDateStr, "?", sizeof(BldDateStr)); + if (BldMachineStr[0] == '\0') + ink_strncpy(BldMachineStr, "?", sizeof(BldMachineStr)); + if (BldPersonStr[0] == '\0') + ink_strncpy(BldPersonStr, "?", sizeof(BldPersonStr)); + if (BldCompileFlagsStr[0] == '\0') + ink_strncpy(BldCompileFlagsStr, "?", sizeof(BldCompileFlagsStr)); + if (FullVersionInfoStr[0] == '\0') + ink_strncpy(FullVersionInfoStr, "?", sizeof(FullVersionInfoStr)); + + defined = 1; +} diff --git a/lib/ts/defalloc.h b/lib/ts/defalloc.h new file mode 100644 index 00000000..687a1e68 --- /dev/null +++ b/lib/ts/defalloc.h @@ -0,0 +1,32 @@ +/** @file + + Default allocator: malloc/free + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +#ifndef _defalloc_H_ +#define _defalloc_H_ + +class DefaultAlloc { public: + static void *alloc(int s) { return ::malloc(s); } + static void free(void *p) { ::free(p); } +}; + +#endif + diff --git a/lib/ts/fastlz.c b/lib/ts/fastlz.c new file mode 100644 index 00000000..dabbdcbb --- /dev/null +++ b/lib/ts/fastlz.c @@ -0,0 +1,551 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) + +/* + * Always check for bound when decompressing. + * Generally it is best to leave it defined. + */ +#define FASTLZ_SAFE + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) +#else +#define FASTLZ_EXPECT_CONDITIONAL(c) (c) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) +#endif + +/* + * Use inlined functions for supported systems. + */ +#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) +#define FASTLZ_INLINE inline +#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) +#define FASTLZ_INLINE __inline +#else +#define FASTLZ_INLINE +#endif + +/* + * Prevent accessing more than 8-bit at once, except on x86 architectures. + */ +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_STRICT_ALIGN +#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(_M_IX86) /* Intel, MSVC */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__386) +#undef FASTLZ_STRICT_ALIGN +#elif defined(_X86_) /* MinGW */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__I86__) /* Digital Mars */ +#undef FASTLZ_STRICT_ALIGN +#endif +#endif + +/* + * FIXME: use preprocessor magic to set this on different platforms! + */ +typedef unsigned char flzuint8; +typedef unsigned short flzuint16; +typedef unsigned int flzuint32; + +/* prototypes */ +int fastlz_compress(const void* input, int length, void* output); +int fastlz_compress_level(int level, const void* input, int length, void* output); +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +#define MAX_COPY 32 +#define MAX_LEN 264 /* 256 + 8 */ +#define MAX_DISTANCE 8192 + +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_READU16(p) *((const flzuint16*)(p)) +#else +#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) +#endif + +#define HASH_LOG 13 +#define HASH_SIZE (1<< HASH_LOG) +#define HASH_MASK (HASH_SIZE-1) +#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 1 + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz1_compress +#define FASTLZ_DECOMPRESSOR fastlz1_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 2 + +#undef MAX_DISTANCE +#define MAX_DISTANCE 8191 +#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz2_compress +#define FASTLZ_DECOMPRESSOR fastlz2_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +int fastlz_compress(const void* input, int length, void* output) +{ + /* for short block, choose fastlz1 */ + if(length < 65536) + return fastlz1_compress(input, length, output); + + /* else... */ + return fastlz2_compress(input, length, output); +} + +int fastlz_decompress(const void* input, int length, void* output, int maxout) +{ + /* magic identifier for compression level */ + int level = ((*(const flzuint8*)input) >> 5) + 1; + + if(level == 1) + return fastlz1_decompress(input, length, output, maxout); + if(level == 2) + return fastlz2_decompress(input, length, output, maxout); + + /* unknown level, trigger error */ + return 0; +} + +int fastlz_compress_level(int level, const void* input, int length, void* output) +{ + if(level == 1) + return fastlz1_compress(input, length, output); + if(level == 2) + return fastlz2_compress(input, length, output); + + return 0; +} + +#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ + +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_bound = ip + length - 2; + const flzuint8* ip_limit = ip + length - 12; + flzuint8* op = (flzuint8*) output; + + const flzuint8* htab[HASH_SIZE]; + const flzuint8** hslot; + flzuint32 hval; + + flzuint32 copy; + + /* sanity check */ + if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) + { + if(length) + { + /* create literal copy only */ + *op++ = length-1; + ip_bound++; + while(ip <= ip_bound) + *op++ = *ip++; + return length+1; + } + else + return 0; + } + + /* initializes hash table */ + for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) + *hslot = ip; + + /* we start with literal copy */ + copy = 2; + *op++ = MAX_COPY-1; + *op++ = *ip++; + *op++ = *ip++; + + /* main loop */ + while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + { + const flzuint8* ref; + flzuint32 distance; + + /* minimum match length */ + flzuint32 len = 3; + + /* comparison starting-point */ + const flzuint8* anchor = ip; + + /* check for a run */ +#if FASTLZ_LEVEL==2 + if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) + { + distance = 1; + ip += 3; + ref = anchor - 1 + 3; + goto match; + } +#endif + + /* find potential match */ + HASH_FUNCTION(hval,ip); + hslot = htab + hval; + ref = htab[hval]; + + /* calculate distance to the match */ + distance = anchor - ref; + + /* update hash table */ + *hslot = anchor; + + /* is this a match? check the first 3 bytes */ + if(distance==0 || +#if FASTLZ_LEVEL==1 + (distance >= MAX_DISTANCE) || +#else + (distance >= MAX_FARDISTANCE) || +#endif + *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) + goto literal; + +#if FASTLZ_LEVEL==2 + /* far, needs at least 5-byte match */ + if(distance >= MAX_DISTANCE) + { + if(*ip++ != *ref++ || *ip++!= *ref++) + goto literal; + len += 2; + } + + match: +#endif + + /* last matched byte */ + ip = anchor + len; + + /* distance is biased */ + distance--; + + if(!distance) + { + /* zero distance means a run */ + flzuint8 x = ip[-1]; + while(ip < ip_bound) + if(*ref++ != x) break; else ip++; + } + else + for(;;) + { + /* safe because the outer check against ip limit */ + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + while(ip < ip_bound) + if(*ref++ != *ip++) break; + break; + } + + /* if we have copied something, adjust the copy count */ + if(copy) + /* copy is biased, '0' means 1 byte copy */ + *(op-copy-1) = copy-1; + else + /* back, to overwrite the copy count */ + op--; + + /* reset literal counter */ + copy = 0; + + /* length is biased, '1' means a match of 3 bytes */ + ip -= 3; + len = ip - anchor; + + /* encode the match */ +#if FASTLZ_LEVEL==2 + if(distance < MAX_DISTANCE) + { + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = (distance & 255); + } + } + else + { + /* far away, but not yet in the another galaxy... */ + if(len < 7) + { + distance -= MAX_DISTANCE; + *op++ = (len << 5) + 31; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + else + { + distance -= MAX_DISTANCE; + *op++ = (7 << 5) + 31; + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + } +#else + + if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) + while(len > MAX_LEN-2) + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = MAX_LEN - 2 - 7 -2; + *op++ = (distance & 255); + len -= MAX_LEN-2; + } + + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = len - 7; + *op++ = (distance & 255); + } +#endif + + /* update the hash at match boundary */ + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + + /* assuming literal copy */ + *op++ = MAX_COPY-1; + + continue; + + literal: + *op++ = *anchor++; + ip = anchor; + copy++; + if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* left-over as literal copy */ + ip_bound++; + while(ip <= ip_bound) + { + *op++ = *ip++; + copy++; + if(copy == MAX_COPY) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* if we have copied something, adjust the copy length */ + if(copy) + *(op-copy-1) = copy-1; + else + op--; + +#if FASTLZ_LEVEL==2 + /* marker for fastlz2 */ + *(flzuint8*)output |= (1 << 5); +#endif + + return op - (flzuint8*)output; +} + +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_limit = ip + length; + flzuint8* op = (flzuint8*) output; + flzuint8* op_limit = op + maxout; + flzuint32 ctrl = (*ip++) & 31; + int loop = 1; + + do + { + const flzuint8* ref = op; + flzuint32 len = ctrl >> 5; + flzuint32 ofs = (ctrl & 31) << 8; + + if(ctrl >= 32) + { +#if FASTLZ_LEVEL==2 + flzuint8 code; +#endif + len--; + ref -= ofs; + if (len == 7-1) +#if FASTLZ_LEVEL==1 + len += *ip++; + ref -= *ip++; +#else + do + { + code = *ip++; + len += code; + } while (code==255); + code = *ip++; + ref -= code; + + /* match from 16-bit distance */ + if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) + if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) + { + ofs = (*ip++) << 8; + ofs += *ip++; + ref = op - ofs - MAX_DISTANCE; + } +#endif + +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) + return 0; + + if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) + return 0; +#endif + + if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + ctrl = *ip++; + else + loop = 0; + + if(ref == op) + { + /* optimize copy for a run */ + flzuint8 b = ref[-1]; + *op++ = b; + *op++ = b; + *op++ = b; + for(; len; --len) + *op++ = b; + } + else + { +#if !defined(FASTLZ_STRICT_ALIGN) + const flzuint16* p; + flzuint16* q; +#endif + /* copy from reference */ + ref--; + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + +#if !defined(FASTLZ_STRICT_ALIGN) + /* copy a byte, so that now it's word aligned */ + if(len & 1) + { + *op++ = *ref++; + len--; + } + + /* copy 16-bit at once */ + q = (flzuint16*) op; + op += len; + p = (const flzuint16*) ref; + for(len>>=1; len > 4; len-=4) + { + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + } + for(; len; --len) + *q++ = *p++; +#else + for(; len; --len) + *op++ = *ref++; +#endif + } + } + else + { + ctrl++; +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) + return 0; + if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) + return 0; +#endif + + *op++ = *ip++; + for(--ctrl; ctrl; ctrl--) + *op++ = *ip++; + + loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); + if(loop) + ctrl = *ip++; + } + } + while(FASTLZ_EXPECT_CONDITIONAL(loop)); + + return op - (flzuint8*)output; +} + +#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/lib/ts/fastlz.h b/lib/ts/fastlz.h new file mode 100644 index 00000000..e5ca8dfc --- /dev/null +++ b/lib/ts/fastlz.h @@ -0,0 +1,100 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef FASTLZ_H +#define FASTLZ_H + +#define FASTLZ_VERSION 0x000100 + +#define FASTLZ_VERSION_MAJOR 0 +#define FASTLZ_VERSION_MINOR 0 +#define FASTLZ_VERSION_REVISION 0 + +#define FASTLZ_VERSION_STRING "0.1.0" + +#if defined (__cplusplus) +extern "C" { +#endif + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. +*/ + +int fastlz_compress(const void* input, int length, void* output); + +/** + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) + will be returned instead. + + The input buffer and the output buffer can not overlap. + + Decompression is memory safe and guaranteed not to write the output buffer + more than what is specified in maxout. + */ + +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. + + Compression level can be specified in parameter level. At the moment, + only level 1 and level 2 are supported. + Level 1 is the fastest compression and generally useful for short data. + Level 2 is slightly slower but it gives better compression ratio. + + Note that the compressed data, regardless of the level, can always be + decompressed using the function fastlz_decompress above. +*/ + +int fastlz_compress_level(int level, const void* input, int length, void* output); + +#if defined (__cplusplus) +} +#endif + +#endif /* FASTLZ_H */ diff --git a/lib/ts/ink_aiocb.h b/lib/ts/ink_aiocb.h new file mode 100644 index 00000000..1cf9d38c --- /dev/null +++ b/lib/ts/ink_aiocb.h @@ -0,0 +1,63 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Async Struct definition. + + + + ****************************************************************************/ + +#ifndef _ink_aiocb_h_ +#define _ink_aiocb_h_ + +#include "ink_port.h" + +/* TODO use native aiocb where possible */ + +#define LIO_READ 0x1 +#define LIO_WRITE 0x2 + +typedef struct ink_aiocb +{ + int aio_fildes; +#if defined(__STDC__) + volatile void *aio_buf; /* buffer location */ +#else + void *aio_buf; /* buffer location */ +#endif + size_t aio_nbytes; /* length of transfer */ + + // TODO change to off_t + off_t aio_offset; /* file offset */ + + int aio_reqprio; /* request priority offset */ + // struct sigevent aio_sigevent; /* signal number and offset */ + int aio_lio_opcode; /* listio operation */ + // aio_result_t aio_resultp; /* results */ + int aio_state; /* state flag for List I/O */ + int aio__pad[1]; /* extension padding */ +} ink_aiocb_t; + +#endif diff --git a/lib/ts/ink_align.h b/lib/ts/ink_align.h new file mode 100644 index 00000000..4f903d95 --- /dev/null +++ b/lib/ts/ink_align.h @@ -0,0 +1,82 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +//-*-c++-*- +#ifndef _ink_align_h_ +#define _ink_align_h_ + +/** + * Alignment macros + */ + +#define INK_MIN_ALIGN 8 +/* INK_ALIGN() is only to be used to align on a power of 2 boundary */ +#define INK_ALIGN(size, boundary) \ + (((size) + ((boundary) - 1)) & ~((boundary) - 1)) + +/** Default alignment */ +#define INK_ALIGN_DEFAULT(size) INK_ALIGN(size, INK_MIN_ALIGN) + +// +// Move a pointer forward until it meets the alignment width. +// +static inline void * +align_pointer_forward(const void *pointer_, size_t alignment) +{ + char *pointer = (char *) pointer_; + // + // Round up alignment.. + // + pointer = (char *) INK_ALIGN((ptrdiff_t) pointer, alignment); + + return (void *) pointer; +} + +// +// Move a pointer forward until it meets the alignment width specified, +// and zero out the contents of the space you're skipping over. +// +static inline void * +align_pointer_forward_and_zero(const void *pointer_, size_t alignment) +{ + char *pointer = (char *) pointer_; + char *aligned = (char *) INK_ALIGN((ptrdiff_t) pointer, alignment); + // + // Fill the skippings.. + // + while (pointer < aligned) { + *pointer = 0; + pointer++; + } + + return (void *) aligned; +} + +// +// We include two signatures for the same function to avoid error +// messages concerning coercion between void* and unsigned long. +// We could handle this using casts, but that's more prone to +// errors during porting. +// + +#endif diff --git a/lib/ts/ink_apidefs.h b/lib/ts/ink_apidefs.h new file mode 100644 index 00000000..166b72b8 --- /dev/null +++ b/lib/ts/ink_apidefs.h @@ -0,0 +1,32 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_apidefs_h_ +#define _ink_apidefs_h_ + +#define inkliapi +#define inkcoreapi +#define ink_undoc_liapi +#define ink_undoc_coreapi inkcoreapi + +#endif diff --git a/lib/ts/ink_args.cc b/lib/ts/ink_args.cc new file mode 100644 index 00000000..d21bd0c2 --- /dev/null +++ b/lib/ts/ink_args.cc @@ -0,0 +1,254 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** +Process arguments + +****************************************************************************/ + +#include "libts.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +// +// Global variables +// + +char *file_arguments[MAX_FILE_ARGUMENTS] = { 0 }; +char *program_name = (char *) "Traffic Server"; +int n_file_arguments = 0; + +// +// Local variables +// + +static char *argument_types_keys = (char *) "ISDfFTL"; +static char *argument_types_descriptions[] = { + (char *) "int ", + (char *) "str ", + (char *) "dbl ", + (char *) "off ", + (char *) "on ", + (char *) "tog ", + (char *) "i64 ", + (char *) " " +}; + +// +// Functions +// + +static void +process_arg(ArgumentDescription * argument_descriptions, + int n_argument_descriptions, int i, char ***argv, const char *usage_string) +{ + char *arg = NULL; + if (argument_descriptions[i].type) { + char type = argument_descriptions[i].type[0]; + if (type == 'F' || type == 'f') + *(int *) argument_descriptions[i].location = type == 'F' ? 1 : 0; + else if (type == 'T') + *(int *) argument_descriptions[i].location = !*(int *) argument_descriptions[i].location; + else { + arg = *++(**argv) ? **argv : *++(*argv); + if (!arg) + usage(argument_descriptions, n_argument_descriptions, usage_string); + switch (type) { + case 'I': + *(int *) argument_descriptions[i].location = atoi(arg); + break; + case 'D': + *(double *) argument_descriptions[i].location = atof(arg); + break; + case 'L': + *(int64_t *) argument_descriptions[i].location = ink_atoi64(arg); + break; + case 'S': + strncpy((char *) argument_descriptions[i].location, arg, atoi(argument_descriptions[i].type + 1)); + break; + default: + ink_fatal(1, (char *) "bad argument description"); + break; + } + **argv += strlen(**argv) - 1; + } + } + if (argument_descriptions[i].pfn) + argument_descriptions[i].pfn(argument_descriptions, n_argument_descriptions, arg); +} + + +void +show_argument_configuration(ArgumentDescription * argument_descriptions, int n_argument_descriptions) +{ + int i = 0; + printf("Argument Configuration\n"); + for (i = 0; i < n_argument_descriptions; i++) { + if (argument_descriptions[i].type) { + printf(" %-34s ", argument_descriptions[i].description); + switch (argument_descriptions[i].type[0]) { + case 'F': + case 'f': + case 'T': + printf(*(int *) argument_descriptions[i].location ? "TRUE" : "FALSE"); + break; + case 'I': + printf("%d", *(int *) argument_descriptions[i].location); + break; + case 'D': + printf("%f", *(double *) argument_descriptions[i].location); + break; + case 'L': + printf("%" PRId64 "", *(int64_t *) argument_descriptions[i].location); + break; + case 'S': + printf("%s", (char *) argument_descriptions[i].location); + break; + default: + ink_fatal(1, (char *) "bad argument description"); + break; + } + printf("\n"); + } + } +} + +void +process_args(ArgumentDescription * argument_descriptions, int n_argument_descriptions, char **argv, const char *usage_string) +{ + int i = 0; + // + // Grab Environment Variables + // + for (i = 0; i < n_argument_descriptions; i++) + if (argument_descriptions[i].env) { + char type = argument_descriptions[i].type[0]; + char *env = getenv(argument_descriptions[i].env); + if (!env) + continue; + switch (type) { + case 'f': + case 'F': + case 'I': + *(int *) argument_descriptions[i].location = atoi(env); + break; + case 'D': + *(double *) argument_descriptions[i].location = atof(env); + break; + case 'L': + *(int64_t *) argument_descriptions[i].location = atoll(env); + break; + case 'S': + strncpy((char *) argument_descriptions[i].location, env, atoi(argument_descriptions[i].type + 1)); + break; + } + } + // + // Grab Command Line Arguments + // + program_name = argv[0]; + while (*++argv) { + if (**argv == '-') { + if ((*argv)[1] == '-') { + for (i = 0; i < n_argument_descriptions; i++) + if (!strcmp(argument_descriptions[i].name, (*argv) + 2)) { + *argv += strlen(*argv) - 1; + process_arg(argument_descriptions, n_argument_descriptions, i, &argv, usage_string); + break; + } + if (i >= n_argument_descriptions) + usage(argument_descriptions, n_argument_descriptions, usage_string); + } else { + while (*++(*argv)) + for (i = 0; i < n_argument_descriptions; i++) + if (argument_descriptions[i].key == **argv) { + process_arg(argument_descriptions, n_argument_descriptions, i, &argv, usage_string); + break; + } + if (i >= n_argument_descriptions) + usage(argument_descriptions, n_argument_descriptions, usage_string); + } + } else { + if (n_file_arguments > MAX_FILE_ARGUMENTS) + ink_fatal(1, (char *) "too many files"); + file_arguments[n_file_arguments++] = *argv; + file_arguments[n_file_arguments] = NULL; + } + } +} + +void +usage(ArgumentDescription * argument_descriptions, int n_argument_descriptions, const char *usage_string) +{ + (void) argument_descriptions; + (void) n_argument_descriptions; + (void) usage_string; + if (usage_string) + fprintf(stderr, "%s\n", usage_string); + else + fprintf(stderr, "Usage: %s [--SWITCH [ARG]]\n", program_name); + fprintf(stderr, " switch__________________type__default___description\n"); + for (int i = 0; i < n_argument_descriptions; i++) { + if (!argument_descriptions[i].description) + continue; + fprintf(stderr, " -%c, --%-17s %s", + argument_descriptions[i].key, + argument_descriptions[i].name, + argument_types_descriptions[argument_descriptions[i].type ? + strchr(argument_types_keys, + argument_descriptions[i].type[0]) - + argument_types_keys : strlen(argument_types_keys) + ]); + switch (argument_descriptions[i].type ? argument_descriptions[i].type[0] : 0) { + case 0: + fprintf(stderr, " "); + break; + case 'L': + fprintf(stderr, " %-9" PRId64 "", *(int64_t *) argument_descriptions[i].location); + break; + case 'S': + if (*(char *) argument_descriptions[i].location) { + if (strlen((char *) argument_descriptions[i].location) < 10) + fprintf(stderr, " %-9s", (char *) argument_descriptions[i].location); + else { + ((char *) argument_descriptions[i].location)[7] = 0; + fprintf(stderr, " %-7s..", (char *) argument_descriptions[i].location); + } + } else + fprintf(stderr, " (null) "); + break; + case 'D': + fprintf(stderr, " %-9.3f", *(double *) argument_descriptions[i].location); + break; + case 'I': + fprintf(stderr, " %-9d", *(int *) argument_descriptions[i].location); + break; + case 'T': + case 'f': + case 'F': + fprintf(stderr, " %-9s", *(int *) argument_descriptions[i].location ? "true " : "false"); + break; + } + fprintf(stderr, " %s\n", argument_descriptions[i].description); + } + _exit(1); +} diff --git a/lib/ts/ink_args.h b/lib/ts/ink_args.h new file mode 100644 index 00000000..de6d34a4 --- /dev/null +++ b/lib/ts/ink_args.h @@ -0,0 +1,77 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** +Process arguments + +****************************************************************************/ + +#ifndef _INK_ARGS_H +#define _INK_ARGS_H +#include "ink_defs.h" + +#define MAX_FILE_ARGUMENTS 100 + +struct ArgumentDescription; + +typedef void ArgumentFunction(ArgumentDescription * argument_descriptions, int n_argument_descriptions, const char *arg); + +struct ArgumentDescription +{ + const char *name; + char key; + /* + "I" = integer + "L" = int64_t + "D" = double (floating point) + "T" = toggle + "F" = set flag to TRUE (default is FALSE) + "f" = set flag to FALSE (default is TRUE) + "T" = toggle + "S80" = read string, 80 chars max + */ + const char *description; + const char *type; + void *location; + const char *env; + ArgumentFunction *pfn; +}; + +/* Global Data +*/ +extern char *file_arguments[]; // exported by process_args() +extern int n_file_arguments; // exported by process_args() +extern char *program_name; // exported by process_args() + +/* Print out arguments and values +*/ +void show_argument_configuration(ArgumentDescription * argument_descriptions, int n_argument_descriptions); + +void usage(ArgumentDescription * argument_descriptions, int n_argument_descriptions, const char *arg_unused); + +/* Process all arguments +*/ +void process_args(ArgumentDescription * argument_descriptions, + int n_argument_descriptions, char **argv, const char *usage_string = 0); + +#endif /*_INK_ARGS_H*/ diff --git a/lib/ts/ink_assert.cc b/lib/ts/ink_assert.cc new file mode 100644 index 00000000..38deb00c --- /dev/null +++ b/lib/ts/ink_assert.cc @@ -0,0 +1,47 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************************************************************** +Assertions + +***************************************************************************/ + +#include "ink_platform.h" +#include "ink_assert.h" +#include "ink_error.h" +#include "ink_unused.h" +#include "ink_string.h" /* MAGIC_EDITING_TAG */ + +int +_ink_assert(const char *a, const char *f, int l) +{ + char buf1[256]; + char buf2[512]; + ink_strlcpy(buf1, f, sizeof(buf1)); + snprintf(buf2, sizeof(buf2), "%s:%d: failed assert `", buf1, l); + ink_strlcat(buf2, a, sizeof(buf2)); + ink_strlcat(buf2, "`", sizeof(buf2)); + ink_fatal(1, buf2); + + return (0); +} diff --git a/lib/ts/ink_assert.h b/lib/ts/ink_assert.h new file mode 100644 index 00000000..ed59cd9f --- /dev/null +++ b/lib/ts/ink_assert.h @@ -0,0 +1,74 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************************************************************** +Assertions + +***************************************************************************/ +#ifndef _INK_ASSERT_H +#define _INK_ASSERT_H + +#include "ink_apidefs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* don't use assert, no really DON'T use assert */ +#undef assert +#define assert __DONT_USE_BARE_assert_USE_ink_assert__ +#undef _ASSERT_H +#define _ASSERT_H +#undef __ASSERT_H__ +#define __ASSERT_H__ + + inkcoreapi int _ink_assert(const char *a, const char *f, int l); + +#ifdef DEBUG +#define ink_assert(EX) (\ + void)((EX) || (_ink_assert(#EX, __FILE__, __LINE__))) +#define ink_debug_assert(EX) \ + (void)((EX) || (_ink_assert(#EX, __FILE__, __LINE__))) +#else +#define ink_assert(EX) (void)(EX) +#define ink_debug_assert(EX) +#endif + +#define ink_release_assert(EX) \ + (void)((EX) || (_ink_assert(#EX, __FILE__, __LINE__))) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /*_INK_ASSERT_H*/ + +/* workaround a bug in the stupid Sun preprocessor + +#undef assert +#define assert __DONT_USE_BARE_assert_USE_ink_assert__ +#define _ASSERT_H +#undef __ASSERT_H__ +#define __ASSERT_H__ +*/ diff --git a/lib/ts/ink_atomic.h b/lib/ts/ink_atomic.h new file mode 100644 index 00000000..5853e194 --- /dev/null +++ b/lib/ts/ink_atomic.h @@ -0,0 +1,167 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_atomic.h + + This file defines atomic memory operations. + + On a Sparc V9, ink_atomic.c must be compiled with gcc and requires + the argument "-Wa,-xarch=v8plus" to get the assembler to emit V9 + instructions. + + + ****************************************************************************/ + +#ifndef _ink_atomic_h_ +#define _ink_atomic_h_ + +#include +#include +#include +#include +#include "ink_port.h" + +#include "ink_apidefs.h" +#include "ink_mutex.h" + +typedef volatile int8_t vint8; +typedef volatile int16_t vint16; +typedef volatile int32_t vint32; +typedef volatile int64_t vint64; +typedef volatile void *vvoidp; + +typedef vint8 *pvint8; +typedef vint16 *pvint16; +typedef vint32 *pvint32; +typedef vint64 *pvint64; +typedef vvoidp *pvvoidp; + +// Sun/Solaris and the SunPRO compiler +#if defined(__SUNPRO_CC) +typedef volatile uint8_t vuint8; +typedef volatile uint16_t vuint16; +typedef volatile uint32_t vuint32; +#if __WORDSIZE == 64 +typedef unsigned long uint64_s; +#else +typedef uint64_t uint64_s; +#endif +typedef volatile uint64_s vuint64_s; +typedef vuint8 *pvuint8; +typedef vuint16 *pvuint16; +typedef vuint32 *pvuint32; +typedef vuint64_s *pvuint64_s; + +#include + +static inline int8_t ink_atomic_swap8(pvint8 mem, int8_t value) { return (int8_t)atomic_swap_8((pvuint8)mem, (uint8_t)value); } +static inline int16_t ink_atomic_swap16(pvint16 mem, int16_t value) { return (int16_t)atomic_swap_16((pvuint16)mem, (uint16_t)value); } +static inline int32_t ink_atomic_swap32(pvint32 mem, int32_t value) { return (int32_t)atomic_swap_32((pvuint32)mem, (uint32_t)value); } + +static inline int32_t ink_atomic_swap(pvint32 mem, int32_t value) { return (int32_t)atomic_swap_32((pvuint32)mem, (uint32_t)value); } +static inline int64_t ink_atomic_swap64(pvint64 mem, int64_t value) { return (int64_t)atomic_swap_64((pvuint64_s)mem, (uint64_s)value); } +static inline void *ink_atomic_swap_ptr(vvoidp mem, void *value) { return atomic_swap_ptr((vvoidp)mem, value); } + +static inline int ink_atomic_cas(pvint32 mem, int old, int new_value) { return atomic_cas_32((pvuint32)mem, (uint32_t)old, (uint32_t)new_value) == old; } +static inline int ink_atomic_cas64(pvint64 mem, int64_t old, int64_t new_value) { return atomic_cas_64((pvuint64_s)mem, (uint64_s)old, (uint64_s)new_value) == old; } +static inline int ink_atomic_cas_ptr(pvvoidp mem, void* old, void* new_value) { return atomic_cas_ptr((vvoidp)mem, old, new_value) == old; } +static inline int ink_atomic_increment(pvint32 mem, int value) { return ((uint32_t)atomic_add_32_nv((pvuint32)mem, (uint32_t)value)) - value; } +static inline int64_t ink_atomic_increment64(pvint64 mem, int64_t value) { return ((uint64_s)atomic_add_64_nv((pvuint64_s)mem, (uint64_s)value)) - value; } +static inline void *ink_atomic_increment_ptr(pvvoidp mem, intptr_t value) { return (void*)(((char*)atomic_add_ptr_nv((vvoidp)mem, (ssize_t)value)) - value); } + +/* not used for Intel Processors or Sparc which are mostly sequentally consistent */ +#define INK_WRITE_MEMORY_BARRIER +#define INK_MEMORY_BARRIER + +#else /* ! defined(__SUNPRO_CC) */ + +/* GCC compiler >= 4.1 */ +#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1) + +/* see http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html */ + +static inline int8_t ink_atomic_swap8(pvint8 mem, int8_t value) { return __sync_lock_test_and_set(mem, value); } +static inline int16_t ink_atomic_swap16(pvint16 mem, int16_t value) { return __sync_lock_test_and_set(mem, value); } +static inline int32_t ink_atomic_swap32(pvint32 mem, int32_t value) { return __sync_lock_test_and_set(mem, value); } + +static inline int32_t ink_atomic_swap(pvint32 mem, int32_t value) { return __sync_lock_test_and_set(mem, value); } +static inline void *ink_atomic_swap_ptr(vvoidp mem, void *value) { return __sync_lock_test_and_set((void**)mem, value); } + +static inline int ink_atomic_cas(pvint32 mem, int old, int new_value) { return __sync_bool_compare_and_swap(mem, old, new_value); } +static inline int ink_atomic_cas_ptr(pvvoidp mem, void* old, void* new_value) { return __sync_bool_compare_and_swap(mem, old, new_value); } + +static inline int ink_atomic_increment(pvint32 mem, int value) { return __sync_fetch_and_add(mem, value); } +static inline void *ink_atomic_increment_ptr(pvvoidp mem, intptr_t value) { return __sync_fetch_and_add((void**)mem, value); } + +// Special hacks for ARM 32-bit +#if defined(__arm__) && (SIZEOF_VOIDP == 4) +extern ProcessMutex __global_death; + +static inline int64_t +ink_atomic_swap64(pvint64 mem, int64_t value) { + int64_t old; + ink_mutex_acquire(&__global_death); + old = *mem; + *mem = value; + ink_mutex_release(&__global_death); + return old; +} +static inline int64_t +ink_atomic_cas64(pvint64 mem, int64_t old, int64_t new_value) { + int64_t curr; + ink_mutex_acquire(&__global_death); + curr = *mem; + if(old == curr) *mem = new_value; + ink_mutex_release(&__global_death); + if(old == curr) return 1; + return 0; +} +static inline int64_t +ink_atomic_increment64(pvint64 mem, int64_t value) { + int64_t curr; + ink_mutex_acquire(&__global_death); + curr = *mem; + *mem = curr + value; + ink_mutex_release(&__global_death); + return curr + value; +} + +#else /* Intel 64-bit operations */ +static inline int64_t ink_atomic_swap64(pvint64 mem, int64_t value) { return __sync_lock_test_and_set(mem, value); } +static inline int64_t ink_atomic_cas64(pvint64 mem, int64_t old, int64_t new_value) { return __sync_bool_compare_and_swap(mem, old, new_value); } +static inline int64_t ink_atomic_increment64(pvint64 mem, int64_t value) { return __sync_fetch_and_add(mem, value); } +#endif + +/* not used for Intel Processors which have sequential(esque) consistency */ +#define INK_WRITE_MEMORY_BARRIER +#define INK_MEMORY_BARRIER + +#else /* not gcc > v4.1.2 */ +#error Need a compiler / libc that supports atomic operations, e.g. gcc v4.1.2 or later +#endif + +#endif /* SunPRO CC */ + +#endif /* _ink_atomic_h_ */ diff --git a/lib/ts/ink_auth_api.cc b/lib/ts/ink_auth_api.cc new file mode 100644 index 00000000..4926ddcb --- /dev/null +++ b/lib/ts/ink_auth_api.cc @@ -0,0 +1,82 @@ +/** @file + + PE/TE authentication definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include "ink_rand.h" +#include "ink_code.h" +#include "ink_auth_api.h" + +static int s_rand_seed = time(NULL) + s_rand_seed; +static InkRand +s_rand_gen(ink_rand_r((unsigned int *) &s_rand_seed) ^ (uintptr_t) &s_rand_seed); + +inline uint32_t +ink_get_rand_intrn() +{ + return s_rand_gen.random(); +} + +inline void +ink_make_token_intrn(INK_AUTH_TOKEN * tok, const INK_AUTH_SEED * const *seeds, int slen) +{ + INK_DIGEST_CTX ctx; + ink_code_incr_md5_init(&ctx); + while (slen-- > 0) { + ink_code_incr_md5_update(&ctx, (const char *) seeds[slen]->data(), seeds[slen]->length()); + } + ink_code_incr_md5_final((char *) &(tok->u8[0]), &ctx); +} + +uint32_t +ink_get_rand() +{ + return ink_get_rand_intrn(); +} + +void +ink_make_token(INK_AUTH_TOKEN * tok, const INK_AUTH_TOKEN & mask, const INK_AUTH_SEED * const *seeds, int slen) +{ + ink_make_token_intrn(tok, seeds, slen); + for (int i = 3; i >= 0; i--) // randomize masked bits + tok->u32[i] ^= mask.u32[i] & ink_get_rand_intrn(); +} + +uint32_t +ink_make_token32(uint32_t mask, const INK_AUTH_SEED * const *seeds, int slen) +{ + INK_AUTH_TOKEN tok; + ink_make_token_intrn(&tok, seeds, slen); + tok.u64[1] ^= tok.u64[0]; + tok.u32[3] ^= tok.u32[2]; + return tok.u32[3] ^ (mask & ink_get_rand_intrn()); +} + +uint64_t +ink_make_token64(uint64_t mask, const INK_AUTH_SEED * const *seeds, int slen) +{ + INK_AUTH_TOKEN tok; + ink_make_token_intrn(&tok, seeds, slen); + tok.u64[1] ^= tok.u64[0]; + return tok.u64[1] ^ (mask & ((uint64_t) ink_get_rand_intrn() + (((uint64_t) ink_get_rand_intrn()) << 32))); +} diff --git a/lib/ts/ink_auth_api.h b/lib/ts/ink_auth_api.h new file mode 100644 index 00000000..ddb2564f --- /dev/null +++ b/lib/ts/ink_auth_api.h @@ -0,0 +1,228 @@ +/** @file + + PE/TE authentication definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __INK_AUTH_API_H_INCLUDDED__ +#define __INK_AUTH_API_H_INCLUDDED__ + +#include +#include + +#include "ink_port.h" + +typedef union +{ + uint64_t u64[2]; + uint32_t u32[4]; + uint16_t u16[8]; + uint8_t u8[16]; +} INK_AUTH_TOKEN; + +class INK_AUTH_SEED +{ +public: + const void *data() const + { + return m_data; + } + unsigned length() const + { + return m_length; + } + + inline INK_AUTH_SEED(const void *x, unsigned ln) + { + init(x, ln); + } + + inline INK_AUTH_SEED(const uint8_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const uint16_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const uint32_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const uint64_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const int8_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const int16_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const int32_t & x) + { + init((const void *) &x, sizeof(x)); + } + inline INK_AUTH_SEED(const int64_t & x) + { + init((const void *) &x, sizeof(x)); + } + + inline INK_AUTH_SEED(const INK_AUTH_TOKEN & x) + { + init((const void *) &(x.u8[0]), sizeof(x.u8)); + } + + inline INK_AUTH_SEED(const char *str) + { + init((const void *) str, strlen((const char *) str)); + } + + inline INK_AUTH_SEED(const char *str, unsigned ln) + { + init((const void *) str, ln); + } + + inline INK_AUTH_SEED(const unsigned char *str) + { + init((const void *) str, strlen((const char *) str)); + } + + inline INK_AUTH_SEED(const unsigned char *str, unsigned ln) + { + init((const void *) str, ln); + } + +protected: + + void init(const void *d, unsigned l) + { + m_data = d; + m_length = l; + } + + const void *m_data; + unsigned m_length; +}; + + +void ink_make_token(INK_AUTH_TOKEN * tok, const INK_AUTH_TOKEN & mask, const INK_AUTH_SEED * const *seeds, int slen); + +uint32_t ink_make_token32(uint32_t mask, const INK_AUTH_SEED * const *seeds, int slen); +uint64_t ink_make_token64(uint64_t mask, const INK_AUTH_SEED * const *seeds, int slen); + +uint32_t ink_get_rand(); + +#define INK_TOKENS_EQUAL(m,t1,t2) ((((t1)^(t2))&(~(m))) == 0) + +// +// Helper functions - wiil create INK_AUTH_SEEDs from base types on fly +// +inline uint32_t +ink_make_token32(uint32_t mask, const INK_AUTH_SEED & s1) +{ + const INK_AUTH_SEED *s[] = { &s1 }; + return ink_make_token32(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint32_t +ink_make_token32(uint32_t mask, const INK_AUTH_SEED & s1, const INK_AUTH_SEED & s2) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2 }; + return ink_make_token32(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint32_t +ink_make_token32(uint32_t mask, const INK_AUTH_SEED & s1, const INK_AUTH_SEED & s2, const INK_AUTH_SEED & s3) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2, &s3 }; + return ink_make_token32(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint32_t +ink_make_token32(uint32_t mask, + const INK_AUTH_SEED & s1, const INK_AUTH_SEED & s2, const INK_AUTH_SEED & s3, const INK_AUTH_SEED & s4) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2, &s3, &s4 }; + return ink_make_token32(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint32_t +ink_make_token32(uint32_t mask, + const INK_AUTH_SEED & s1, + const INK_AUTH_SEED & s2, const INK_AUTH_SEED & s3, const INK_AUTH_SEED & s4, const INK_AUTH_SEED & s5) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2, &s3, &s4, &s5 }; + return ink_make_token32(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint64_t +ink_make_token64(uint64_t mask, const INK_AUTH_SEED & s1) +{ + const INK_AUTH_SEED *s[] = { &s1 }; + return ink_make_token64(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint64_t +ink_make_token64(uint64_t mask, const INK_AUTH_SEED & s1, const INK_AUTH_SEED & s2) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2 }; + return ink_make_token64(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint64_t +ink_make_token64(uint64_t mask, const INK_AUTH_SEED & s1, const INK_AUTH_SEED & s2, const INK_AUTH_SEED & s3) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2, &s3 }; + return ink_make_token64(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint64_t +ink_make_token64(uint64_t mask, + const INK_AUTH_SEED & s1, const INK_AUTH_SEED & s2, const INK_AUTH_SEED & s3, const INK_AUTH_SEED & s4) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2, &s3, &s4 }; + return ink_make_token64(mask, s, sizeof(s) / sizeof(*s)); +} + +inline uint64_t +ink_make_token64(uint64_t mask, + const INK_AUTH_SEED & s1, + const INK_AUTH_SEED & s2, const INK_AUTH_SEED & s3, const INK_AUTH_SEED & s4, const INK_AUTH_SEED & s5) +{ + const INK_AUTH_SEED *s[] = { &s1, &s2, &s3, &s4, &s5 }; + return ink_make_token64(mask, s, sizeof(s) / sizeof(*s)); +} + +inline int64_t +INK_AUTH_MAKE_INT_64(uint32_t h, uint32_t l) +{ + return int64_t((((uint64_t) h) << 32) + (uint32_t) l); +} + +inline int64_t +INK_AUTH_MAKE_INT_64(uint32_t u) +{ + return INK_AUTH_MAKE_INT_64(u, u); +} + +#endif // #ifndef __INK_AUTH_API_H_INCLUDDED__ diff --git a/lib/ts/ink_autoconf.h.in b/lib/ts/ink_autoconf.h.in new file mode 100644 index 00000000..f521d514 --- /dev/null +++ b/lib/ts/ink_autoconf.h.in @@ -0,0 +1,269 @@ +/* lib/ts/ink_autoconf.h.in. Generated from configure.ac by autoheader. */ + + +#ifndef _ink_autoconf_h +#define _ink_autoconf_h + + +/* Define if gethostbyname_r has the glibc style */ +#undef GETHOSTBYNAME_R_GLIBC2 + +/* Define if gethostbyname_r has the hostent_data for the third argument */ +#undef GETHOSTBYNAME_R_HOSTENT_DATA + +/* Define to 1 if you have the header file. */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_NAMESER_COMPAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_CPIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + +/* Define to 1 if you have the declaration of `EVP_PKEY_CTX_new', and to 0 if + you don't. */ +#undef HAVE_DECL_EVP_PKEY_CTX_NEW + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the `epoll_ctl' function. */ +#undef HAVE_EPOLL_CTL + +/* Define to 1 if you have the `eventfd' function. */ +#undef HAVE_EVENTFD + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXPAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FLOAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_GOOGLE_PROFILER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `kqueue' function. */ +#undef HAVE_KQUEUE + +/* Define to 1 if you have Expat library */ +#undef HAVE_LIBEXPAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBGEN_H + +/* Compiling with pcre support */ +#undef HAVE_LIBPCRE + +/* Define to 1 if you have the `lrand48_r' function. */ +#undef HAVE_LRAND48_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_LZMA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACHINE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MATH_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_SYSTM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IP_ICMP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NET_PPP_DEFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_X509_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PCRE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PCRE_PCRE_H + +/* Define to 1 if you have the `port_create' function. */ +#undef HAVE_PORT_CREATE + +/* Define to 1 if you have the `posix_fadvise' function. */ +#undef HAVE_POSIX_FADVISE + +/* Define to 1 if you have the `posix_memalign' function. */ +#undef HAVE_POSIX_MEMALIGN + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGINFO_H + +/* Define to 1 if you have the `srand48_r' function. */ +#undef HAVE_SRAND48_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the header file. */ +#undef HAVE_STROPTS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BYTEORDER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CAPABILITY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_EPOLL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_EVENTFD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_EVENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PRCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSINFO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSMACROS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSTEMINFO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_VALUES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ZLIB_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `void*', as computed by sizeof. */ +#undef SIZEOF_VOIDP + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* posix thread semantics */ +#undef _POSIX_PTHREAD_SEMANTICS + + + +#endif /* _ink_autoconf_h */ + diff --git a/lib/ts/ink_base64.cc b/lib/ts/ink_base64.cc new file mode 100644 index 00000000..b1a5994f --- /dev/null +++ b/lib/ts/ink_base64.cc @@ -0,0 +1,306 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * Base64 encoding and decoding as according to RFC1521. Similar to uudecode. + * + * RFC 1521 requires inserting line breaks for long lines. The basic web + * authentication scheme does not require them. This implementation is + * intended for web-related use, and line breaks are not implemented. + * + * These routines return char*'s to malloc-ed strings. The caller is + * responsible for freeing the strings. + */ +#include "libts.h" + +#include "ink_assert.h" +#include "ink_bool.h" +#include "ink_resource.h" +#include "ink_unused.h" + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +#ifdef decode +# undef decode +#endif +#define decode(A) ((unsigned int)codes[(unsigned char)input[A]]) + +// NOTE: ink_base64_decode returns xmalloc'd memory + +char * +ink_base64_decode(const char *input, int input_len, int *output_len) +{ + char *output; + char *obuf; + static bool initialized = FALSE; + static char codes[256]; + int cc = 0; + int len; + int i; + + if (!initialized) { + /* Build translation table */ + for (i = 0; i < 256; i++) + codes[i] = 0; + for (i = 'A'; i <= 'Z'; i++) + codes[i] = cc++; + for (i = 'a'; i <= 'z'; i++) + codes[i] = cc++; + for (i = '0'; i <= '9'; i++) + codes[i] = cc++; + codes[0 + '+'] = cc++; + codes[0 + '/'] = cc++; + initialized = TRUE; + } + // compute ciphertext length + for (len = 0; len < input_len && input[len] != '='; len++); + + output = obuf = (char *) xmalloc((len * 6) / 8 + 4); + ink_assert(output != NULL); + + while (len > 0) { + *output++ = decode(0) << 2 | decode(1) >> 4; + *output++ = decode(1) << 4 | decode(2) >> 2; + *output++ = decode(2) << 6 | decode(3); + len -= 4; + input += 4; + } + + /* + * We don't need to worry about leftover bits because + * we've allocated a few extra characters and if there + * are leftover bits they will be zeros because the extra + * inputs will be '='s and '=' decodes to 0. + */ + + *output = '\0'; + *output_len = (int) (output - obuf); + return obuf; +} + +#undef decode + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +// NOTE: ink_base64_encode returns xmalloc'd memory + +char * +ink_base64_encode(const char *input, int input_len, int *output_len) +{ + return ink_base64_encode_unsigned((const unsigned char *) input, input_len, output_len); +} + +char * +ink_base64_encode_unsigned(const unsigned char *input, int input_len, int *output_len) +{ + char *output; + char *obuf; + static char codes[66] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char in_tail[4]; + int len; + + len = input_len; + + output = obuf = (char *) xmalloc((len * 8) / 6 + 4); + ink_assert(output != NULL); + + while (len > 2) { + *output++ = codes[(input[0] >> 2) & 077]; + + *output++ = codes[((input[0] & 03) << 4) + | ((input[1] >> 4) & 017)]; + + *output++ = codes[((input[1] & 017) << 2) + | ((input[2] >> 6) & 017)]; + + *output++ = codes[input[2] & 077]; + + len -= 3; + input += 3; + } + + /* + * We've done all the input groups of three chars. We're left + * with 0, 1, or 2 input chars. We have to add zero-bits to the + * right if we don't have enough input chars. + * If 0 chars left, we're done. + * If 1 char left, form 2 output chars, and add 2 pad chars to output. + * If 2 chars left, form 3 output chars, add 1 pad char to output. + */ + + if (len == 0) { + *output_len = (int) (output - obuf); + *output = '\0'; + return obuf; + } else { + memset(in_tail, 0, sizeof(in_tail)); + memcpy(in_tail, input, len); + + *(output) = codes[(in_tail[0] >> 2) & 077]; + + *(output + 1) = codes[((in_tail[0] & 03) << 4) + | ((in_tail[1] >> 4) & 017)]; + + *(output + 2) = codes[((in_tail[1] & 017) << 2) + | ((in_tail[2] >> 6) & 017)]; + + *(output + 3) = codes[in_tail[2] & 077]; + + if (len == 1) + *(output + 2) = '='; + + *(output + 3) = '='; + + *(output + 4) = '\0'; + + *output_len = (int) ((output + 4) - obuf); + return obuf; + } +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +// int ink_base64_decode() +// +// The above functions require malloc'ing buffer which isn't good for +// Traffic Server performance and the the decode routine is not +// reentrant. The following function fixes both those problems + +/* Converts a printable character to it's six bit representation */ +const unsigned char printableToSixBit[256] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 +}; + + +#ifdef DECODE +#undef DECODE +#endif + +#define DECODE(x) printableToSixBit[(unsigned char)x] +#define MAX_PRINT_VAL 63 + +int +ink_base64_decode(const char *inBuffer, int outBufSize, unsigned char *outBuffer) +{ + + int inBytes = 0; + int decodedBytes = 0; + unsigned char *outStart = outBuffer; + int inputBytesDecoded = 0; + + // Figure out much encoded string is really there + while (printableToSixBit[(uint8_t)inBuffer[inBytes]] <= MAX_PRINT_VAL) { + inBytes++; + } + + // Make sure there is sufficient space in the output buffer + // if not shorten the number of bytes in + if ((((inBytes + 3) / 4) * 3) > outBufSize - 1) { + inBytes = ((outBufSize - 1) * 4) / 3; + } + + for (int i = 0; i < inBytes; i += 4) { + + outBuffer[0] = (unsigned char) (DECODE(inBuffer[0]) << 2 | DECODE(inBuffer[1]) >> 4); + + outBuffer[1] = (unsigned char) (DECODE(inBuffer[1]) << 4 | DECODE(inBuffer[2]) >> 2); + outBuffer[2] = (unsigned char) (DECODE(inBuffer[2]) << 6 | DECODE(inBuffer[3])); + + outBuffer += 3; + inBuffer += 4; + decodedBytes += 3; + inputBytesDecoded += 4; + } + + // Check to see if we decoded a multiple of 4 four + // bytes + if ((inBytes - inputBytesDecoded) & 0x3) { + if (DECODE(inBuffer[-2]) > MAX_PRINT_VAL) { + decodedBytes -= 2; + } else { + decodedBytes -= 1; + } + } + + outStart[decodedBytes] = '\0'; + + return decodedBytes; +} + + +char six2pr[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +ink_base64_uuencode(const char *bufin, int nbytes, unsigned char *outBuffer) +{ + + int i; + + for (i = 0; i < nbytes; i += 3) { + *(outBuffer++) = six2pr[*bufin >> 2]; /* c1 */ + *(outBuffer++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2 */ + *(outBuffer++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)]; /*c3 */ + *(outBuffer++) = six2pr[bufin[2] & 077]; /* c4 */ + + bufin += 3; + } + + /* If nbytes was not a multiple of 3, then we have encoded too + * many characters. Adjust appropriately. + */ + if (i == nbytes + 1) { + /* There were only 2 bytes in that last group */ + outBuffer[-1] = '='; + } else if (i == nbytes + 2) { + /* There was only 1 byte in that last group */ + outBuffer[-1] = '='; + outBuffer[-2] = '='; + } + + *outBuffer = '\0'; + + return TRUE; +} diff --git a/lib/ts/ink_base64.h b/lib/ts/ink_base64.h new file mode 100644 index 00000000..111ea1d0 --- /dev/null +++ b/lib/ts/ink_base64.h @@ -0,0 +1,49 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_base64_h_ +#define _ink_base64_h_ +#include "ink_apidefs.h" +/* + * Base64 encoding and decoding as according to RFC1521. Similar to uudecode. + * See RFC1521 for specificiation. + * + * RFC 1521 requires inserting line breaks for long lines. The basic web + * authentication scheme does not require them. This implementation is + * intended for web-related use, and line breaks are not implemented. + * + * These routines return char*'s to malloc-ed strings. The caller is + * responsible for freeing the strings. + * + */ + +// These functions return xmalloc'd memory which caller needs to xfree +inkcoreapi char *ink_base64_decode(const char *input, int input_len, int *output_len); +char *ink_base64_encode(const char *input, int input_len, int *output_len); +char *ink_base64_encode_unsigned(const unsigned char *input, int input_len, int *output_len); + +// Decodes into user supplied buffer. Returns number of bytes decoded +inkcoreapi int ink_base64_decode(const char *inBuffer, int outBufSize, unsigned char *outBuffer); +int ink_base64_uuencode(const char *bufin, int nbytes, unsigned char *outBuffer); + +#endif diff --git a/lib/ts/ink_bool.h b/lib/ts/ink_bool.h new file mode 100644 index 00000000..b43702d9 --- /dev/null +++ b/lib/ts/ink_bool.h @@ -0,0 +1,75 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************** -*- Mod: C++ -*- ****************************** + + ink_bool.h -- + Created On : Wed Dec 4 11:36:03 1996 + Last Modified By: Ivry Semel + Last Modified On: Tue Dec 17 14:27:41 1996 + Update Count : 3 + Status : + + Description: + define type bool for the compilers that don't define it. + + + ****************************************************************************/ +#if !defined (_ink_bool_h_) +#define _ink_bool_h_ + + +#if !defined(linux) + +#if (defined (__GNUC__) || ! defined(__cplusplus)) +/* + * bool, true, and false already declared in C++ + */ +#if !defined (bool) +#if !defined(freebsd) && !defined(solaris) +#define bool int +#endif +#endif + +#if !defined (true) +#define true 1 +#endif + +#if !defined (false) +#define false 0 +#endif + +#endif /* #if (defined (__GNUC__) || ! defined(__cplusplus)) */ +#endif // not linux + +/* + * TRUE and FALSE not declared in C++ + */ +#if !defined (TRUE) +#define TRUE 1 +#endif +#if !defined (FALSE) +#define FALSE 0 +#endif + +#endif /* #if !defined (_ink_bool_h_) */ diff --git a/lib/ts/ink_cap.cc b/lib/ts/ink_cap.cc new file mode 100644 index 00000000..534db88a --- /dev/null +++ b/lib/ts/ink_cap.cc @@ -0,0 +1,88 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +# include "ink_config.h" +# include "Diags.h" +# include "ink_cap.h" + +# if TS_USE_POSIX_CAP +# include +# include +# endif + +void +DebugCapabilities(char const* tag) { + if (is_debug_tag_set(tag)) { +# if TS_USE_POSIX_CAP + cap_t caps = cap_get_proc(); + char* caps_text = cap_to_text(caps, 0); +# endif + + Debug(tag, + "uid=%u, gid=%u, euid=%u, egid=%u" +# if TS_USE_POSIX_CAP + ", caps %s thread 0x%x" +# endif + ,static_cast(getuid()) + ,static_cast(getgid()) + ,static_cast(geteuid()) + ,static_cast(getegid()) +# if TS_USE_POSIX_CAP + ,caps_text + ,pthread_self() +# endif + ); + +# if TS_USE_POSIX_CAP + cap_free(caps_text); + cap_free(caps); +# endif + } +} + +int +PreserveCapabilities() { + int zret = 0; +# if TS_USE_POSIX_CAP + zret = prctl(PR_SET_KEEPCAPS, 1); +# endif + return zret; +} + +// Adjust the capabilities to only those needed. +int +RestrictCapabilities() { + int zret = 0; // return value. +# if TS_USE_POSIX_CAP + cap_t caps = cap_init(); // start with nothing. + // Capabilities we need. + cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK }; + static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); + + cap_set_flag(caps, CAP_PERMITTED, CAP_COUNT, cap_list, CAP_SET); + cap_set_flag(caps, CAP_EFFECTIVE, CAP_COUNT, cap_list, CAP_SET); + zret = cap_set_proc(caps); + cap_free(caps); +# endif + return zret; +} diff --git a/lib/ts/ink_cap.h b/lib/ts/ink_cap.h new file mode 100644 index 00000000..c13df485 --- /dev/null +++ b/lib/ts/ink_cap.h @@ -0,0 +1,39 @@ +/** @file + + POSIX Capability related utilities. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#if !defined (_ink_cap_h_) +#define _ink_cap_h_ + +/// Generate a debug message with the current capabilities for the process. +extern void DebugCapabilities( + char const* tag ///< Debug message tag. +); +/// Set capabilities to persist across change of user id. +/// @return 0 on success, non-zero otherwise. +extern int PreserveCapabilities(); +/// Initialize and restrict the capabilities of a thread. +/// @return 0 on success, non-zero otherwise. +extern int RestrictCapabilities(); + +#endif diff --git a/lib/ts/ink_code.cc b/lib/ts/ink_code.cc new file mode 100644 index 00000000..659781e9 --- /dev/null +++ b/lib/ts/ink_code.cc @@ -0,0 +1,135 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include "ink_code.h" +#include "ink_assert.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + + +/** + @brief Wrapper around MD5_Init +*/ +int +ink_code_incr_md5_init(INK_DIGEST_CTX * context) { + return MD5_Init(context); +} + +/** + @brief Wrapper around MD5_Update +*/ +int +ink_code_incr_md5_update(INK_DIGEST_CTX * context, const char *input, int input_length) { + return MD5_Update(context, input, input_length); +} + +/** + @brief Wrapper around MD5_Final +*/ +int +ink_code_incr_md5_final(char *sixteen_byte_hash_pointer, INK_DIGEST_CTX * context) { + return MD5_Final((unsigned char*)sixteen_byte_hash_pointer, context); +} + +/** + @brief Helper that will init, update, and create a final MD5 + + @return always returns 0, maybe some error checking should be done +*/ +int +ink_code_md5(unsigned char *input, int input_length, unsigned char *sixteen_byte_hash_pointer) +{ + MD5_CTX context; + + MD5_Init(&context); + MD5_Update(&context, input, input_length); + MD5_Final(sixteen_byte_hash_pointer, &context); + + return (0); +} + +/** + @brief Converts a MD5 to a null-terminated string + + Externalizes an INK_MD5 as a null-terminated string into the first argument. + Side Effects: none + Reentrancy: n/a. + Thread Safety: safe. + Mem Management: stomps the passed dest char*. + + @return returns the passed destination string ptr. +*/ +/* reentrant version */ +char * +ink_code_md5_stringify(char *dest33, const size_t destSize, const char *md5) +{ + ink_assert(destSize >= 33); + + int i; + for (i = 0; i < 16; i++) { + // we check the size of the destination buffer above + // coverity[secure_coding] + sprintf(&(dest33[i * 2]), "%02X", md5[i]); + } + ink_assert(dest33[32] == '\0'); + return (dest33); +} /* End ink_code_stringify_md5(const char *md5) */ + +/** + @brief Converts a MD5 to a null-terminated string + + Externalizes an INK_MD5 as a null-terminated string into the first argument. + Does so without intenal procedure calls. + Side Effects: none. + Reentrancy: n/a. + Thread Safety: safe. + Mem Management: stomps the passed dest char*. + + @return returns the passed destination string ptr. +*/ +/* reentrant version */ +char * +ink_code_md5_stringify_fast(char *dest33, const char *md5) +{ + int i; + char *d; + + static char hex_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + d = dest33; + for (i = 0; i < 16; i += 4) { + *(d + 0) = hex_digits[((unsigned char) md5[i + 0]) >> 4]; + *(d + 1) = hex_digits[((unsigned char) md5[i + 0]) & 15]; + *(d + 2) = hex_digits[((unsigned char) md5[i + 1]) >> 4]; + *(d + 3) = hex_digits[((unsigned char) md5[i + 1]) & 15]; + *(d + 4) = hex_digits[((unsigned char) md5[i + 2]) >> 4]; + *(d + 5) = hex_digits[((unsigned char) md5[i + 2]) & 15]; + *(d + 6) = hex_digits[((unsigned char) md5[i + 3]) >> 4]; + *(d + 7) = hex_digits[((unsigned char) md5[i + 3]) & 15]; + d += 8; + } + *d = '\0'; + return (dest33); +} /* End ink_code_stringify_md5_fast */ + diff --git a/lib/ts/ink_code.h b/lib/ts/ink_code.h new file mode 100644 index 00000000..8e9eb38d --- /dev/null +++ b/lib/ts/ink_code.h @@ -0,0 +1,44 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_code_h_ +#define _ink_code_h_ + +#include "ink_apidefs.h" +#include + +/* INK_MD5 context. */ +typedef MD5_CTX INK_DIGEST_CTX; + +/* + Wrappers around the MD5 functions, all of this should be depericated and just use the functions directly +*/ + +inkcoreapi int ink_code_md5(unsigned char *input, int input_length, unsigned char *sixteen_byte_hash_pointer); +inkcoreapi char *ink_code_md5_stringify(char *dest33, const size_t destSize, const char *md5); +inkcoreapi char *ink_code_md5_stringify_fast(char *dest33, const char *md5); + +inkcoreapi int ink_code_incr_md5_init(INK_DIGEST_CTX * context); +inkcoreapi int ink_code_incr_md5_update(INK_DIGEST_CTX * context, const char *input, int input_length); +inkcoreapi int ink_code_incr_md5_final(char *sixteen_byte_hash_pointer, INK_DIGEST_CTX * context); +#endif diff --git a/lib/ts/ink_config.h.in b/lib/ts/ink_config.h.in new file mode 100644 index 00000000..ed199cc5 --- /dev/null +++ b/lib/ts/ink_config.h.in @@ -0,0 +1,194 @@ +/** @file + + Some small general interest definitions. The general standard is to + prefix these defines with TS_. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_config_h +#define _ink_config_h + +// Note: All "defines" should be prefixed with TS_ when appropriate, please +// don't use ATS_ any more. + +/* GENERATED FILE WARNING! DO NOT EDIT ink_config.h + * + * You must modify ink_config.h.in instead. + * + */ + +/* Include automake generated defines + */ +#include "ink_autoconf.h" + +#define BUILD_MACHINE "@build_machine@" +#define BUILD_PERSON "@build_person@" +#define BUILD_GROUP "@build_group@" + +/* Includes */ +#define TS_HAVE_SYS_EPOLL_H @sys_epollh@ +#define TS_HAVE_SYS_EVENT_H @sys_eventh@ +#define TS_HAVE_MACHINE_ENDIAN_H @machine_endianh@ +#define TS_HAVE_ENDIAN_H @endianh@ +#define TS_HAVE_NETINET_IN_H @netinet_inh@ +#define TS_HAVE_NETINET_IN_SYSTM_H @netinet_in_systmh@ +#define TS_HAVE_NETINET_TCP_H @netinet_tcph@ +#define TS_HAVE_SYS_IOCTL_H @sys_ioctlh@ +#define TS_HAVE_SYS_BYTEORDER_H @sys_byteorderh@ +#define TS_HAVE_SYS_SOCKIO_H @sys_sockioh@ +#define TS_HAVE_SYS_SYSCTL_H @sys_sysctlh@ +#define TS_HAVE_SYS_SYSINFO_H @sys_sysinfoh@ +#define TS_HAVE_SYS_SYSTEMINFO_H @sys_systeminfoh@ +#define TS_HAVE_ARPA_INET_H @arpa_ineth@ +#define TS_HAVE_ARPA_NAMESER_H @arpa_nameserh@ +#define TS_HAVE_ARPA_NAMESER_COMPAT_H @arpa_nameser_compath@ +#define TS_HAVE_EXECINFO_H @execinfoh@ +#define TS_HAVE_NETDB_H @netdbh@ +#define TS_HAVE_CTYPE_H @ctypeh@ +#define TS_HAVE_SIGINFO_H @siginfoh@ +#define TS_HAVE_MALLOC_H @malloch@ +#define TS_HAVE_WAIT_H @waith@ +#define TS_HAVE_FLOAT_H @floath@ +#define TS_HAVE_LIBGEN_H @libgenh@ +#define TS_HAVE_VALUES_H @valuesh@ +#define TS_HAVE_ALLOCA_H @allocah@ +#define TS_HAVE_CPIO_H @cpioh@ +#define TS_HAVE_STROPTS_H @stroptsh@ +#define TS_HAVE_SYS_MOUNT_H @sys_mounth@ +#define TS_HAVE_SYS_PARAM_H @sys_paramh@ +#define TS_HAVE_SYS_SYSMACROS_H @sys_sysmacrosh@ +#define TS_HAVE_MATH_H @mathh@ +#define TS_HAVE_NET_PPP_DEFS_H @net_ppp_defsh@ +#define TS_HAVE_NETINET_IP_H @netinet_iph@ +#define TS_HAVE_NETINET_IP_ICMP_H @netinet_ip_icmph@ +#define TS_HAVE_EXECINFO_H @execinfoh@ + +/* Libraries */ +#define TS_HAS_LIBZ @zlibh@ +#define TS_HAS_LZMA @lzmah@ +#define TS_HAS_EXPAT @expath@ + +/* Features */ +#define TS_HAS_EVENTFD @has_eventfd@ +#define TS_HAS_CLOCK_GETTIME @has_clock_gettime@ +#define TS_HAS_POSIX_MEMALIGN @has_posix_memalign@ +#define TS_HAS_POSIX_FADVISE @has_posix_fadvise@ +#define TS_HAS_LRAND48_R @has_lrand48_r@ +#define TS_HAS_SRAND48_R @has_srand48_r@ +#define TS_HAS_STRNDUP @has_strndup@ +#define TS_HAS_STRLCPY @has_strlcpy@ +#define TS_HAS_STRLCAT @has_strlcat@ + +#define TS_HAS_BACKTRACE @has_backtrace@ +#define TS_HAS_PROFILER @has_profiler@ +#define TS_USE_FAST_SDK @use_fast_sdk@ +#define TS_USE_DIAGS @use_diags@ +#define TS_USE_LIBEV @use_libev@ +#define TS_USE_EPOLL @use_epoll@ +#define TS_USE_KQUEUE @use_kqueue@ +#define TS_USE_PORT @use_port@ +#define TS_USE_POSIX_CAP @use_posix_cap@ +#define TS_USE_TPROXY @use_tproxy@ + +/* OS API definitions */ +#define GETHOSTBYNAME_R_HOSTENT_DATA @gethostbyname_r_hostent_data@ +#define GETHOSTBYNAME_R_GLIBC2 @gethostbyname_r_glibc2@ +#define NEED_UNION_SEMUN @need_union_semun@ +#define SIZEOF_VOID_POINTER @ac_cv_sizeof_voidp@ +#define TS_IP_TRANSPARENT @ip_transparent@ + +/* API */ +#define TS_IS_MICRO_BUILD @is_micro_build@ +#define TS_HAS_STANDALONE_IOCORE @has_standalone_iocore@ +#define TS_HAS_INKAPI @has_inkapi@ +#define TS_HAS_PURIFY @has_purify@ +#define TS_HAS_DEMANGLE @has_demangle@ +#define TS_HAS_TESTS @has_tests@ +#define TS_HAS_WCCP @has_wccp@ + +/* XXX: Should make those individually selectable ? */ +/* TODO: Use TS prefix instead no prefix or INK */ +#if TS_IS_MICRO_BUILD +# define TS_MICRO 1 +# define INK_NO_ACL 1 +# define INK_NO_CLUSTER 1 +# define TS_USE_DIAGS 0 +# define INK_NO_HOSTDB 1 +# define INK_NO_ICP 1 +# define INK_NO_LOG 1 +# define INK_NO_REVERSE 1 +# define INK_NO_SOCKS 1 +# define INK_NO_STAT_PAGES 1 +# define INK_USE_MUTEX_FOR_ATOMICLISTS 1 +# define INK_USE_MUTEX_FOR_FREELISTS 1 +# define USE_MD5_FOR_MMH 1 +# define _NO_FREELIST 1 +#endif + +#if TS_HAS_INKAPI +#define TS_MAX_API_STATS @max_api_stats@ +/* XXX: Should make those individually selectable ? */ +#else +# define TS_NO_TRANSFORM 1 +# define TS_NO_API 1 +#endif + +#if TS_HAS_STANDALONE_IOCORE +# define STANDALONE_IOCORE 1 +#else +# define FIXME_NONMODULAR 1 +# define SPLIT_DNS 1 +# define NON_MODULAR 1 +# define HTTP_CACHE 1 +#endif + +#if TS_HAS_PURIFY +# define PURIFY 1 +#endif + +/* Defaults for user / group */ +#define TS_PKGSYSUSER "@pkgsysuser@" +#define TS_PKGSYSGROUP "@pkgsysgroup@" + +/* TODO: Fix those always defined features */ +#define MODULARIZED + + +/* Various "build" defines */ +#define TS_BUILD_PREFIX "@prefix@" +#define TS_BUILD_EXEC_PREFIX "@rel_exec_prefix@" +#define TS_BUILD_BINDIR "@rel_bindir@" +#define TS_BUILD_SBINDIR "@rel_sbindir@" +#define TS_BUILD_SYSCONFDIR "@rel_sysconfdir@" +#define TS_BUILD_SYSCONFIGDIR "@exp_sysconfdir@" +#define TS_BUILD_DATADIR "@rel_datadir@" +#define TS_BUILD_INCLUDEDIR "@rel_includedir@" +#define TS_BUILD_LIBDIR "@rel_libdir@" +#define TS_BUILD_LIBEXECDIR "@rel_libexecdir@" +#define TS_BUILD_LOCALSTATEDIR "@rel_localstatedir@" +#define TS_BUILD_RUNTIMEDIR "@rel_runtimedir@" +#define TS_BUILD_LOGDIR "@rel_logdir@" +#define TS_BUILD_MANDIR "@rel_mandir@" +#define TS_BUILD_CACHEDIR "@rel_cachedir@" +#define TS_BUILD_INFODIR "@rel_infodir@" + +#define TS_BUILD_DEFAULT_LOOPBACK_IFACE "@default_loopback_iface@" + +#endif /* _ink_config_h */ diff --git a/lib/ts/ink_defs.cc b/lib/ts/ink_defs.cc new file mode 100644 index 00000000..029f4214 --- /dev/null +++ b/lib/ts/ink_defs.cc @@ -0,0 +1,107 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_defs.h + Some small general interest definitions + + ****************************************************************************/ + +#include "libts.h" +#include "ink_unused.h" +#include "ink_platform.h" +#if defined(linux) || defined(freebsd) || defined(darwin) +#include +#include +#include +#endif +#if defined(linux) +#include +#endif /* MAGIC_EDITING_TAG */ + +int off = 0; +int on = 1; + +int +ink_sys_name_release(char *name, int namelen, char *release, int releaselen) +{ + *name = 0; + *release = 0; +#if defined(freebsd) || defined(darwin) + int mib[2]; + size_t len = namelen; + mib[0] = CTL_KERN; + mib[1] = KERN_OSTYPE; + + if (sysctl(mib, 2, name, &len, NULL, 0) == -1) + return -1; + + len = releaselen; + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELEASE; + + if (sysctl(mib, 2, release, &len, NULL, 0) == -1) + return -1; + + return 0; +#elif defined(linux) + struct utsname buf; + int n; + + if (uname(&buf)) + return -1; + + n = strlen(buf.sysname); + if (namelen <= n) + n = namelen - 1; + memcpy(name, buf.sysname, n); + name[n] = 0; + + n = strlen(buf.release); + if (releaselen <= n) + n = releaselen - 1; + memcpy(release, buf.release, n); + release[n] = 0; + + return 0; +#else + return -1; +#endif +} + +int +ink_number_of_processors() +{ +#if defined(freebsd) + int mib[2], n; + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + size_t len = sizeof(n); + if (sysctl(mib, 2, &n, &len, NULL, 0) == -1) + return 1; + return n; +#else + return sysconf(_SC_NPROCESSORS_ONLN); // number of Net threads +#endif +} diff --git a/lib/ts/ink_defs.h b/lib/ts/ink_defs.h new file mode 100644 index 00000000..f23f77a6 --- /dev/null +++ b/lib/ts/ink_defs.h @@ -0,0 +1,94 @@ +/** @file + + Some small general interest definitions + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_defs_h +#define _ink_defs_h + +/* Defines +*/ +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) +#define ON ((char*)&on) +#define OFF ((char*)&off) +#ifndef ABS +#define ABS(_x_) (((_x_) < 0) ? ( - (_x_)) : (_x_)) +#endif + +/* Debugging +*/ +#ifdef NDEBUG + +#define FDBG +#define DBG(s) +#define DBG1(s,a) +#define DBG2(s,a1,a2) +#define DBG3(s,a1,a2,a3) +#define DBG4(s,a1,a2,a3,a4) + +#else + +#define FDBG if (debug_level==1) printf("debug "__FILE__":%d %s : entered\n" ,__LINE__,__FUNCTION__) +#define DBG(s) if (debug_level==1) printf("debug "__FILE__":%d %s :" s ,__LINE__,__FUNCTION__) +#define DBG1(s,a) if (debug_level==1) printf("debug "__FILE__":%d %s :" s ,__LINE__,__FUNCTION__, a) +#define DBG2(s,a1,a2) if (debug_level==1) printf("debug "__FILE__":%d %s :" s ,__LINE__,__FUNCTION__, a1,a2) +#define DBG3(s,a1,a2,a3) if (debug_level==1) printf("debug "__FILE__":%d %s :" s ,__LINE__,__FUNCTION__, a1,a2,a3) +#define DBG4(s,a1,a2,a3,a4) if (debug_level==1) printf("debug "__FILE__":%d %s :" s ,__LINE__,__FUNCTION__, a1,a2,a3,a4) + +#endif + +/* Types +*/ +typedef void *(*VPVP_PFN) (void *); +typedef void (*VVP_PFN) (void *); +typedef void (*VV_PFN) (void); +typedef void (*VI_PFN) (int); + +/* Compiler Hints + */ +#define NOWARN_UNUSED(x) (void)(x) +#define NOWARN_UNUSED_RETURN(x) if (x) {} +#ifdef __GNUC__ +/* Enable this to get printf() style warnings on the Inktomi functions. */ +/* #define PRINTFLIKE(IDX, FIRST) __attribute__((format (printf, IDX, FIRST))) */ +#define PRINTFLIKE(IDX, FIRST) +#else +#define PRINTFLIKE(IDX, FIRST) +#endif + +/* Variables +*/ +extern int debug_level; +extern int off; +extern int on; + +/* Functions +*/ +int ink_sys_name_release(char *name, int namelen, char *release, int releaselen); +int ink_number_of_processors(); + +/** Constants. + */ +namespace ts { + static const int NO_FD = -1; ///< No or invalid file descriptor. +} + +#endif /*__ink_defs_h*/ diff --git a/lib/ts/ink_error.cc b/lib/ts/ink_error.cc new file mode 100644 index 00000000..7b4bf846 --- /dev/null +++ b/lib/ts/ink_error.cc @@ -0,0 +1,258 @@ +/** @file + + Error reporting routines + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#include "libts.h" +#include "ink_error.h" +#include "ink_stack_trace.h" + +#include +#include /* MAGIC_EDITING_TAG */ + +static int ink_dprintf_level = 0; + +/** + This routine causes process death. Some signal handler problems got + in the way of abort before, so this is an overzealous and somewhat + amusing implementation. + +*/ +void +ink_die_die_die(int retval) +{ + abort(); + _exit(retval); + exit(retval); +} + +/** + This routine prints/logs an error message given the printf format + string in message_format, and the optional arguments. The program is + then terminated with return_code. + +*/ +void +ink_fatal_va(int return_code, const char *message_format, va_list ap) +{ + char extended_format[4096], message[4096]; + snprintf(extended_format, sizeof(extended_format) - 1, "FATAL: %s", message_format); + extended_format[sizeof(extended_format) - 1] = 0; + vsnprintf(message, sizeof(message) - 1, extended_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + syslog(LOG_CRIT, "%s", message); + ink_stack_trace_dump(); + ink_die_die_die(return_code); +} + +void +ink_fatal(int return_code, const char *message_format, ...) +{ + va_list ap; + va_start(ap, message_format); + ink_fatal_va(return_code, message_format, ap); + va_end(ap); +} + +void +ink_fatal_die(const char *message_format, ...) +{ + va_list ap; + va_start(ap, message_format); + ink_fatal_va(1, message_format, ap); + va_end(ap); +} + +/** + This routine prints/logs an error message given the printf format + string in message_format, and the optional arguments. The current + errno is also printed. The program is then terminated with return_code. + +*/ +void +ink_pfatal(int return_code, const char *message_format, ...) +{ + va_list ap; + char extended_format[4096], message[4096]; + + char *errno_string; + + va_start(ap, message_format); + errno_string = strerror(errno); + snprintf(extended_format, sizeof(extended_format) - 1, "FATAL: %s ", + message_format, errno, (errno_string == NULL ? "unknown" : errno_string)); + extended_format[sizeof(extended_format) - 1] = 0; + vsnprintf(message, sizeof(message) - 1, extended_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + syslog(LOG_CRIT, "%s", message); + va_end(ap); + ink_stack_trace_dump(); + ink_die_die_die(return_code); +} + +/** + This routine prints/logs a warning message given the printf format + string in message_format, and the optional arguments. + +*/ +void +ink_warning(const char *message_format, ...) +{ + va_list ap; + char extended_format[4096], message[4096]; + va_start(ap, message_format); + snprintf(extended_format, sizeof(extended_format) - 1, "WARNING: %s", message_format); + extended_format[sizeof(extended_format) - 1] = 0; + vsnprintf(message, sizeof(message) - 1, extended_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + syslog(LOG_WARNING, "%s", message); + va_end(ap); +} + +/** + This routine prints/logs a warning message given the printf format + string in message_format, and the optional arguments. The current + errno is also printed. + +*/ +void +ink_pwarning(const char *message_format, ...) +{ + va_list ap; + char extended_format[4096], message[4096]; + char *errno_string; + + va_start(ap, message_format); + errno_string = strerror(errno); + snprintf(extended_format, sizeof(extended_format) - 1, "WARNING: %s ", + message_format, errno, (errno_string == NULL ? "unknown" : errno_string)); + extended_format[sizeof(extended_format) - 1] = 0; + vsnprintf(message, sizeof(message) - 1, extended_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + syslog(LOG_WARNING, "%s", message); + va_end(ap); +} + +/** + This routine prints/logs a notice message given the printf format + string in message_format, and the optional arguments. + +*/ +void +ink_notice(const char *message_format, ...) +{ + va_list ap; + char extended_format[4096], message[4096]; + va_start(ap, message_format); + snprintf(extended_format, sizeof(extended_format) - 1, "NOTE: %s", message_format); + extended_format[sizeof(extended_format) - 1] = 0; + vsnprintf(message, sizeof(message) - 1, extended_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + syslog(LOG_NOTICE, "%s", message); + va_end(ap); +} + +/** + This routine prints/logs a message given the printf format string in + message_format, and the optional arguments. + +*/ +void +ink_eprintf(const char *message_format, ...) +{ + va_list ap; + char message[4096]; + va_start(ap, message_format); + vsnprintf(message, sizeof(message) - 1, message_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "ERROR: %s\n", message); + va_end(ap); +} + +/** + This routine prints/logs a warning message given the printf format + string in message_format, and the optional arguments. + +*/ +void +ink_error(const char *message_format, ...) +{ + va_list ap; + char extended_format[2048], message[4096]; + va_start(ap, message_format); + snprintf(extended_format, sizeof(extended_format) - 1, "ERROR: %s", message_format); + extended_format[sizeof(extended_format) - 1] = 0; + vsnprintf(message, sizeof(message) - 1, extended_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + syslog(LOG_ERR, "%s", message); + va_end(ap); +} + +/** + This routine prints/logs a message given the printf format string in + message_format, and the optional arguments. + +*/ +void +ink_dprintf(int debug_level, const char *message_format, ...) +{ + char message[4096]; + va_list ap; + if (debug_level <= ink_dprintf_level) { + va_start(ap, message_format); + vsnprintf(message, sizeof(message) - 1, message_format, ap); + message[sizeof(message) - 1] = 0; + fprintf(stderr, "%s\n", message); + va_end(ap); + } +} + +/** + Set output level for ink_dprintf() function. For debugging purposes + only! + +*/ +int +ink_set_dprintf_level(int debug_level) +{ + int old_ink_dprintf_level = ink_dprintf_level; + if ((ink_dprintf_level = debug_level) < 0) + ink_dprintf_level = 0; + return old_ink_dprintf_level; +} + +/** + Initiates a SEGV the old-fashioned way, it earns it. + +*/ +void +ink_segv() +{ + char *addr = NULL; + *addr = 0; +} diff --git a/lib/ts/ink_error.h b/lib/ts/ink_error.h new file mode 100644 index 00000000..2fde48e4 --- /dev/null +++ b/lib/ts/ink_error.h @@ -0,0 +1,64 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_error.h + + Error reporting routines for libts + + ****************************************************************************/ + +#ifndef _ink_error_h_ +#define _ink_error_h_ + +#include +#include "ink_platform.h" + +#include "ink_apidefs.h" +#include "ink_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +inkcoreapi void ink_fatal_va(int return_code, const char *message_format, va_list ap); +void ink_fatal(int return_code, const char *message_format, ...) PRINTFLIKE(2, 3); +void ink_pfatal(int return_code, const char *message_format, ...) PRINTFLIKE(2, 3); +void ink_warning(const char *message_format, ...) PRINTFLIKE(1, 2); +void ink_pwarning(const char *message_format, ...) PRINTFLIKE(1, 2); +void ink_notice(const char *message_format, ...) PRINTFLIKE(1, 2); +void ink_eprintf(const char *message_format, ...) PRINTFLIKE(1, 2); +void ink_error(const char *message_format, ...) PRINTFLIKE(1, 2); +void ink_dprintf(int debug_level, const char *message_format, ...) PRINTFLIKE(2, 3); +void ink_fatal_die(const char *message_format, ...) PRINTFLIKE(1, 2); + +void ink_die_die_die(int retval); +void ink_segv(); +int ink_set_dprintf_level(int debug_level); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/lib/ts/ink_exception.h b/lib/ts/ink_exception.h new file mode 100644 index 00000000..85b5d126 --- /dev/null +++ b/lib/ts/ink_exception.h @@ -0,0 +1,71 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * ink_exception.h + * + * Contains some global exception classes. + * + * $Date: 2003-06-01 18:36:43 $ + * + * + */ + + +class Exception +{ +}; + +class OSException:public Exception +{ +}; + +class IOException:public OSException +{ +}; + +class FileOpenException:public IOException +{ +}; +class FileStatException:public IOException +{ +}; +class FileSeekException:public IOException +{ +}; +class FileReadException:public IOException +{ +}; +class FileWriteException:public IOException +{ +}; +class FileCloseException:public IOException +{ +}; + +class MemoryMapException:public OSException +{ +}; +class MemoryUnmapException:public OSException +{ +}; diff --git a/lib/ts/ink_file.cc b/lib/ts/ink_file.cc new file mode 100644 index 00000000..9ae7e8e4 --- /dev/null +++ b/lib/ts/ink_file.cc @@ -0,0 +1,341 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_file.c + + File manipulation routines for libts + + ****************************************************************************/ + +#include "libts.h" + + +int +ink_fputln(FILE * stream, const char *s) +{ + if (stream && s) { + int rc = fputs(s, stream); + if (rc > 0) + rc += fputc('\n', stream); + return rc; + } + else + return -EINVAL; +} /* End ink_fgets */ + +/*---------------------------------------------------------------------------* + + int ink_file_fd_readline(int fd, int bufsz, char *buf) + + This routine reads bytes from into the buffer pointed to by . + The reading stops when (a) a LF is read into the buffer, (b) the end of + file is reached, or (c) - 1 bytes are read. The parameter + must be >= 2. + + The data pointed to by is always NUL terminated, and the LF is + left in the data. This routine can be used as a replacement for + fgets-like functions. If the is too small to hold a complete line, + the partial line will be stored, and subsequent reads will read more data. + + This routine returns the number of bytes read, 0 on end of file, or + a negative errno on error. + + *---------------------------------------------------------------------------*/ + +int +ink_file_fd_readline(int fd, int bufsz, char *buf) +{ + char c; + int i = 0; + + if (bufsz < 2) + return (-EINVAL); /* bufsz must by >= 2 */ + + while (i < bufsz - 1) { /* leave 1 byte for NUL */ + int n = read(fd, &c, 1); /* read 1 byte */ + if (n == 0) + break; /* EOF */ + if (n < 0) + return (n); /* error */ + buf[i++] = c; /* store in buffer */ + if (c == '\n') + break; /* stop if stored a LF */ + } + + buf[i] = '\0'; /* NUL terminate buffer */ + return (i); /* number of bytes read */ +} /* End ink_file_fd_readline */ + +/* Write until NUL */ +int +ink_file_fd_writestring(int fd, const char *buf) +{ + int len, i = 0; + + if (buf && (len = strlen(buf)) > 0 && (i = (int) write(fd, buf, (size_t) len) != len)) + i = -1; + + return i; /* return chars written */ +} /* End ink_file_fd_writestring */ + +int +ink_filepath_merge(char *path, int pathsz, const char *rootpath, + const char *addpath, int flags) +{ + size_t rootlen; // is the length of the src rootpath + size_t maxlen; // maximum total path length + size_t keptlen; // is the length of the retained rootpath + size_t pathlen; // is the length of the result path + size_t seglen; // is the end of the current segment + char curdir[PATH_MAX]; + + /* Treat null as an empty path. + */ + if (!addpath) + addpath = ""; + + if (addpath[0] == '/') { + // If addpath is rooted, then rootpath is unused. + // Ths violates any INK_FILEPATH_SECUREROOTTEST and + // INK_FILEPATH_NOTABSOLUTE flags specified. + // + if (flags & INK_FILEPATH_SECUREROOTTEST) + return EACCES; // APR_EABOVEROOT; + if (flags & INK_FILEPATH_NOTABSOLUTE) + return EISDIR; // APR_EABSOLUTE; + + // If INK_FILEPATH_NOTABOVEROOT wasn't specified, + // we won't test the root again, it's ignored. + // Waste no CPU retrieving the working path. + // + if (!rootpath && !(flags & INK_FILEPATH_NOTABOVEROOT)) + rootpath = ""; + } + else { + // If INK_FILEPATH_NOTABSOLUTE is specified, the caller + // requires a relative result. If the rootpath is + // ommitted, we do not retrieve the working path, + // if rootpath was supplied as absolute then fail. + // + if (flags & INK_FILEPATH_NOTABSOLUTE) { + if (!rootpath) + rootpath = ""; + else if (rootpath[0] == '/') + return EISDIR; //APR_EABSOLUTE; + } + } + if (!rootpath) { + // Start with the current working path. This is bass akwards, + // but required since the compiler (at least vc) doesn't like + // passing the address of a char const* for a char** arg. + // + if (!getcwd(curdir, sizeof(curdir))) { + return errno; + } + rootpath = curdir; + } + rootlen = strlen(rootpath); + maxlen = rootlen + strlen(addpath) + 4; // 4 for slashes at start, after + // root, and at end, plus trailing + // null + if (maxlen > (size_t)pathsz) { + return E2BIG; //APR_ENAMETOOLONG; + } + if (addpath[0] == '/') { + // Ignore the given root path, strip off leading + // '/'s to a single leading '/' from the addpath, + // and leave addpath at the first non-'/' character. + // + keptlen = 0; + while (addpath[0] == '/') + ++addpath; + path[0] = '/'; + pathlen = 1; + } + else { + // If both paths are relative, fail early + // + if (rootpath[0] != '/' && (flags & INK_FILEPATH_NOTRELATIVE)) + return EBADF; //APR_ERELATIVE; + + // Base the result path on the rootpath + // + keptlen = rootlen; + memcpy(path, rootpath, rootlen); + + // Always '/' terminate the given root path + // + if (keptlen && path[keptlen - 1] != '/') { + path[keptlen++] = '/'; + } + pathlen = keptlen; + } + + while (*addpath) { + // Parse each segment, find the closing '/' + // + const char *next = addpath; + while (*next && (*next != '/')) { + ++next; + } + seglen = next - addpath; + + if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) { + // noop segment (/ or ./) so skip it + // + } + else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') { + // backpath (../) + if (pathlen == 1 && path[0] == '/') { + // Attempt to move above root. Always die if the + // INK_FILEPATH_SECUREROOTTEST flag is specified. + // + if (flags & INK_FILEPATH_SECUREROOTTEST) { + return EACCES; //APR_EABOVEROOT; + } + + // Otherwise this is simply a noop, above root is root. + // Flag that rootpath was entirely replaced. + // + keptlen = 0; + } + else if (pathlen == 0 + || (pathlen == 3 + && !memcmp(path + pathlen - 3, "../", 3)) + || (pathlen > 3 + && !memcmp(path + pathlen - 4, "/../", 4))) { + // Path is already backpathed or empty, if the + // INK_FILEPATH_SECUREROOTTEST.was given die now. + // + if (flags & INK_FILEPATH_SECUREROOTTEST) { + return EACCES; //APR_EABOVEROOT; + } + + // Otherwise append another backpath, including + // trailing slash if present. + // + memcpy(path + pathlen, "../", *next ? 3 : 2); + pathlen += *next ? 3 : 2; + } + else { + // otherwise crop the prior segment + // + do { + --pathlen; + } while (pathlen && path[pathlen - 1] != '/'); + } + + // Now test if we are above where we started and back up + // the keptlen offset to reflect the added/altered path. + // + if (pathlen < keptlen) { + if (flags & INK_FILEPATH_SECUREROOTTEST) { + return EACCES; //APR_EABOVEROOT; + } + keptlen = pathlen; + } + } + else { + // An actual segment, append it to the destination path + // + if (*next) { + seglen++; + } + memcpy(path + pathlen, addpath, seglen); + pathlen += seglen; + } + + // Skip over trailing slash to the next segment + // + if (*next) { + ++next; + } + + addpath = next; + } + path[pathlen] = '\0'; + if (pathlen > 1 && path[pathlen - 1] == '/') { + // Trim trailing slash unless requested + size_t es = strlen(addpath); + if (es == 0 || addpath[es - 1] != '/') { + --pathlen; + path[pathlen] = '\0'; + } + } + + // keptlen will be the rootlen unless the addpath contained + // backpath elements. If so, and INK_FILEPATH_NOTABOVEROOT + // is specified (INK_FILEPATH_SECUREROOTTEST was caught above), + // compare the original root to assure the result path is + // still within given root path. + // + if ((flags & INK_FILEPATH_NOTABOVEROOT) && keptlen < rootlen) { + if (strncmp(rootpath, path, rootlen)) { + return EACCES; //APR_EABOVEROOT; + } + if (rootpath[rootlen - 1] != '/' + && path[rootlen] && path[rootlen] != '/') { + return EACCES; //APR_EABOVEROOT; + } + } + + return 0; +} + +int +ink_filepath_make(char *path, int pathsz, const char *rootpath, + const char *addpath) +{ + size_t rootlen; // is the length of the src rootpath + size_t maxlen; // maximum total path length + + /* Treat null as an empty path. + */ + if (!addpath) + addpath = ""; + + if (addpath[0] == '/') { + // If addpath is rooted, then rootpath is unused. + ink_strncpy(path, addpath, pathsz); + return 0; + } + if (!rootpath || !*rootpath) { + // If there's no rootpath return the addpath + ink_strncpy(path, addpath, pathsz); + return 0; + } + rootlen = strlen(rootpath); + maxlen = strlen(addpath) + 2; + if (maxlen > (size_t)pathsz) { + *path = '\0'; + return (int)maxlen; + } + strcpy(path, rootpath); + path += rootlen; + if (*(path - 1) != '/') + *(path++) = '/'; + strcpy(path, addpath); + return 0; +} diff --git a/lib/ts/ink_file.h b/lib/ts/ink_file.h new file mode 100644 index 00000000..0f6e5014 --- /dev/null +++ b/lib/ts/ink_file.h @@ -0,0 +1,82 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_file.h + + File manipulation routines for libts + + ****************************************************************************/ + +#ifndef _ink_file_h_ +#define _ink_file_h_ + +#include +#include + +/*===========================================================================* + + Function Prototypes + + *===========================================================================*/ + +#include + +// Cause ink_filepath_merge to fail if addpath is above rootpath +// +#define INK_FILEPATH_NOTABOVEROOT 0x01 +// internal: Only meaningful with INK_FILEPATH_NOTABOVEROOT +#define INK_FILEPATH_SECUREROOTTEST 0x02 +// Cause ink_filepath_merge to fail if addpath is above rootpath, +// even given a rootpath /foo/bar and an addpath ../bar/bash +// +#define INK_FILEPATH_SECUREROOT 0x03 +// Fail ink_filepath_merge if the merged path is relative +#define INK_FILEPATH_NOTRELATIVE 0x04 +// Fail ink_filepath_merge if the merged path is absolute +#define INK_FILEPATH_NOTABSOLUTE 0x08 +// Return the file system's native path format (e.g. path delimiters +// of ':' on MacOS9, '\' on Win32, etc.) +#define INK_FILEPATH_NATIVE 0x10 +// Resolve the true case of existing directories and file elements +// of addpath, (resolving any aliases on Win32) and append a proper +// trailing slash if a directory +// +#define INK_FILEPATH_TRUENAME 0x20 + +int ink_fputln(FILE *stream, const char *s); +int ink_file_fd_readline(int fd, int bufsize, char *buf); +int ink_file_fd_writestring(int fd, const char *buf); +int ink_filepath_merge(char *buf, int bufsz, const char *rootpath, + const char *addpath, int flags = INK_FILEPATH_TRUENAME); +/** + Add addpath to the rootpath prepending slash if rootpath + is not NULL and doesn't end with the slash already and put the + result into path buffer. If the buffer is too small to hold the + resulting string, required size is returned. On success zero is returned + */ +int ink_filepath_make(char *path, int pathsz, const char *rootpath, + const char *addpath); + +#endif // _ink_file_h_ diff --git a/lib/ts/ink_hash_table.cc b/lib/ts/ink_hash_table.cc new file mode 100644 index 00000000..00b3b1e4 --- /dev/null +++ b/lib/ts/ink_hash_table.cc @@ -0,0 +1,461 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_hash_table.c + + This file implements hash tables. This allows us to provide alternative + implementations of hash tables. + + ****************************************************************************/ + +#include "ink_error.h" +#include "ink_hash_table.h" +#include "ink_memory.h" +#include "ink_resource.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +/*===========================================================================* + + This is the Tcl implementation of InkHashTable + + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + + InkHashTable *ink_hash_table_create(InkHashTableKeyType key_type) + + This routine allocates an initializes an empty InkHashTable, and returns a + pointer to the new table. The argument indicates whether keys + are represented as strings, or as words. Legal values are + InkHashTableKeyType_String and InkHashTableKeyType_Word. + + *---------------------------------------------------------------------------*/ + +InkHashTable * +ink_hash_table_create(InkHashTableKeyType key_type) +{ + InkHashTable *ht_ptr; + Tcl_HashTable *tcl_ht_ptr; + int tcl_key_type; + + tcl_ht_ptr = ink_type_malloc(Tcl_HashTable); + + tcl_key_type = -1; + if (key_type == InkHashTableKeyType_String) + tcl_key_type = TCL_STRING_KEYS; + else if (key_type == InkHashTableKeyType_Word) + tcl_key_type = TCL_ONE_WORD_KEYS; + else + ink_fatal(1, "ink_hash_table_create: bad key_type %d", key_type); + + Tcl_InitHashTable(tcl_ht_ptr, tcl_key_type); + + ht_ptr = (InkHashTable *) tcl_ht_ptr; + return (ht_ptr); +} /* End ink_hash_table_create */ + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_destroy(InkHashTable *ht_ptr) + + This routine takes a hash table , and frees its storage. + + *---------------------------------------------------------------------------*/ + +InkHashTable * +ink_hash_table_destroy(InkHashTable * ht_ptr) +{ + Tcl_HashTable *tcl_ht_ptr; + + tcl_ht_ptr = (Tcl_HashTable *) ht_ptr; + Tcl_DeleteHashTable(tcl_ht_ptr); + ink_free(tcl_ht_ptr); + return (InkHashTable *) 0; +} /* End ink_hash_table_destroy */ + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_destroy_and_free_values(InkHashTable *ht_ptr) + + This routine takes a hash table , and frees its storage, after + first calling ink_free on all the values. You better darn well make sure the + values have been dynamically allocated. + + *---------------------------------------------------------------------------*/ + +static int +_ink_hash_table_free_entry_value(InkHashTable * ht_ptr, InkHashTableEntry * e) +{ + InkHashTableValue value; + + value = ink_hash_table_entry_value(ht_ptr, e); + if (value != NULL) { + ink_free(value); + } + + return (0); +} /* End _ink_hash_table_free_entry_value */ + + +static int +_ink_hash_table_xfree_entry_value(InkHashTable * ht_ptr, InkHashTableEntry * e) +{ + InkHashTableValue value; + + value = ink_hash_table_entry_value(ht_ptr, e); + if (value != NULL) { + xfree(value); + } + + return (0); +} /* End _ink_hash_table_xfree_entry_value */ + +InkHashTable * +ink_hash_table_destroy_and_free_values(InkHashTable * ht_ptr) +{ + ink_hash_table_map(ht_ptr, _ink_hash_table_free_entry_value); + ink_hash_table_destroy(ht_ptr); + return (InkHashTable *) 0; +} /* End ink_hash_table_destroy_and_free_values */ + +InkHashTable * +ink_hash_table_destroy_and_xfree_values(InkHashTable * ht_ptr) +{ + ink_hash_table_map(ht_ptr, _ink_hash_table_xfree_entry_value); + ink_hash_table_destroy(ht_ptr); + return (InkHashTable *) 0; +} /* End ink_hash_table_destroy_and_xfree_values */ + + +/*---------------------------------------------------------------------------* + + int ink_hash_table_isbound(InkHashTable *ht_ptr, InkHashTableKey key) + + This routine takes a hash table , a key , and returns 1 + if the value is bound in the hash table, 0 otherwise. + + *---------------------------------------------------------------------------*/ + +int +ink_hash_table_isbound(InkHashTable * ht_ptr, const char *key) +{ + InkHashTableEntry *he_ptr; + + he_ptr = ink_hash_table_lookup_entry(ht_ptr, key); + return ((he_ptr == NULL) ? 0 : 1); +} /* End ink_hash_table_isbound */ + + +/*---------------------------------------------------------------------------* + int ink_hash_table_lookup(InkHashTable *ht_ptr, + InkHashTableKey key, + InkHashTableValue *value_ptr) + + This routine takes a hash table , a key , and stores the + value bound to the key by reference through . If no binding is + found, 0 is returned, else 1 is returned. + + *---------------------------------------------------------------------------*/ + +int +ink_hash_table_lookup(InkHashTable *ht_ptr, const char* key, InkHashTableValue *value_ptr) +{ + InkHashTableEntry *he_ptr; + InkHashTableValue value; + + he_ptr = ink_hash_table_lookup_entry(ht_ptr, key); + if (he_ptr == NULL) + return (0); + + value = ink_hash_table_entry_value(ht_ptr, he_ptr); + *value_ptr = value; + return (1); +} /* End ink_hash_table_lookup */ + + +/*---------------------------------------------------------------------------* + + int ink_hash_table_delete(InkHashTable *ht_ptr, InkHashTableKey key) + + This routine takes a hash table and a key , and deletes the + binding for the in the hash table if it exists. This routine + returns 1 if the key existed, else 0. + + *---------------------------------------------------------------------------*/ + +int +ink_hash_table_delete(InkHashTable * ht_ptr, const char *key) +{ + char *tcl_key; + Tcl_HashTable *tcl_ht_ptr; + Tcl_HashEntry *tcl_he_ptr; + + tcl_key = (char *) key; + tcl_ht_ptr = (Tcl_HashTable *) ht_ptr; + tcl_he_ptr = Tcl_FindHashEntry(tcl_ht_ptr, tcl_key); + + if (!tcl_he_ptr) + return (0); + Tcl_DeleteHashEntry(tcl_he_ptr); + + return (1); +} /* End ink_hash_table_delete */ + + +/*---------------------------------------------------------------------------* + + InkHashTableEntry *ink_hash_table_lookup_entry(InkHashTable *ht_ptr, + InkHashTableKey key) + + This routine takes a hash table and a key , and returns the + entry matching the key, or NULL otherwise. + + *---------------------------------------------------------------------------*/ + +InkHashTableEntry * +ink_hash_table_lookup_entry(InkHashTable * ht_ptr, const char* key) +{ + Tcl_HashTable *tcl_ht_ptr; + Tcl_HashEntry *tcl_he_ptr; + InkHashTableEntry *he_ptr; + + tcl_ht_ptr = (Tcl_HashTable *) ht_ptr; + tcl_he_ptr = Tcl_FindHashEntry(tcl_ht_ptr, key); + he_ptr = (InkHashTableEntry *) tcl_he_ptr; + + return (he_ptr); +} /* End ink_hash_table_lookup_entry */ + + +/*---------------------------------------------------------------------------* + + InkHashTableEntry *ink_hash_table_get_entry(InkHashTable *ht_ptr, + InkHashTableKey key, + int *new_value) + + This routine takes a hash table and a key , and returns the + entry matching the key, or creates, binds, and returns a new entry. + If the binding already existed, *new is set to 0, else 1. + + *---------------------------------------------------------------------------*/ + +InkHashTableEntry * +ink_hash_table_get_entry(InkHashTable *ht_ptr, const char *key, int *new_value) +{ + Tcl_HashTable *tcl_ht_ptr; + Tcl_HashEntry *tcl_he_ptr; + + tcl_ht_ptr = (Tcl_HashTable *) ht_ptr; + tcl_he_ptr = Tcl_CreateHashEntry(tcl_ht_ptr, key, new_value); + + if (tcl_he_ptr == NULL) { + ink_fatal(1, "%s: Tcl_CreateHashEntry returned NULL", "ink_hash_table_get_entry"); + } + + return ((InkHashTableEntry *) tcl_he_ptr); +} /* End ink_hash_table_get_entry */ + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_set_entry(InkHashTable *ht_ptr, + InkHashTableEntry *he_ptr, + InkHashTableValue value) + + This routine takes a hash table , a hash table entry , + and changes the value field of the entry to . + + *---------------------------------------------------------------------------*/ + +void +ink_hash_table_set_entry(InkHashTable * ht_ptr, InkHashTableEntry * he_ptr, InkHashTableValue value) +{ + (void) ht_ptr; + ClientData tcl_value; + Tcl_HashEntry *tcl_he_ptr; + + tcl_value = (ClientData) value; + tcl_he_ptr = (Tcl_HashEntry *) he_ptr; + Tcl_SetHashValue(tcl_he_ptr, tcl_value); +} /* End ink_hash_table_set_entry */ + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_insert(InkHashTable *ht_ptr, + InkHashTableKey key, + InkHashTableValue value) + + This routine takes a hash table , a key , and binds the value + to the key, replacing any previous binding, if any. + + *---------------------------------------------------------------------------*/ + +void +ink_hash_table_insert(InkHashTable * ht_ptr, const char *key, InkHashTableValue value) +{ + int new_value; + InkHashTableEntry *he_ptr; + + he_ptr = ink_hash_table_get_entry(ht_ptr, key, &new_value); + ink_hash_table_set_entry(ht_ptr, he_ptr, value); +} /* End ink_hash_table_insert */ + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_map(InkHashTable *ht_ptr, InkHashTableEntryFunction map) + + This routine takes a hash table and a function pointer , and + applies the function to each entry in the hash table. The function + should return 0 normally, otherwise the iteration will stop. + + *---------------------------------------------------------------------------*/ + +void +ink_hash_table_map(InkHashTable * ht_ptr, InkHashTableEntryFunction map) +{ + int retcode; + InkHashTableEntry *e; + InkHashTableIteratorState state; + + for (e = ink_hash_table_iterator_first(ht_ptr, &state); e != NULL; e = ink_hash_table_iterator_next(ht_ptr, &state)) { + retcode = (*map) (ht_ptr, e); + if (retcode != 0) + break; + } +} /* End ink_hash_table_map */ + + +/*---------------------------------------------------------------------------* + + InkHashTableKey ink_hash_table_entry_key(InkHashTable *ht_ptr, + InkHashTableEntry *entry_ptr) + + This routine takes a hash table and a pointer to a hash table + entry , and returns the key portion of the entry. + + *---------------------------------------------------------------------------*/ + +InkHashTableKey +ink_hash_table_entry_key(InkHashTable * ht_ptr, InkHashTableEntry * entry_ptr) +{ + char *tcl_key; + + tcl_key = Tcl_GetHashKey((Tcl_HashTable *) ht_ptr, (Tcl_HashEntry *) entry_ptr); + return ((InkHashTableKey) tcl_key); +} /* End ink_hash_table_entry_key */ + + +/*---------------------------------------------------------------------------* + + InkHashTableValue ink_hash_table_entry_value(InkHashTable *ht_ptr, + InkHashTableEntry *entry_ptr) + + This routine takes a hash table and a pointer to a hash table + entry , and returns the value portion of the entry. + + *---------------------------------------------------------------------------*/ + +InkHashTableValue +ink_hash_table_entry_value(InkHashTable * ht_ptr, InkHashTableEntry * entry_ptr) +{ + (void) ht_ptr; + ClientData tcl_value; + + tcl_value = Tcl_GetHashValue((Tcl_HashEntry *) entry_ptr); + return ((InkHashTableValue) tcl_value); +} /* End ink_hash_table_entry_value */ + + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_dump_strings(InkHashTable *ht_ptr) + + This routine takes a hash table of string values, and dumps the keys and + string values to stdout. It is the caller's responsibility to ensure that + both the key and the value are NUL terminated strings. + + *---------------------------------------------------------------------------*/ + +static int +DumpStringEntry(InkHashTable * ht_ptr, InkHashTableEntry * e) +{ + InkHashTableKey key; + InkHashTableValue value; + + key = ink_hash_table_entry_key(ht_ptr, e); + value = ink_hash_table_entry_value(ht_ptr, e); + + fprintf(stderr, "key = '%s', value = '%s'\n", (char *) key, (char *) value); + + return (0); +} + + +void +ink_hash_table_dump_strings(InkHashTable * ht_ptr) +{ + ink_hash_table_map(ht_ptr, DumpStringEntry); +} /* End ink_hash_table_dump_strings */ + + +/*---------------------------------------------------------------------------* + + void ink_hash_table_replace_string(InkHashTable *ht_ptr, + char *string_key, char *string_value) + + This conveninece routine is intended for hash tables with keys of type + InkHashTableKeyType_String, and values being dynamically allocated strings. + This routine binds to a copy of , and any + previous bound value is deallocated. + + *---------------------------------------------------------------------------*/ + +void +ink_hash_table_replace_string(InkHashTable * ht_ptr, char *string_key, char *string_value) +{ + int new_value; + char *old_str; + InkHashTableEntry *he_ptr; + + /* + * The following line will flag a type-conversion warning on the + * DEC Alpha, but that message can be ignored, since we're + * still dealing with pointers, and we aren't loosing any bits. + */ + + he_ptr = ink_hash_table_get_entry(ht_ptr, (InkHashTableKey) string_key, &new_value); + if (new_value == 0) { + old_str = (char *) ink_hash_table_entry_value(ht_ptr, he_ptr); + if (old_str) + ink_free(old_str); + } + + ink_hash_table_set_entry(ht_ptr, he_ptr, (InkHashTableValue) (ink_duplicate_string(string_value))); +} /* End ink_hash_table_replace_string */ diff --git a/lib/ts/ink_hash_table.h b/lib/ts/ink_hash_table.h new file mode 100644 index 00000000..ec3dc56e --- /dev/null +++ b/lib/ts/ink_hash_table.h @@ -0,0 +1,149 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_hash_table.h + + This file implements hash tables. This allows us to provide alternative + implementations of hash tables. + + ****************************************************************************/ + +#ifndef _ink_hash_table_h_ +#define _ink_hash_table_h_ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ +#include "ink_apidefs.h" + +/*===========================================================================* + + This is the Tcl implementation of InkHashTable + + *===========================================================================*/ + +#include + + typedef Tcl_HashTable InkHashTable; + typedef Tcl_HashEntry InkHashTableEntry; + typedef char *InkHashTableKey; + typedef ClientData InkHashTableValue; + typedef Tcl_HashSearch InkHashTableIteratorState; + + typedef int (*InkHashTableEntryFunction) (InkHashTable * ht, InkHashTableEntry * entry); + + /* Types of InkHashTable Keys */ + + typedef enum + { InkHashTableKeyType_String, InkHashTableKeyType_Word } + InkHashTableKeyType; + +/*===========================================================================* + + Function Prototypes + + *===========================================================================*/ + + InkHashTable *ink_hash_table_create(InkHashTableKeyType key_type); + InkHashTable *ink_hash_table_destroy(InkHashTable * ht_ptr); + InkHashTable *ink_hash_table_destroy_and_free_values(InkHashTable * ht_ptr); + InkHashTable *ink_hash_table_destroy_and_xfree_values(InkHashTable * ht_ptr); + inkcoreapi int ink_hash_table_isbound(InkHashTable * ht_ptr, const char *key); + inkcoreapi int ink_hash_table_lookup(InkHashTable * ht_ptr, const char *key, InkHashTableValue * value_ptr); + inkcoreapi int ink_hash_table_delete(InkHashTable * ht_ptr, const char *key); + InkHashTableEntry *ink_hash_table_lookup_entry(InkHashTable * ht_ptr, const char *key); + InkHashTableEntry *ink_hash_table_get_entry(InkHashTable * ht_ptr, const char *key, int *new_value); + void ink_hash_table_set_entry(InkHashTable * ht_ptr, InkHashTableEntry * he_ptr, InkHashTableValue value); + inkcoreapi void ink_hash_table_insert(InkHashTable * ht_ptr, const char *key, InkHashTableValue value); + void ink_hash_table_map(InkHashTable * ht_ptr, InkHashTableEntryFunction map); + InkHashTableKey ink_hash_table_entry_key(InkHashTable * ht_ptr, InkHashTableEntry * entry_ptr); + inkcoreapi InkHashTableValue ink_hash_table_entry_value(InkHashTable * ht_ptr, InkHashTableEntry * entry_ptr); + void ink_hash_table_dump_strings(InkHashTable * ht_ptr); + void ink_hash_table_replace_string(InkHashTable * ht_ptr, InkHashTableKey key, char *str); + +/* inline functions declarations */ + +/*---------------------------------------------------------------------------* + + InkHashTableEntry *ink_hash_table_iterator_first + (InkHashTable *ht_ptr, InkHashTableIteratorState *state_ptr) + + This routine takes a hash table , creates some iterator state + stored through , and returns a pointer to the first hash table + entry. The iterator state is used by InkHashTableIteratorNext() to proceed + through the rest of the entries. + + *---------------------------------------------------------------------------*/ + + static inline InkHashTableEntry *ink_hash_table_iterator_first + (InkHashTable * ht_ptr, InkHashTableIteratorState * state_ptr) + { + Tcl_HashTable *tcl_ht_ptr; + Tcl_HashSearch *tcl_search_state_ptr; + Tcl_HashEntry *tcl_he_ptr; + InkHashTableEntry *he_ptr; + + tcl_ht_ptr = (Tcl_HashTable *) ht_ptr; + tcl_search_state_ptr = (Tcl_HashSearch *) state_ptr; + + tcl_he_ptr = Tcl_FirstHashEntry(tcl_ht_ptr, tcl_search_state_ptr); + he_ptr = (InkHashTableEntry *) tcl_he_ptr; + + return (he_ptr); + } /* End ink_hash_table_iterator_first */ + + +/*---------------------------------------------------------------------------* + + InkHashTableEntry *ink_hash_table_iterator_next(InkHashTable *ht_ptr, + InkHashTableIteratorState *state_ptr) + + This routine takes a hash table and a pointer to iterator state + initialized by a previous call to InkHashTableIteratorFirst(), and returns + a pointer to the next InkHashTableEntry, or NULL if no entries remain. + + *---------------------------------------------------------------------------*/ + + static inline InkHashTableEntry *ink_hash_table_iterator_next(InkHashTable * ht_ptr, + InkHashTableIteratorState * state_ptr) + { + (void) ht_ptr; + Tcl_HashSearch *tcl_search_state_ptr; + Tcl_HashEntry *tcl_he_ptr; + InkHashTableEntry *he_ptr; + + tcl_search_state_ptr = (Tcl_HashSearch *) state_ptr; + + tcl_he_ptr = Tcl_NextHashEntry(tcl_search_state_ptr); + he_ptr = (InkHashTableEntry *) tcl_he_ptr; + + return (he_ptr); + } /* End ink_hash_table_iterator_next */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* #ifndef _ink_hash_table_h_ */ diff --git a/lib/ts/ink_hrtime.cc b/lib/ts/ink_hrtime.cc new file mode 100644 index 00000000..06283072 --- /dev/null +++ b/lib/ts/ink_hrtime.cc @@ -0,0 +1,223 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + + ink_hrtime.cc + + This file contains code supporting the Inktomi high-resolution timer. +**************************************************************************/ + +#include "ink_hrtime.h" +#include "ink_assert.h" + +#if defined(freebsd) +#include +#include +#include +#endif +#include + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +char * +int64_to_str(char *buf, unsigned int buf_size, int64_t val, unsigned int *total_chars, unsigned int req_width, char pad_char) +{ + const unsigned int local_buf_size = 32; + char local_buf[local_buf_size]; + bool using_local_buffer = false; + bool negative = false; + char *out_buf; + + if (buf_size < 22) { + // int64_t may not fit in provided buffer, use the local one + out_buf = &local_buf[local_buf_size - 1]; + using_local_buffer = true; + } else { + out_buf = &buf[buf_size - 1]; + } + + unsigned int num_chars = 1; // includes eos + *out_buf-- = 0; + + if (val < 0) { + val = -val; + negative = true; + } + + if (val < 10) { + *out_buf-- = '0' + (char) val; + ++num_chars; + } else { + do { + *out_buf-- = (char) (val % 10) + '0'; + val /= 10; + ++num_chars; + } while (val); + } + + // pad with pad_char if needed + // + if (req_width) { + // add minus sign if padding character is not 0 + if (negative && pad_char != '0') { + *out_buf = '-'; + ++num_chars; + } else { + out_buf++; + } + if (req_width > buf_size) + req_width = buf_size; + unsigned int num_padding = 0; + if (req_width > num_chars) { + num_padding = req_width - num_chars; + switch (num_padding) { + case 3: + *--out_buf = pad_char; + case 2: + *--out_buf = pad_char; + case 1: + *--out_buf = pad_char; + break; + default: + for (unsigned int i = 0; i < num_padding; ++i, *--out_buf = pad_char); + } + num_chars += num_padding; + } + // add minus sign if padding character is 0 + if (negative && pad_char == '0') { + if (num_padding) { + *out_buf = '-'; // overwrite padding + } else { + *--out_buf = '-'; + ++num_chars; + } + } + } else if (negative) { + *out_buf = '-'; + ++num_chars; + } else { + out_buf++; + } + + if (using_local_buffer) { + if (num_chars <= buf_size) { + memcpy(buf, out_buf, num_chars); + out_buf = buf; + } else { + // data does not fit return NULL + out_buf = NULL; + } + } + + if (total_chars) + *total_chars = num_chars; + return out_buf; +} + + +int +squid_timestamp_to_buf(char *buf, unsigned int buf_size, long timestamp_sec, long timestamp_usec) +{ + int res; + const unsigned int tmp_buf_size = 32; + char tmp_buf[tmp_buf_size]; + + unsigned int num_chars_s; + char *ts_s = int64_to_str(tmp_buf, tmp_buf_size - 4, timestamp_sec, &num_chars_s, 0, '0'); + ink_debug_assert(ts_s); + + // convert milliseconds + // + tmp_buf[tmp_buf_size - 5] = '.'; + int ms = timestamp_usec / 1000; + unsigned int num_chars_ms; + char RELEASE_UNUSED *ts_ms = int64_to_str(&tmp_buf[tmp_buf_size - 4], 4, ms, &num_chars_ms, 4, '0'); + ink_debug_assert(ts_ms && num_chars_ms == 4); + + unsigned int chars_to_write = num_chars_s + 3; // no eos + + if (buf_size >= chars_to_write) { + memcpy(buf, ts_s, chars_to_write); + res = chars_to_write; + } else { + res = -((int) chars_to_write); + } + + return res; +} + +#ifdef USE_TIME_STAMP_COUNTER_HRTIME +uint32_t +init_hrtime_TCS() +{ + int freqlen = sizeof(hrtime_freq); + if (sysctlbyname("machdep.tsc_freq", &hrtime_freq, (size_t *) & freqlen, NULL, 0) < 0) { + perror("sysctl: machdep.tsc_freq"); + exit(1); + } + hrtime_freq_float = (double) 1000000000 / (double) hrtime_freq; + return hrtime_freq; +} + +double hrtime_freq_float = 0.5; // 500 Mhz +uint32_t hrtime_freq = init_hrtime_TCS(); +#endif + +#ifdef NEED_HRTIME_BASIS +timespec timespec_basis; +ink_hrtime hrtime_offset; +ink_hrtime hrtime_basis = init_hrtime_basis(); + +ink_hrtime +init_hrtime_basis() +{ + ink_hrtime t1, t2, b, now; + timespec ts; +#ifdef USE_TIME_STAMP_COUNTER_HRTIME + init_hrtime_TCS(); +#endif + do { + t1 = ink_get_hrtime_internal(); +#if TS_HAS_CLOCK_GETTIME + ink_assert(!clock_gettime(CLOCK_REALTIME, ×pec_basis)); +#else + { + struct timeval tnow; + ink_assert(!gettimeofday(&tnow, NULL)); + timespec_basis.tv_sec = tnow.tv_sec; + timespec_basis.tv_nsec = tnow.tv_usec * 1000; + } +#endif + t2 = ink_get_hrtime_internal(); + // accuracy must be at least 100 microseconds + } while (t2 - t1 > HRTIME_USECONDS(100)); + b = (t2 + t1) / 2; + now = ink_timespec_to_based_hrtime(×pec_basis); + ts = ink_based_hrtime_to_timespec(now); + ink_assert(ts.tv_sec == timespec_basis.tv_sec && ts.tv_nsec == timespec_basis.tv_nsec); + hrtime_offset = now - b; + hrtime_basis = b; + return b; +} +#endif diff --git a/lib/ts/ink_hrtime.h b/lib/ts/ink_hrtime.h new file mode 100644 index 00000000..08952ff2 --- /dev/null +++ b/lib/ts/ink_hrtime.h @@ -0,0 +1,331 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + + ink_hrtime.h + + This file contains code supporting the Inktomi high-resolution timer. +**************************************************************************/ + +#if !defined (_ink_hrtime_h_) +#define _ink_hrtime_h_ + +#include "ink_config.h" +#include "ink_assert.h" +#include "Compatability.h" + +int squid_timestamp_to_buf(char *buf, unsigned int buf_size, long timestamp_sec, long timestamp_usec); +char *int64_to_str(char *buf, unsigned int buf_size, int64_t val, unsigned int *total_chars, unsigned int req_width=0, char pad_char='0'); + +#ifdef NEED_HRTIME +#include +#include +#include +typedef int64_t ink_hrtime; +#else /* !defined (NEED_HRTIME) */ +#include +typedef hrtime_t ink_hrtime; +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// Time Stamp Counter +// +////////////////////////////////////////////////////////////////////////////// +#ifdef USE_TIME_STAMP_COUNTER_HRTIME +extern ink_hrtime init_hrtime_TSC(); +extern uint32_t hrtime_freq; +extern double hrtime_freq_float; +static inline ink_hrtime +hrtime_rdtsc() +{ + ink_hrtime rv; + asm volatile (".byte 0x0f, 0x31":"=A" (rv)); + return (rv); +} +static inline uint64_t +get_hrtime_rdtsc() +{ + // do it fixed point if you have better hardware support + return (uint64_t) (hrtime_freq_float * hrtime_rdtsc()); +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Factors to multiply units by to obtain coresponding ink_hrtime values. +// +////////////////////////////////////////////////////////////////////////////// + +#define HRTIME_FOREVER (10*HRTIME_DECADE) +#define HRTIME_DECADE (10*HRTIME_YEAR) +#define HRTIME_YEAR (365*HRTIME_DAY+HRTIME_DAY/4) +#define HRTIME_WEEK (7*HRTIME_DAY) +#define HRTIME_DAY (24*HRTIME_HOUR) +#define HRTIME_HOUR (60*HRTIME_MINUTE) +#define HRTIME_MINUTE (60*HRTIME_SECOND) +#define HRTIME_SECOND (1000*HRTIME_MSECOND) +#define HRTIME_MSECOND (1000*HRTIME_USECOND) +#define HRTIME_USECOND (1000*HRTIME_NSECOND) +#define HRTIME_NSECOND (1LL) + +#define HRTIME_APPROX_SECONDS(_x) ((_x)>>30) // off by 7.3% +#define HRTIME_APPROX_FACTOR (((float)(1<<30))/(((float)HRTIME_SECOND))) + +////////////////////////////////////////////////////////////////////////////// +// +// Map from units to ink_hrtime values +// +////////////////////////////////////////////////////////////////////////////// + +// simple macros + +#define HRTIME_YEARS(_x) ((_x)*HRTIME_YEAR) +#define HRTIME_WEEKS(_x) ((_x)*HRTIME_WEEK) +#define HRTIME_DAYS(_x) ((_x)*HRTIME_DAY) +#define HRTIME_HOURS(_x) ((_x)*HRTIME_HOUR) +#define HRTIME_MINUTES(_x) ((_x)*HRTIME_MINUTE) +#define HRTIME_SECONDS(_x) ((_x)*HRTIME_SECOND) +#define HRTIME_MSECONDS(_x) ((_x)*HRTIME_MSECOND) +#define HRTIME_USECONDS(_x) ((_x)*HRTIME_USECOND) +#define HRTIME_NSECONDS(_x) ((_x)*HRTIME_NSECOND) + +// gratuituous wrappers + +static inline ink_hrtime +ink_hrtime_from_years(unsigned int years) +{ + return (HRTIME_YEARS(years)); +} +static inline ink_hrtime +ink_hrtime_from_weeks(unsigned int weeks) +{ + return (HRTIME_WEEKS(weeks)); +} +static inline ink_hrtime +ink_hrtime_from_days(unsigned int days) +{ + return (HRTIME_DAYS(days)); +} +static inline ink_hrtime +ink_hrtime_from_mins(unsigned int mins) +{ + return (HRTIME_MINUTES(mins)); +} +static inline ink_hrtime +ink_hrtime_from_sec(unsigned int sec) +{ + return (HRTIME_SECONDS(sec)); +} +static inline ink_hrtime +ink_hrtime_from_msec(unsigned int msec) +{ + return (HRTIME_MSECONDS(msec)); +} +static inline ink_hrtime +ink_hrtime_from_usec(unsigned int usec) +{ + return (HRTIME_USECONDS(usec)); +} +static inline ink_hrtime +ink_hrtime_from_nsec(unsigned int nsec) +{ + return (HRTIME_NSECONDS(nsec)); +} + +static inline ink_hrtime +ink_hrtime_from_timeval(struct timeval *tv) +{ + int64_t usecs; + + usecs = tv->tv_sec * 1000000 + tv->tv_usec; + return (ink_hrtime_from_usec((unsigned int) usecs)); +} + +////////////////////////////////////////////////////////////////////////////// +// +// Map from ink_hrtime values to other units +// +////////////////////////////////////////////////////////////////////////////// + +static inline ink_hrtime +ink_hrtime_to_years(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_YEAR)); +} +static inline ink_hrtime +ink_hrtime_to_weeks(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_WEEK)); +} +static inline ink_hrtime +ink_hrtime_to_days(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_DAY)); +} +static inline ink_hrtime +ink_hrtime_to_mins(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_MINUTE)); +} +static inline ink_hrtime +ink_hrtime_to_sec(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_SECOND)); +} +static inline ink_hrtime +ink_hrtime_to_msec(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_MSECOND)); +} +static inline ink_hrtime +ink_hrtime_to_usec(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_USECOND)); +} +static inline ink_hrtime +ink_hrtime_to_nsec(ink_hrtime t) +{ + return ((ink_hrtime) (t / HRTIME_NSECOND)); +} + +static inline struct timeval +ink_hrtime_to_timeval(ink_hrtime t) +{ + int64_t usecs; + struct timeval tv; + + usecs = ink_hrtime_to_usec(t); + tv.tv_sec = usecs / 1000000; + tv.tv_usec = usecs % 1000000; + return (tv); +} + +static inline int +ink_hrtime_to_timeval2(ink_hrtime t, struct timeval *tv) +{ + int64_t usecs = ink_hrtime_to_usec(t); + tv->tv_sec = usecs / 1000000; + tv->tv_usec = usecs % 1000000; + return 0; +} + + +/* + using Jan 1 1970 as the base year, instead of Jan 1 1601, + which translates to (365 + 0.25)369*24*60*60 seconds */ +#define NT_TIMEBASE_DIFFERENCE_100NSECS 116444736000000000i64 + + +static inline ink_hrtime +ink_get_hrtime_internal() +{ +#if defined (NEED_HRTIME) +#if defined (USE_TIME_STAMP_COUNTER_HRTIME) + return get_hrtime_rdtsc(); +#elif defined(freebsd) + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (ts.tv_sec * HRTIME_SECOND + ts.tv_nsec * HRTIME_NSECOND); +#else + timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * HRTIME_SECOND + tv.tv_usec * HRTIME_USECOND); +#endif +#else /* !defined (NEED_HRTIME) */ + return gethrtime(); +#endif +} + +static inline ink_hrtime +ink_get_based_hrtime_internal() +{ +#if defined(USE_TIME_STAMP_COUNTER_HRTIME) + return hrtime_offset + ink_get_hrtime_internal(); +#elif !TS_HAS_CLOCK_GETTIME + timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * HRTIME_SECOND + tv.tv_usec * HRTIME_USECOND); +#else + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (ts.tv_sec * HRTIME_SECOND + ts.tv_nsec * HRTIME_NSECOND); +#endif +} + + + +static inline struct timeval +ink_gettimeofday() +{ + return ink_hrtime_to_timeval(ink_get_based_hrtime_internal()); +} + +static inline int +ink_gethrtimeofday(struct timeval *tp, void *) +{ + return ink_hrtime_to_timeval2(ink_get_based_hrtime_internal(), tp); +} + +static inline int +ink_time() +{ + return (int) (ink_get_based_hrtime_internal() / HRTIME_SECOND); +} + +static inline int +ink_hrtime_diff_msec(ink_hrtime t1, ink_hrtime t2) +{ + return (int) ((t1 - t2) / 1000); +} + +static inline ink_hrtime +ink_hrtime_diff(ink_hrtime t1, ink_hrtime t2) +{ + return (t1 - t2); +} + +static inline ink_hrtime +ink_hrtime_add(ink_hrtime t1, ink_hrtime t2) +{ + return (t1 + t2); +} + +static inline timespec +ink_based_hrtime_to_timespec(ink_hrtime t) +{ + timespec ts; + ts.tv_sec = (time_t) (t / HRTIME_SECOND); + ts.tv_nsec = (t % HRTIME_SECOND); + return ts; +} + +static inline ink_hrtime +ink_timespec_to_based_hrtime(timespec * ts) +{ + return (ts->tv_sec * HRTIME_SECOND + ts->tv_nsec * HRTIME_NSECOND); +} + +#endif /* _ink_hrtime_h_ */ diff --git a/lib/ts/ink_inet.cc b/lib/ts/ink_inet.cc new file mode 100644 index 00000000..91573d94 --- /dev/null +++ b/lib/ts/ink_inet.cc @@ -0,0 +1,196 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#if defined(darwin) +extern "C" +{ + struct hostent *gethostbyname_r(const char *name, struct hostent *result, char *buffer, int buflen, int *h_errnop); + struct hostent *gethostbyaddr_r(const char *name, size_t size, int type, + struct hostent *result, char *buffer, int buflen, int *h_errnop); +} +#endif + + +struct hostent * +ink_gethostbyname_r(char *hostname, ink_gethostbyname_r_data * data) +{ +#ifdef RENTRENT_GETHOSTBYNAME + struct hostent *r = gethostbyname(hostname); + if (r) + data->ent = *r; + data->herrno = errno; + +#else //RENTRENT_GETHOSTBYNAME +#if GETHOSTBYNAME_R_GLIBC2 + + struct hostent *addrp = NULL; + int res = gethostbyname_r(hostname, &data->ent, data->buf, + INK_GETHOSTBYNAME_R_DATA_SIZE, &addrp, + &data->herrno); + struct hostent *r = NULL; + if (!res && addrp) + r = addrp; + +#else + struct hostent *r = gethostbyname_r(hostname, &data->ent, data->buf, + INK_GETHOSTBYNAME_R_DATA_SIZE, + &data->herrno); +#endif +#endif + return r; +} + +struct hostent * +ink_gethostbyaddr_r(char *ip, int len, int type, ink_gethostbyaddr_r_data * data) +{ +#if GETHOSTBYNAME_R_GLIBC2 + struct hostent *r = NULL; + struct hostent *addrp = NULL; + int res = gethostbyaddr_r((char *) ip, len, type, &data->ent, data->buf, + INK_GETHOSTBYNAME_R_DATA_SIZE, &addrp, + &data->herrno); + if (!res && addrp) + r = addrp; +#else +#ifdef RENTRENT_GETHOSTBYADDR + struct hostent *r = gethostbyaddr((const void *) ip, len, type); + +#else + struct hostent *r = gethostbyaddr_r((char *) ip, len, type, &data->ent, + data->buf, + INK_GETHOSTBYNAME_R_DATA_SIZE, + &data->herrno); +#endif +#endif //LINUX + return r; +} + +unsigned int +host_to_ip(char *hostname) +{ + struct hostent *he; + + he = gethostbyname(hostname); + if (he == NULL) + return INADDR_ANY; + + return *(unsigned int *) he->h_addr; +} + +uint32_t +ink_inet_addr(const char *s) +{ + uint32_t u[4]; + uint8_t *pc = (uint8_t *) s; + int n = 0; + uint32_t base = 10; + + while (n < 4) { + + u[n] = 0; + base = 10; + + // handle hex, octal + + if (*pc == '0') { + if (*++pc == 'x' || *pc == 'X') + base = 16, pc++; + else + base = 8; + } + // handle hex, octal, decimal + + while (*pc) { + if (ParseRules::is_digit(*pc)) { + u[n] = u[n] * base + (*pc++ - '0'); + continue; + } + if (base == 16 && ParseRules::is_hex(*pc)) { + u[n] = u[n] * 16 + ParseRules::ink_tolower(*pc++) - 'a' + 10; + continue; + } + break; + } + + n++; + if (*pc == '.') + pc++; + else + break; + } + + if (*pc && !ParseRules::is_wslfcr(*pc)) + return htonl((uint32_t) - 1); + + switch (n) { + case 1: + return htonl(u[0]); + case 2: + if (u[0] > 0xff || u[1] > 0xffffff) + return htonl((uint32_t) - 1); + return htonl((u[0] << 24) | u[1]); + case 3: + if (u[0] > 0xff || u[1] > 0xff || u[2] > 0xffff) + return htonl((uint32_t) - 1); + return htonl((u[0] << 24) | (u[1] << 16) | u[2]); + case 4: + if (u[0] > 0xff || u[1] > 0xff || u[2] > 0xff || u[3] > 0xff) + return htonl((uint32_t) - 1); + return htonl((u[0] << 24) | (u[1] << 16) | (u[2] << 8) | u[3]); + } + return htonl((uint32_t) - 1); +} + +const char *ink_inet_ntop(const struct sockaddr *addr, char *dst, size_t size) +{ + void *address = NULL; + + switch (addr->sa_family) { + case AF_INET: + address = &((struct sockaddr_in *)addr)->sin_addr; + break; + case AF_INET6: + address = &((struct sockaddr_in6 *)addr)->sin6_addr; + break; + } + + return inet_ntop(addr->sa_family, address, dst, size); +} + +uint16_t ink_inet_port(const struct sockaddr *addr) +{ + uint16_t port = 0; + + switch (addr->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)addr)->sin_port); + break; + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); + break; + } + + return port; +} diff --git a/lib/ts/ink_inet.h b/lib/ts/ink_inet.h new file mode 100644 index 00000000..96e6bbae --- /dev/null +++ b/lib/ts/ink_inet.h @@ -0,0 +1,272 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#if !defined (_ink_inet_h_) +#define _ink_inet_h_ + +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_apidefs.h" + +#define INK_GETHOSTBYNAME_R_DATA_SIZE 1024 +#define INK_GETHOSTBYADDR_R_DATA_SIZE 1024 + +struct ink_gethostbyname_r_data +{ + int herrno; + struct hostent ent; + char buf[INK_GETHOSTBYNAME_R_DATA_SIZE]; +}; + +struct ink_gethostbyaddr_r_data +{ + int herrno; + struct hostent ent; + char buf[INK_GETHOSTBYADDR_R_DATA_SIZE]; +}; + +/** + returns the IP address of the hostname. If the hostname has + multiple IP addresses, the first IP address in the list returned + by 'gethostbyname' is returned. + + @note Not thread-safe + +*/ +unsigned int host_to_ip(char *hostname); + +/** + Wrapper for gethostbyname_r(). If successful, returns a pointer + to the hostent structure. Returns NULL and sets data->herrno to + the appropriate error code on failure. + + @param hostname null-terminated host name string + @param data pointer to ink_gethostbyname_r_data allocated by the caller + +*/ +struct hostent *ink_gethostbyname_r(char *hostname, ink_gethostbyname_r_data * data); + +/** + Wrapper for gethostbyaddr_r(). If successful, returns a pointer + to the hostent structure. Returns NULL and sets data->herrno to + the appropriate error code on failure. + + @param ip IP address of the host + @param len length of the buffer indicated by ip + @param type family of the address + @param data pointer to ink_gethostbyname_r_data allocated by the caller + +*/ +struct hostent *ink_gethostbyaddr_r(char *ip, int len, int type, ink_gethostbyaddr_r_data * data); + +/** + Wrapper for inet_addr(). + + @param s IP address in the Internet standard dot notation. + +*/ +inkcoreapi uint32_t ink_inet_addr(const char *s); + +const char *ink_inet_ntop(const struct sockaddr *addr, char *dst, size_t size); +uint16_t ink_inet_port(const struct sockaddr *addr); + +/// Reset an address to invalid. +/// Convenience overload. +/// @note Useful for marking a member as not yet set. +inline void ink_inet_invalidate(sockaddr_storage* addr) { + addr->ss_family = AF_UNSPEC; +} + +/// Set to all zero. +inline void ink_inet_init(sockaddr_storage* addr) { + memset(addr, 0, sizeof(addr)); + ink_inet_invalidate(addr); +} + +/// @return @a a cast to @c sockaddr_storage*. +inline sockaddr_storage* ink_inet_ss_cast(sockaddr* a) { + return static_cast(static_cast(a)); +} +/// @return @a a cast to @c sockaddr_storage const*. +inline sockaddr_storage const* ink_inet_ss_cast(sockaddr const* a) { + return static_cast(static_cast(a)); +} +/// @return @a a cast to @c sockaddr_storage const*. +inline sockaddr_storage* ink_inet_ss_cast(sockaddr_in6* a) { + return reinterpret_cast(a); +} +/// @return @a a cast to @c sockaddr_storage const*. +inline sockaddr_storage const* ink_inet_ss_cast(sockaddr_in6 const* a) { + return reinterpret_cast(a); +} +/// @return @a a cast to @c sockaddr*. +inline sockaddr* ink_inet_sa_cast(sockaddr_storage* a) { + return reinterpret_cast(a); +} +/// @return @a a cast to sockaddr const*. +inline sockaddr const* ink_inet_sa_cast(sockaddr_storage const* a) { + return reinterpret_cast(a); +} +/// @return @a a cast to sockaddr const*. +inline sockaddr const* ink_inet_sa_cast(sockaddr_in6 const* a) { + return reinterpret_cast(a); +} + +/// Test for IPv4 protocol. +/// @return @c true if the address is IPv4, @c false otherwise. +inline bool ink_inet_is_ip4(sockaddr_storage const* addr) { + return AF_INET == addr->ss_family; +} +/// Test for IPv4 protocol. +/// @return @c true if the address is IPv4, @c false otherwise. +inline bool ink_inet_is_ip4(sockaddr const* addr) { + return AF_INET == addr->sa_family; +} +/// Test for IPv6 protocol. +/// Convenience overload. +/// @return @c true if the address is IPv6, @c false otherwise. +inline bool ink_inet_is_ip6(sockaddr_storage const* addr) { + return AF_INET6 == addr->ss_family; +} + +/// IPv4 cast. +/// @return @a a cast to a @c sockaddr_in* +inline sockaddr_in* ink_inet_ip4_cast( + sockaddr_storage* a ///< Address structure. +) { + return static_cast(static_cast(a)); +} +/// IPv4 cast. +/// @return @a a cast to a @c sockaddr_in* +inline sockaddr_in const* ink_inet_ip4_cast( + sockaddr_storage const* a ///< Address structure. +) { + return static_cast(static_cast(a)); +} +/// IPv4 cast. +/// @return @a a cast to a @c sockaddr_in* +inline sockaddr_in const* ink_inet_ip4_cast( + sockaddr const* a ///< Address structure. +) { + return reinterpret_cast(a); +} +/// IPv6 cast. +/// @return @a a cast to a @c sockaddr_in6* +inline sockaddr_in6* ink_inet_ip6_cast(sockaddr_storage* a) { + return static_cast(static_cast(a)); +} +/// IPv6 cast. +/// @return @a a cast to a @c sockaddr_in6* +inline sockaddr_in6 const* ink_inet_ip6_cast(sockaddr_storage const* a) { + return static_cast(static_cast(a)); +} + +/** Get a reference to the port in an address. + @note Because this is direct access, the port value is in network order. + @see ink_inet_get_port for host order copy. + @return A reference to the port value in an IPv4 or IPv6 address. + @internal This is primarily for internal use but it might be handy for + clients so it is exposed. +*/ +inline uint16_t& ink_inet_port_cast(sockaddr_storage* ss) { + static uint16_t dummy = 0; + return AF_INET == ss->ss_family + ? ink_inet_ip4_cast(ss)->sin_port + : AF_INET6 == ss->ss_family + ? ink_inet_ip6_cast(ss)->sin6_port + : (dummy = 0) + ; +} +/** Get a reference to the port in an address. + @note Because this is direct access, the port value is in network order. + @see ink_inet_get_port for host order copy. + @return A reference to the port value in an IPv4 or IPv6 address. + @internal This is primarily for internal use but it might be handy for + clients so it is exposed. +*/ +inline uint16_t const& ink_inet_port_cast(sockaddr_storage const* ss) { + return ink_inet_port_cast(const_cast(ss)); +} +/** Get a reference to the port in an address. + @note Because this is direct access, the port value is in network order. + @see ink_inet_get_port for host order copy. + @return A reference to the port value in an IPv4 or IPv6 address. + @internal This is primarily for internal use but it might be handy for + clients so it is exposed. +*/ +inline uint16_t const& ink_inet_port_cast(sockaddr const* sa) { + return ink_inet_port_cast(ink_inet_ss_cast(sa)); +} + +/** Access the IPv4 address. + + If @a addr is not IPv4 the results are indeterminate. + + @note This is direct access to the address so it will be in + network order. + + @return A reference to the IPv4 address in @a addr. +*/ +inline in_addr_t& ink_inet_ip4_addr_cast(sockaddr_storage* addr) { + return ink_inet_ip4_cast(addr)->sin_addr.s_addr; +} +/** Access the IPv4 address. + + If @a addr is not IPv4 the results are indeterminate. + + @note This is direct access to the address so it will be in + network order. + + @return A reference to the IPv4 address in @a addr. +*/ +inline in_addr_t const& ink_inet_ip4_addr_cast(sockaddr_storage const* addr) { + return ink_inet_ip4_cast(addr)->sin_addr.s_addr; +} +/** Access the IPv4 address. + + If @a addr is not IPv4 the results are indeterminate. + + @note This is direct access to the address so it will be in + network order. + + @return A reference to the IPv4 address in @a addr. +*/ +inline in_addr_t const& ink_inet_ip4_addr_cast(sockaddr const* addr) { + return ink_inet_ip4_cast(addr)->sin_addr.s_addr; +} + +/// Write IPv4 data to a @c sockaddr_storage. +inline void ink_inet_ip4_set( + sockaddr_storage* ss, ///< Destination storage. + in_addr_t ip4, ///< address, IPv4 network order. + uint16_t port = 0 ///< port, network order. +) { + sockaddr_in* sin = ink_inet_ip4_cast(ss); + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + memcpy(&(sin->sin_addr), &ip4, sizeof(ip4)); + sin->sin_port = port; +} + +#endif // _ink_inet.h diff --git a/lib/ts/ink_inout.h b/lib/ts/ink_inout.h new file mode 100644 index 00000000..0663a8f1 --- /dev/null +++ b/lib/ts/ink_inout.h @@ -0,0 +1,73 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + I/O Marshalling + +**************************************************************************/ + +#ifndef _INOUT_H +#define _INOUT_H + +// source of good macros.. +extern "C" +{ +#include "/usr/include/arpa/nameser.h" +} + +#define GETCHAR(s, cp) { \ + (s) = *(cp)++; \ +} + +#define PUTCHAR(s, cp) { \ + *(cp)++ = (s); \ +} + +#define GETLONGLONG(l, cp) { \ + (l) = *(cp)++ << 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; (l) <<= 8; \ + (l) |= *(cp)++; \ +} + +/* + * Warning: PUTLONGLONG destroys its first argument. + */ +#define PUTLONGLONG(l, cp) { \ + (cp)[7] = l; \ + (cp)[6] = (l >>= 8); \ + (cp)[5] = (l >>= 8); \ + (cp)[4] = (l >>= 8); \ + (cp)[3] = (l >>= 8); \ + (cp)[2] = (l >>= 8); \ + (cp)[1] = (l >>= 8); \ + (cp)[0] = l >> 8; \ + (cp) += 8; \ +} + + +#endif /* #ifndef _INOUT_H */ diff --git a/lib/ts/ink_isolatin_table.cc b/lib/ts/ink_isolatin_table.cc new file mode 100644 index 00000000..a65ae41e --- /dev/null +++ b/lib/ts/ink_isolatin_table.cc @@ -0,0 +1,579 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * + * ink_isolatin_table.h + * The eight bit table used by the isolatin macros. + * + * $Date: 2003-06-01 18:36:44 $ + * + * + */ + +#include "ink_isolatin_table.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "ink_apidefs.h" + +#define UNDEF 0 +#define DIGIT 1 +#define ALPHL 2 +#define ALPHU 3 +#define PUNCT 4 +#define WHSPC 5 + +/* + * The eight bit table. + */ +ink_undoc_liapi int eight_bit_table[] = { + /* 000 */ UNDEF, + /* ^@ NUL */ + /* 001 */ UNDEF, + /* ^A SOH */ + /* 002 */ UNDEF, + /* ^B STX */ + /* 003 */ UNDEF, + /* ^C ETX */ + /* 004 */ UNDEF, + /* ^D EOT */ + /* 005 */ UNDEF, + /* ^E ENQ */ + /* 006 */ UNDEF, + /* ^F ACK */ + /* 007 */ UNDEF, + /* ^G BEL */ + /* 008 */ UNDEF, + /* ^H BS */ + + /* 009 */ WHSPC, + /* " " HT */ + /* 010 */ WHSPC, + /* " " LF */ + /* 011 */ WHSPC, + /* VT */ + /* 012 */ WHSPC, + /* ^L NP */ + /* 013 */ WHSPC, + /* ^M CR */ + + /* 014 */ UNDEF, + /* ^N SO */ + /* 015 */ UNDEF, + /* ^O SI */ + /* 016 */ UNDEF, + /* ^P DLE */ + /* 017 */ UNDEF, + /* ^Q DC1 */ + /* 018 */ UNDEF, + /* ^R DC2 */ + /* 019 */ UNDEF, + /* ^S DC3 */ + /* 020 */ UNDEF, + /* ^T DC4 */ + /* 021 */ UNDEF, + /* ^U NAK */ + /* 022 */ UNDEF, + /* ^V SYN */ + /* 023 */ UNDEF, + /* ^W ETB */ + /* 024 */ UNDEF, + /* ^X CAN */ + /* 025 */ UNDEF, + /* ^Y EM */ + /* 026 */ UNDEF, + /* ^Z SUB */ + /* 027 */ UNDEF, + /* ^[ ESC */ + /* 028 */ UNDEF, + /* ^\ FS */ + /* 029 */ UNDEF, + /* ^] GS */ + /* 030 */ UNDEF, + /* ^^ RS */ + /* 031 */ UNDEF, + /* ^_ US */ + + /* 032 */ WHSPC, + /* " " SP */ + + /* 033 */ PUNCT, + /* ! */ + /* 034 */ PUNCT, + /* " */ + /* 035 */ PUNCT, + /* # */ + /* 036 */ PUNCT, + /* $ */ + /* 037 */ PUNCT, + /* % */ + /* 038 */ PUNCT, + /* & */ + /* 039 */ PUNCT, + /* ' */ + /* 040 */ PUNCT, + /* ( */ + /* 041 */ PUNCT, + /* ) */ + /* 042 */ PUNCT, + /* * */ + /* 043 */ PUNCT, + /* + */ + /* 044 */ PUNCT, + /* , */ + /* 045 */ PUNCT, + /* - */ + /* 046 */ PUNCT, + /* . */ + /* 047 */ PUNCT, + /* / */ + + /* 048 */ DIGIT, + /* 0 */ + /* 049 */ DIGIT, + /* 1 */ + /* 050 */ DIGIT, + /* 2 */ + /* 051 */ DIGIT, + /* 3 */ + /* 052 */ DIGIT, + /* 4 */ + /* 053 */ DIGIT, + /* 5 */ + /* 054 */ DIGIT, + /* 6 */ + /* 055 */ DIGIT, + /* 7 */ + /* 056 */ DIGIT, + /* 8 */ + /* 057 */ DIGIT, + /* 9 */ + + /* 058 */ PUNCT, + /* : */ + /* 059 */ PUNCT, + /* ; */ + /* 060 */ PUNCT, + /* < */ + /* 061 */ PUNCT, + /* = */ + /* 062 */ PUNCT, + /* > */ + /* 063 */ PUNCT, + /* ? */ + /* 064 */ PUNCT, + /* @ */ + + /* 065 */ ALPHU, + /* A */ + /* 066 */ ALPHU, + /* B */ + /* 067 */ ALPHU, + /* C */ + /* 068 */ ALPHU, + /* D */ + /* 069 */ ALPHU, + /* E */ + /* 070 */ ALPHU, + /* F */ + /* 071 */ ALPHU, + /* G */ + /* 072 */ ALPHU, + /* H */ + /* 073 */ ALPHU, + /* I */ + /* 074 */ ALPHU, + /* J */ + /* 075 */ ALPHU, + /* K */ + /* 076 */ ALPHU, + /* L */ + /* 077 */ ALPHU, + /* M */ + /* 078 */ ALPHU, + /* N */ + /* 079 */ ALPHU, + /* O */ + /* 080 */ ALPHU, + /* P */ + /* 081 */ ALPHU, + /* Q */ + /* 082 */ ALPHU, + /* R */ + /* 083 */ ALPHU, + /* S */ + /* 084 */ ALPHU, + /* T */ + /* 085 */ ALPHU, + /* U */ + /* 086 */ ALPHU, + /* V */ + /* 087 */ ALPHU, + /* W */ + /* 088 */ ALPHU, + /* X */ + /* 089 */ ALPHU, + /* Y */ + /* 090 */ ALPHU, + /* Z */ + + /* 091 */ PUNCT, + /* [ */ + /* 092 */ PUNCT, + /* \ */ + /* 093 */ PUNCT, + /* ] */ + /* 094 */ PUNCT, + /* ^ */ + /* 095 */ PUNCT, + /* _ */ + /* 096 */ PUNCT, + /* ` */ + + /* 097 */ ALPHL, + /* a */ + /* 098 */ ALPHL, + /* b */ + /* 099 */ ALPHL, + /* c */ + /* 100 */ ALPHL, + /* d */ + /* 101 */ ALPHL, + /* e */ + /* 102 */ ALPHL, + /* f */ + /* 103 */ ALPHL, + /* g */ + /* 104 */ ALPHL, + /* h */ + /* 105 */ ALPHL, + /* i */ + /* 106 */ ALPHL, + /* j */ + /* 107 */ ALPHL, + /* k */ + /* 108 */ ALPHL, + /* l */ + /* 109 */ ALPHL, + /* m */ + /* 110 */ ALPHL, + /* n */ + /* 111 */ ALPHL, + /* o */ + /* 112 */ ALPHL, + /* p */ + /* 113 */ ALPHL, + /* q */ + /* 114 */ ALPHL, + /* r */ + /* 115 */ ALPHL, + /* s */ + /* 116 */ ALPHL, + /* t */ + /* 117 */ ALPHL, + /* u */ + /* 118 */ ALPHL, + /* v */ + /* 119 */ ALPHL, + /* w */ + /* 120 */ ALPHL, + /* x */ + /* 121 */ ALPHL, + /* y */ + /* 122 */ ALPHL, + /* z */ + + /* 123 */ PUNCT, + /* { */ + /* 124 */ PUNCT, + /* | */ + /* 125 */ PUNCT, + /* } */ + /* 126 */ PUNCT, + /* ~ */ + + /* 127 */ UNDEF, + /* ^? DEL */ + /* 128 */ UNDEF, + /* € */ + /* 129 */ UNDEF, + /*  */ + /* 130 */ UNDEF, + /* ‚ */ + /* 131 */ UNDEF, + /* ƒ */ + /* 132 */ UNDEF, + /* „ */ + /* 133 */ UNDEF, + /* … */ + /* 134 */ UNDEF, + /* † */ + /* 135 */ UNDEF, + /* ‡ */ + /* 136 */ UNDEF, + /* ˆ */ + /* 137 */ UNDEF, + /* ‰ */ + /* 138 */ UNDEF, + /* Š */ + /* 139 */ UNDEF, + /* ‹ */ + /* 140 */ UNDEF, + /* Œ */ + /* 141 */ UNDEF, + /*  */ + /* 142 */ UNDEF, + /* Ž */ + /* 143 */ UNDEF, + /*  */ + /* 144 */ UNDEF, + /*  */ + /* 145 */ UNDEF, + /* ‘ */ + /* 146 */ UNDEF, + /* ’ */ + /* 147 */ UNDEF, + /* “ */ + /* 148 */ UNDEF, + /* ” */ + /* 149 */ UNDEF, + /* • */ + /* 150 */ UNDEF, + /* – */ + /* 151 */ UNDEF, + /* — */ + /* 152 */ UNDEF, + /* ˜ */ + /* 153 */ UNDEF, + /* ™ */ + /* 154 */ UNDEF, + /* š */ + /* 155 */ UNDEF, + /* › */ + /* 156 */ UNDEF, + /* œ */ + /* 157 */ UNDEF, + /*  */ + /* 158 */ UNDEF, + /* ž */ + /* 159 */ UNDEF, + /* Ÿ */ + /* 160 */ UNDEF, + /* */ + + /* 161 */ PUNCT, + /* ¡ */ + /* 162 */ PUNCT, + /* ¢ */ + /* 163 */ PUNCT, + /* £ */ + /* 164 */ PUNCT, + /* ¤ */ + /* 165 */ PUNCT, + /* ¥ */ + /* 166 */ PUNCT, + /* ¦ */ + /* 167 */ PUNCT, + /* § */ + /* 168 */ PUNCT, + /* ¨ */ + /* 169 */ PUNCT, + /* © */ + /* 170 */ PUNCT, + /* ª */ + /* 171 */ PUNCT, + /* « */ + /* 172 */ PUNCT, + /* ¬ */ + /* 173 */ PUNCT, + /* ­ */ + /* 174 */ PUNCT, + /* ® */ + /* 175 */ PUNCT, + /* ¯ */ + /* 176 */ PUNCT, + /* ° */ + /* 177 */ PUNCT, + /* ± */ + /* 178 */ PUNCT, + /* ² */ + /* 179 */ PUNCT, + /* ³ */ + /* 180 */ PUNCT, + /* ´ */ + /* 181 */ PUNCT, + /* µ */ + /* 182 */ PUNCT, + /* ¶ */ + /* 183 */ PUNCT, + /* · */ + /* 184 */ PUNCT, + /* ¸ */ + /* 185 */ PUNCT, + /* ¹ */ + /* 186 */ PUNCT, + /* º */ + /* 187 */ PUNCT, + /* » */ + /* 188 */ PUNCT, + /* ¼ */ + /* 189 */ PUNCT, + /* ½ */ + /* 190 */ PUNCT, + /* ¾ */ + /* 191 */ PUNCT, + /* ¿ */ + + /* 192 */ ALPHU, + /* À */ + /* 193 */ ALPHU, + /* Á */ + /* 194 */ ALPHU, + /*  */ + /* 195 */ ALPHU, + /* à */ + /* 196 */ ALPHU, + /* Ä */ + /* 197 */ ALPHU, + /* Å */ + /* 198 */ ALPHU, + /* Æ */ + /* 199 */ ALPHU, + /* Ç */ + /* 200 */ ALPHU, + /* È */ + /* 201 */ ALPHU, + /* É */ + /* 202 */ ALPHU, + /* Ê */ + /* 203 */ ALPHU, + /* Ë */ + /* 204 */ ALPHU, + /* Ì */ + /* 205 */ ALPHU, + /* Í */ + /* 206 */ ALPHU, + /* Î */ + /* 207 */ ALPHU, + /* Ï */ + /* 208 */ ALPHU, + /* Ð */ + /* 209 */ ALPHU, + /* Ñ */ + /* 210 */ ALPHU, + /* Ò */ + /* 211 */ ALPHU, + /* Ó */ + /* 212 */ ALPHU, + /* Ô */ + /* 213 */ ALPHU, + /* Õ */ + /* 214 */ ALPHU, + /* Ö */ + + /* 215 */ PUNCT, + /* × */ + + /* 216 */ ALPHU, + /* Ø */ + /* 217 */ ALPHU, + /* Ù */ + /* 218 */ ALPHU, + /* Ú */ + /* 219 */ ALPHU, + /* Û */ + /* 220 */ ALPHU, + /* Ü */ + /* 221 */ ALPHU, + /* Ý */ + /* 222 */ ALPHU, + /* Þ */ + + /* 223 */ ALPHL, + /* ß */ + /* 224 */ ALPHL, + /* à */ + /* 225 */ ALPHL, + /* á */ + /* 226 */ ALPHL, + /* â */ + /* 227 */ ALPHL, + /* ã */ + /* 228 */ ALPHL, + /* ä */ + /* 229 */ ALPHL, + /* å */ + /* 230 */ ALPHL, + /* æ */ + /* 231 */ ALPHL, + /* ç */ + /* 232 */ ALPHL, + /* è */ + /* 233 */ ALPHL, + /* é */ + /* 234 */ ALPHL, + /* ê */ + /* 235 */ ALPHL, + /* ë */ + /* 236 */ ALPHL, + /* ì */ + /* 237 */ ALPHL, + /* í */ + /* 238 */ ALPHL, + /* î */ + /* 239 */ ALPHL, + /* ï */ + /* 240 */ ALPHL, + /* ð */ + /* 241 */ ALPHL, + /* ñ */ + /* 242 */ ALPHL, + /* ò */ + /* 243 */ ALPHL, + /* ó */ + /* 244 */ ALPHL, + /* ô */ + /* 245 */ ALPHL, + /* õ */ + /* 246 */ ALPHL, + /* ö */ + + /* 247 */ PUNCT, + /* ÷ */ + + /* 248 */ ALPHL, + /* ø */ + /* 249 */ ALPHL, + /* ù */ + /* 250 */ ALPHL, + /* ú */ + /* 251 */ ALPHL, + /* û */ + /* 252 */ ALPHL, + /* ü */ + /* 253 */ ALPHL, + /* ý */ + /* 254 */ ALPHL, + /* þ */ + /* 255 */ ALPHL + /* \377 */ +}; diff --git a/lib/ts/ink_isolatin_table.h b/lib/ts/ink_isolatin_table.h new file mode 100644 index 00000000..3290df8c --- /dev/null +++ b/lib/ts/ink_isolatin_table.h @@ -0,0 +1,51 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * + * ink_isolatin_table.h + * The eight bit table used by the isolatin macros. + * + * $Date: 2003-06-01 18:36:44 $ + * + * + */ + +#ifndef _INK_ISOLATIN_TABLE_H +#define _INK_ISOLATIN_TABLE_H + +#include "ink_apidefs.h" + +#define UNDEF 0 +#define DIGIT 1 +#define ALPHL 2 +#define ALPHU 3 +#define PUNCT 4 +#define WHSPC 5 + +/* + * The eight bit table. + */ +extern inkcoreapi int eight_bit_table[]; + +#endif /* _INK_ISOLATIN_TABLE_H */ diff --git a/lib/ts/ink_killall.cc b/lib/ts/ink_killall.cc new file mode 100644 index 00000000..059ae214 --- /dev/null +++ b/lib/ts/ink_killall.cc @@ -0,0 +1,151 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +#include "libts.h" + +#if defined(linux) + +#include "ink_killall.h" +#include "ink_resource.h" + +#define PROC_BASE "/proc" + +#define INITIAL_PIDVSIZE 32 + +int +ink_killall(const char *pname, int sig) +{ + + int err; + pid_t *pidv; + int pidvcnt; + + if (ink_killall_get_pidv_xmalloc(pname, &pidv, &pidvcnt) < 0) { + return -1; + } + + if (pidvcnt == 0) { + xfree(pidv); + return 0; + } + + err = ink_killall_kill_pidv(pidv, pidvcnt, sig); + + xfree(pidv); + + return err; + +} + +int +ink_killall_get_pidv_xmalloc(const char *pname, pid_t ** pidv, int *pidvcnt) +{ + + DIR *dir; + FILE *fp; + struct dirent *de; + pid_t pid, self; + char buf[LINE_MAX], *p, *comm; + int pidvsize = INITIAL_PIDVSIZE; + + if (!pname || !pidv || !pidvcnt) + goto l_error; + + self = getpid(); + if (!(dir = opendir(PROC_BASE))) + goto l_error; + + *pidvcnt = 0; + if (!(*pidv = (pid_t *) xmalloc(pidvsize * sizeof(pid_t)))) + goto l_error; + + while ((de = readdir(dir))) { + if (!(pid = (pid_t) atoi(de->d_name)) || pid == self) + continue; + snprintf(buf, sizeof(buf), PROC_BASE "/%d/stat", pid); + if ((fp = fopen(buf, "r"))) { + if (fgets(buf, sizeof buf, fp) == 0) + goto l_close; + if ((p = strchr(buf, '('))) { + comm = p + 1; + if ((p = strchr(comm, ')'))) + *p = '\0'; + else + goto l_close; + if (strcmp(comm, pname) == 0) { + if (*pidvcnt >= pidvsize) { + pid_t *pidv_realloc; + pidvsize *= 2; + if (!(pidv_realloc = (pid_t *) xrealloc(*pidv, pidvsize * sizeof(pid_t)))) { + xfree(*pidv); + goto l_error; + } else { + *pidv = pidv_realloc; + } + } + (*pidv)[*pidvcnt] = pid; + (*pidvcnt)++; + } + } + l_close: + fclose(fp); + } + } + closedir(dir); + + if (*pidvcnt == 0) { + xfree(*pidv); + *pidv = 0; + } + + return 0; + +l_error: + *pidv = NULL; + *pidvcnt = 0; + return -1; +} + +int +ink_killall_kill_pidv(pid_t * pidv, int pidvcnt, int sig) +{ + + int err = 0; + + if (!pidv || (pidvcnt <= 0)) + return -1; + + while (pidvcnt > 0) { + pidvcnt--; + if (kill(pidv[pidvcnt], sig) < 0) + err = -1; + } + + return err; + +} + +#endif // linux check diff --git a/lib/ts/ink_killall.h b/lib/ts/ink_killall.h new file mode 100644 index 00000000..fde6f21c --- /dev/null +++ b/lib/ts/ink_killall.h @@ -0,0 +1,63 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + + +#ifndef _INK_KILLALL_H_ +#define _INK_KILLALL_H_ + +#include "ink_config.h" + +#if defined(linux) + +/*------------------------------------------------------------------------- + ink_killall + - Sends signal 'sig' to all processes with the name 'pname' + - Returns: -1 error + 0 okay + -------------------------------------------------------------------------*/ +int ink_killall(const char *pname, int sig); + +/*------------------------------------------------------------------------- + ink_killall_get_pidv_xmalloc + - Get all pid's named 'pname' and stores into xmalloc'd + pid_t array, 'pidv' + - Returns: -1 error (pidv: set to NULL; pidvcnt: set to 0) + 0 okay (pidv: xmalloc'd pid vector; pidvcnt: number of pid's; + if pidvcnt is set to 0, then pidv will be set to NULL) + -------------------------------------------------------------------------*/ +int ink_killall_get_pidv_xmalloc(const char *pname, pid_t ** pidv, int *pidvcnt); + +/*------------------------------------------------------------------------- + ink_killall_kill_pidv + - Kills all pid's in 'pidv' with signal 'sig' + - Returns: -1 error + 0 okay + -------------------------------------------------------------------------*/ +int ink_killall_kill_pidv(pid_t * pidv, int pidvcnt, int sig); + +#endif + +#endif diff --git a/lib/ts/ink_llqueue.h b/lib/ts/ink_llqueue.h new file mode 100644 index 00000000..5aa30430 --- /dev/null +++ b/lib/ts/ink_llqueue.h @@ -0,0 +1,65 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _INK_LLQUEUE_H +#define _INK_LLQUEUE_H + +/**************************************************************************** + + +A simple linked list queue. +****************************************************************************/ + +#include "ink_unused.h" +#include "ink_mutex.h" +#include "ink_thread.h" + +typedef struct llqrec_s +{ + struct llqrec_s *next; + void *data; +} LLQrec; + +typedef struct llq_s +{ + LLQrec * head, *tail, *free; + uint64_t len, highwater; + ink_mutex mux; +#if defined(darwin) + ink_sem *sema; +#else /* !darwin */ + ink_sem sema; +#endif /* !darwin */ +} LLQ; + +LLQ *create_queue(void); +int enqueue(LLQ * q, void *data); +void *dequeue(LLQ * q); +int queue_is_empty(LLQ * q); +uint64_t queue_len(LLQ * Q); +uint64_t queue_highwater(LLQ * Q); +void delete_queue(LLQ * Q); /* only deletes an empty queue but + provides symmetry. */ + + +#endif diff --git a/lib/ts/ink_lockfile.h b/lib/ts/ink_lockfile.h new file mode 100644 index 00000000..9109eeb3 --- /dev/null +++ b/lib/ts/ink_lockfile.h @@ -0,0 +1,117 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************** + * + * ink_lockfile.h + * Definitions for the Lockfile class. + * + * $Date: 2006-03-31 04:25:35 $ + * + * + */ + +#ifndef __INK_LOCKFILE_H__ +#define __INK_LOCKFILE_H__ + +#ifndef INK_LOCKFILE_INCLUDE_REDUCED +#include "ink_resource.h" +#endif +#include "ink_port.h" +#include "ink_string.h" + +#ifndef INK_LOCKFILE_INCLUDE_REDUCED +#define COP_LOCK "cop.lock" +#define MANAGER_LOCK "manager.lock" +#define SERVER_LOCK "server.lock" +#endif + +class Lockfile +{ +public: + Lockfile(void):fd(0) + { + fname[0] = '\0'; + } + + // coverity[uninit_member] + Lockfile(const char *filename):fd(0) + { + ink_strncpy(fname, filename, sizeof(fname)); + } + + ~Lockfile(void) + { + } + + void SetLockfileName(const char *filename) + { + ink_strncpy(fname, filename, sizeof(fname)); + } + + const char *GetLockfileName(void) + { + return fname; + } + + // Open() + // + // Tries to open a lock file, returning: + // -errno on error + // 0 if someone is holding the lock (with holding_pid set) + // 1 if we now have a writable lock file + int Open(pid_t * holding_pid); + + // Get() + // + // Gets write access to a lock file, and if successful, truncates + // file, and writes the current process ID. Returns: + // -errno on error + // 0 if someone is holding the lock (with holding_pid set) + // 1 if we now have a writable lock file + int Get(pid_t * holding_pid); + + // Close() + // + // Closes the file handle on the opened Lockfile. + void Close(void); + + // Kill() + // KillGroup() + // + // Ensures no one is holding the lock. It tries to open the lock file + // and if that does not succeed, it kills the process holding the lock. + // If the lock file open succeeds, it closes the lock file releasing + // the lock. + // + // The intial signal can be used to generate a core from the process while + // still ensuring it dies. + void Kill(int sig, int initial_sig = 0, const char *pname = NULL); + void KillGroup(int sig, int initial_sig = 0, const char *pname = NULL); + +private: + char fname[PATH_MAX]; + int fd; +}; + +#endif // __LOCK_FILE_H__ diff --git a/lib/ts/ink_memory.cc b/lib/ts/ink_memory.cc new file mode 100644 index 00000000..bdd0b07f --- /dev/null +++ b/lib/ts/ink_memory.cc @@ -0,0 +1,283 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_memory.c + + Memory allocation routines for libts + + ****************************************************************************/ + +#include "libts.h" + +#include +#if defined(linux) +// XXX: SHouldn't that be part of CPPFLAGS? +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 +#endif +#endif +#include +#include + +#ifdef HAVE_MALLOC_H +#include +#endif + + +void * +ink_malloc(size_t size) +{ + void *ptr = NULL; + + /* + * There's some nasty code in libts that expects + * a MALLOC of a zero-sized item to wotk properly. Rather + * than allocate any space, we simply return a NULL to make + * certain they die quickly & don't trash things. + */ + + // Useful for tracing bad mallocs + // ink_stack_trace_dump(); + if (likely(size > 0)) { + if (unlikely((ptr = malloc(size)) == NULL)) { + xdump(); + ink_fatal(1, "ink_malloc: couldn't allocate %d bytes", size); + } + } + return (ptr); +} /* End ink_malloc */ + + +void * +ink_calloc(size_t nelem, size_t elsize) +{ + void *ptr = calloc(nelem, elsize); + if (unlikely(ptr == NULL)) { + xdump(); + ink_fatal(1, "ink_calloc: couldn't allocate %d %d byte elements", nelem, elsize); + } + return (ptr); +} /* End ink_calloc */ + + +void * +ink_realloc(void *ptr, size_t size) +{ + void *newptr = realloc(ptr, size); + if (unlikely(newptr == NULL)) { + xdump(); + ink_fatal(1, "ink_realloc: couldn't reallocate %d bytes", size); + } + return (newptr); +} /* End ink_realloc */ + + +void +ink_memalign_free(void *ptr) +{ + if (likely(ptr)) { + ink_free(ptr); + } +} + + +void * +ink_memalign(size_t alignment, size_t size) +{ +#ifndef NO_MEMALIGN + + void *ptr; + +#if TS_HAS_POSIX_MEMALIGN + if (alignment <= 8) + return ink_malloc(size); + + int retcode = posix_memalign(&ptr, alignment, size); + if (unlikely(retcode)) { + if (retcode == EINVAL) { + ink_fatal(1, "ink_memalign: couldn't allocate %d bytes at alignment %d - invalid alignment parameter", + (int) size, (int) alignment); + } else if (retcode == ENOMEM) { + ink_fatal(1, "ink_memalign: couldn't allocate %d bytes at alignment %d - insufficient memory", + (int) size, (int) alignment); + } else { + ink_fatal(1, "ink_memalign: couldn't allocate %d bytes at alignment %d - unknown error %d", + (int) size, (int) alignment, retcode); + } + } +#else + ptr = memalign(alignment, size); + if (unlikely(ptr == NULL)) { + ink_fatal(1, "ink_memalign: couldn't allocate %d bytes at alignment %d", (int) size, (int) alignment); + } +#endif + return (ptr); +#else +#if defined(freebsd) || defined(darwin) + /* + * DEC malloc calims to align for "any allocatable type", + * and the following code checks that. + */ + switch (alignment) { + case 1: + case 2: + case 4: + case 8: + case 16: + return malloc(size); + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + case 8192: + return valloc(size); + default: + abort(); + break; + } +# else +# error "Need a memalign" +# endif +#endif /* #ifndef NO_MEMALIGN */ + return NULL; +} /* End ink_memalign */ + +void +ink_free(void *ptr) +{ + if (likely(ptr != NULL)) + free(ptr); + else + ink_warning("ink_free: freeing a NULL pointer"); +} /* End ink_free */ + + +/* this routine has been renamed --- this stub is for portability & will disappear */ + +char * +ink_duplicate_string(char *ptr) +{ + ink_assert(!"don't use this slow code!"); + return (ink_string_duplicate(ptr)); +} /* End ink_duplicate_string */ + +void * +ink_memcpy(void *s1, const void *s2, int n) +{ + register int i; + register char *s, *d; + + s = (char *) s2; + d = (char *) s1; + + if (n <= 8) { + switch (n) { + case 0: + break; + case 1: + d[0] = s[0]; + break; + case 2: + d[0] = s[0]; + d[1] = s[1]; + break; + case 3: + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + break; + case 4: + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = s[3]; + break; + case 5: + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = s[3]; + d[4] = s[4]; + break; + case 6: + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = s[3]; + d[4] = s[4]; + d[5] = s[5]; + break; + case 7: + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = s[3]; + d[4] = s[4]; + d[5] = s[5]; + d[6] = s[6]; + break; + case 8: + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = s[3]; + d[4] = s[4]; + d[5] = s[5]; + d[6] = s[6]; + d[7] = s[7]; + break; + default: + ink_assert(0); + } + } else if (n < 128) { + for (i = 0; i + 7 < n; i += 8) { + d[i + 0] = s[i + 0]; + d[i + 1] = s[i + 1]; + d[i + 2] = s[i + 2]; + d[i + 3] = s[i + 3]; + d[i + 4] = s[i + 4]; + d[i + 5] = s[i + 5]; + d[i + 6] = s[i + 6]; + d[i + 7] = s[i + 7]; + } + for (; i < n; i++) + d[i] = s[i]; + } else { + memcpy(s1, s2, n); + } + + return (s1); +} /* End ink_memcpy */ + +void +ink_bcopy(void *s1, void *s2, size_t n) +{ + ink_assert(!"don't use this slow code!"); + ink_memcpy(s2, s1, n); +} /* End ink_bcopy */ diff --git a/lib/ts/ink_memory.h b/lib/ts/ink_memory.h new file mode 100644 index 00000000..ff8d2564 --- /dev/null +++ b/lib/ts/ink_memory.h @@ -0,0 +1,67 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_memory.h + + Memory allocation routines for libts + + ****************************************************************************/ + +#ifndef _ink_memory_h_ +#define _ink_memory_h_ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + typedef struct + { + void *ptr; + unsigned int length; + } InkMemoryBlock; + +#define ink_type_malloc(type) (type *)ink_malloc(sizeof(type)); +#define ink_type_malloc_n(n,type) (type *)ink_malloc((n) * sizeof(type)); +#define ink_type_calloc(n,type) (type *)ink_calloc((n),sizeof(type)); + + void *ink_malloc(size_t size); + void *ink_calloc(size_t nelem, size_t elsize); + void *ink_realloc(void *ptr, size_t size); + void *ink_memalign(size_t alignment, size_t size); + void ink_free(void *ptr); + void ink_memalign_free(void *ptr); + char *ink_duplicate_string(char *ptr); /* obsoleted by ink_string_duplicate --- don't use */ + void *ink_memcpy(void *s1, const void *s2, int n); + void ink_bcopy(void *s1, void *s2, size_t n); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/lib/ts/ink_mutex.cc b/lib/ts/ink_mutex.cc new file mode 100644 index 00000000..e97420bd --- /dev/null +++ b/lib/ts/ink_mutex.cc @@ -0,0 +1,81 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_error.h" +#include +#include "stdio.h" +#include "ink_mutex.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +x_pthread_mutexattr_t _g_mattr; + +ProcessMutex __global_death = PTHREAD_MUTEX_INITIALIZER; +ProcessMutex *gobal_death_mutex = &__global_death; + +void +ink_ProcessMutex_init(ProcessMutex * m, const char *name) +{ + NOWARN_UNUSED(name); + if (pthread_mutex_init(m, &_g_mattr.attr) != 0) { + abort(); + } +} + +void +ink_ProcessMutex_destroy(ProcessMutex * m) +{ + pthread_mutex_destroy(m); +} + +void +ink_ProcessMutex_acquire(ProcessMutex * m) +{ + if (pthread_mutex_lock(m) != 0) { + abort(); + } +} + +void +ink_ProcessMutex_release(ProcessMutex * m) +{ + if (pthread_mutex_unlock(m) != 0) { + abort(); + } +} + +int +ink_ProcessMutex_try_acquire(ProcessMutex * m) +{ + return pthread_mutex_trylock(m) == 0; +} + +void +ink_ProcessMutex_print(FILE * out, ProcessMutex * m) +{ + (void) out; + (void) m; + if(m == gobal_death_mutex) + fprintf(out, "Global ProcessMutex\n"); + else + fprintf(out, "ProcessMutex\n"); +} diff --git a/lib/ts/ink_mutex.h b/lib/ts/ink_mutex.h new file mode 100644 index 00000000..59197043 --- /dev/null +++ b/lib/ts/ink_mutex.h @@ -0,0 +1,129 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_mutex_h_ +#define _ink_mutex_h_ + +/*********************************************************************** + + Fast Mutex + + Uses atomic memory operations to minimize blocking. + + +***********************************************************************/ +#include + +#include "ink_port.h" + +#if defined(POSIX_THREAD) +#include +#include + +typedef pthread_mutex_t ProcessMutex; +typedef ProcessMutex ink_mutex; +typedef ProcessMutex InkMutex; + +// just a wrapper so that the constructor gets executed +// before the first call to ink_mutex_init(); +class x_pthread_mutexattr_t +{ +public: + pthread_mutexattr_t attr; + x_pthread_mutexattr_t(); + ~x_pthread_mutexattr_t() + { + } +}; +inline +x_pthread_mutexattr_t::x_pthread_mutexattr_t() +{ + pthread_mutexattr_init(&attr); +#ifndef POSIX_THREAD_10031c + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); +#endif +} + +extern class x_pthread_mutexattr_t _g_mattr; + +static inline int +ink_mutex_init(ink_mutex * m, const char *name) +{ + (void) name; + +#if defined(solaris) + if ( pthread_mutex_init(m, NULL) != 0 ) { + abort(); + } +#else + if (pthread_mutex_init(m, &_g_mattr.attr) != 0) { + abort(); + } +#endif + return 0; +} + +static inline int +ink_mutex_destroy(ink_mutex * m) +{ + return pthread_mutex_destroy(m); +} + +static inline int +ink_mutex_acquire(ink_mutex * m) +{ + if (pthread_mutex_lock(m) != 0) { + abort(); + } + return 0; +} + +static inline int +ink_mutex_release(ink_mutex * m) +{ + if (pthread_mutex_unlock(m) != 0) { + abort(); + } + return 0; +} + +static inline int +ink_mutex_try_acquire(ink_mutex * m) +{ + return pthread_mutex_trylock(m) == 0; +} + +#endif /* #if defined(POSIX_THREAD) */ + + +/* process mutex */ + +void ink_ProcessMutex_init(ProcessMutex *, const char *name); +void ink_ProcessMutex_destroy(ProcessMutex *); +void ink_ProcessMutex_acquire(ProcessMutex *); +void ink_ProcessMutex_release(ProcessMutex *); +int ink_ProcessMutex_try_acquire(ProcessMutex *); +void ink_ProcessMutex_print(FILE * out, ProcessMutex *); + + +#endif /* _ink_mutex_h_ */ diff --git a/lib/ts/ink_platform.h b/lib/ts/ink_platform.h new file mode 100644 index 00000000..f0848195 --- /dev/null +++ b/lib/ts/ink_platform.h @@ -0,0 +1,218 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_platform_h +#define _ink_platform_h + +#include "ink_config.h" + +#include +#include +#ifdef HAVE_STDLIB_H +# include +#endif +#include +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include + +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H +# include +#endif +#ifdef HAVE_NETINET_TCP_H +# include +#endif +#ifdef HAVE_NETINET_IP_H +# include +#endif +#ifdef HAVE_NETINET_IP_ICMP_H +# include +#endif +#ifdef HAVE_NETDB_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +# include +#endif + +#include +#ifdef HAVE_SIGINFO_H +# include +#endif +#ifdef HAVE_WAIT_H +# include +#endif + +#include +#include +#include + +#if TS_USE_EPOLL +#include +#endif +#if TS_USE_KQUEUE +#include +#endif +#if TS_USE_PORT +#include +#endif + + +#ifdef HAVE_VALUES_H +# include +#endif +#ifdef HAVE_ALLOCA_H +# include +#endif +#ifdef HAVE_MALLOC_H +# include +#endif + +#include +#include + +#ifdef HAVE_CPIO_H +# include +#endif + +struct ifafilt; +#include + +#ifdef HAVE_STROPTS_H +#include +#endif + +// +// Gnu C++ doesn't define __STDC__ == 0 as needed to +// have ip_hl be defined. +// +#if defined(__GNUC__) && !defined(__STDC__) +#define __STDC__ 0 +#endif + +#ifdef HAVE_MACHINE_ENDIAN_H +# include +#endif +#ifdef HAVE_ENDIAN_H +# include +#endif +#ifdef HAVE_SYS_BYTEORDER_H +# include +#endif + +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_SYS_SOCKIO_H +# include +#endif + +#include + + +#if defined(linux) +typedef unsigned int in_addr_t; +#endif + +#ifdef HAVE_SYS_SYSINFO_H +# include +#endif + +#if !defined(darwin) +# ifdef HAVE_SYS_SYSCTL_H +# include +# endif +#endif +#ifdef HAVE_SYS_SYSTEMINFO_H +# include +#endif + +#ifdef HAVE_DLFCN_H +# include +#endif +#ifdef HAVE_MATH_H +# include +#endif +#ifdef HAVE_FLOAT_H +# include +#endif + +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif + +#ifdef HAVE_SYS_PRCTL_H +#include +#endif + + +#ifndef PATH_NAME_MAX +#define PATH_NAME_MAX 511 // instead of PATH_MAX which is inconsistent + // on various OSs (linux-4096,osx/bsd-1024, + // windows-260,etc) +#endif + +#endif /* _ink_platform_h */ diff --git a/lib/ts/ink_port.h b/lib/ts/ink_port.h new file mode 100644 index 00000000..485c7253 --- /dev/null +++ b/lib/ts/ink_port.h @@ -0,0 +1,96 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Ink_port.h + + Definitions & declarations to faciliate inter-architecture portability. + + ****************************************************************************/ + +#if !defined (_ink_port_h_) +#define _ink_port_h_ + +#include "ink_config.h" +#include + +#ifdef HAVE_STDINT_H +#define __STDC_LIMIT_MACROS +# include +#else +// TODO: Add "standard" int types? +#endif + +#ifdef HAVE_INTTYPES_H +# define __STDC_FORMAT_MACROS 1 +# include +#else +// TODO: add PRI*64 stuff? +#endif + +#ifndef INT64_MIN +#define INT64_MAX (9223372036854775807LL) +#define INT64_MIN (-INT64_MAX -1LL) +#define INTU32_MAX (4294967295U) +#define INT32_MAX (2147483647) +#define INT32_MIN (-2147483647-1) +#endif +// Hack for MacOSX, have to take this out of the group above. +#ifndef INTU64_MAX +#define INTU64_MAX (18446744073709551615ULL) +#endif + +#define POSIX_THREAD +#define POSIX_THREAD_10031c + +#ifndef ETIME +#ifdef ETIMEDOUT +#define ETIME ETIMEDOUT +#endif +#endif + +#ifndef ENOTSUP +#ifdef EOPNOTSUPP +#define ENOTSUP EOPNOTSUPP +#endif +#endif + +#if defined(freebsd) +#define NO_MEMALIGN +#endif + +#if defined(darwin) +#define NO_MEMALIGN +#define RENTRENT_GETHOSTBYNAME +#define RENTRENT_GETHOSTBYADDR +#endif + +#define NUL '\0' + +// Need to use this to avoid problems when calling variadic functions +// with many arguments. In such cases, a raw '0' or NULL can be +// interpreted as 32 bits +#define NULL_PTR static_cast(0) + +#endif diff --git a/lib/ts/ink_queue.cc b/lib/ts/ink_queue.cc new file mode 100644 index 00000000..18d3b343 --- /dev/null +++ b/lib/ts/ink_queue.cc @@ -0,0 +1,687 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + ink_queue.cc (This used to be ink_queue.c) + + This implements an atomic push/pop queue, and the freelist memory + pools that are built from it. + + The change from ink_queue.cc to ink_queue.c resulted in some changes + in access and store of 64 bit values. This is standardized by using + the INK_QUEUE_LD64 macro which loads the version before the pointer + (independent of endianness of native architecture) on 32 bit platforms + or loads the 64 bit quantity directory on the DECs. + + + ****************************************************************************/ + +#include "ink_config.h" +#include +#include +#include +#include +#include +#include "ink_atomic.h" +#include "ink_queue.h" +#include "ink_memory.h" +#include "ink_error.h" +#include "ink_assert.h" +#include "ink_resource.h" + + +#ifdef __x86_64__ +#define INK_QUEUE_LD64(dst,src) *((uint64_t*)&(dst)) = *((uint64_t*)&(src)) +#else +#define INK_QUEUE_LD64(dst,src) (ink_queue_load_64((void *)&(dst), (void *)&(src))) +#endif + +typedef struct _ink_freelist_list +{ + InkFreeList *fl; + struct _ink_freelist_list *next; +} +ink_freelist_list; + +inkcoreapi volatile int64_t fastalloc_mem_in_use = 0; +inkcoreapi volatile int64_t fastalloc_mem_total = 0; + +/* + * SANITY and DEADBEEF are compute-intensive memory debugging to + * help in diagnosing freelist corruption. We turn them off in + * release builds. + */ + +#ifdef DEBUG +#define SANITY +#define DEADBEEF +// #define CHECK_DEADBEEF // broken +#endif + +// #define MEMPROTECT 1 + +#define MEMPROTECT_SIZE 0x200 + +#ifdef MEMPROTECT +static const int page_size = 8192; /* sysconf (_SC_PAGESIZE); */ +#endif + +static ink_freelist_list *freelists = NULL; + +inkcoreapi volatile int64_t freelist_allocated_mem = 0; + +#define fl_memadd(_x_) \ + ink_atomic_increment64(&freelist_allocated_mem, (int64_t) (_x_)); + +//static void ink_queue_load_64(void *dst, void *src) +//{ +// int32_t src_version = (*(head_p *) src).s.version; +// void *src_pointer = (*(head_p *) src).s.pointer; +// +// (*(head_p *) dst).s.version = src_version; +// (*(head_p *) dst).s.pointer = src_pointer; +//} + + +void +ink_freelist_init(InkFreeList * f, + const char *name, uint32_t type_size, uint32_t chunk_size, uint32_t offset, uint32_t alignment) +{ + ink_freelist_list *fll; + + /* its safe to add to this global list because ink_freelist_init() + is only called from single-threaded initialization code. */ + if ((fll = (ink_freelist_list *) ink_malloc(sizeof(ink_freelist_list))) != 0) { + fll->fl = f; + fll->next = freelists; + freelists = fll; + } + ink_assert(fll != NULL); + + f->name = name; + f->offset = offset; + /* quick test for power of 2 */ + ink_assert(!(alignment & (alignment - 1))); + f->alignment = alignment; + f->chunk_size = chunk_size; + f->type_size = type_size; +#if defined(INK_USE_MUTEX_FOR_FREELISTS) + ink_mutex_init(&(f->inkfreelist_mutex), name); +#endif +#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) + ink_mutex_init(&(f->freelist_mutex), name); + f->head = NULL; +#ifdef CHECK_FOR_DOUBLE_FREE + f->tail = NULL; +#endif +#else + SET_FREELIST_POINTER_VERSION(f->head, FROM_PTR(0), 0); +#endif + + f->count = 0; + f->allocated = 0; + f->allocated_base = 0; + f->count_base = 0; +} + +InkFreeList * +ink_freelist_create(const char *name, uint32_t type_size, uint32_t chunk_size, uint32_t offset, uint32_t alignment) +{ + InkFreeList *f = ink_type_malloc(InkFreeList); + ink_freelist_init(f, name, type_size, chunk_size, offset, alignment); + return f; +} + +#define ADDRESS_OF_NEXT(x, offset) ((void **)((char *)x + offset)) + +#ifdef SANITY +int fake_global_for_ink_queue = 0; +#endif + +int fastmemtotal = 0; + +#if defined(INK_USE_MUTEX_FOR_FREELISTS) +void * +ink_freelist_new_wrap(InkFreeList * f) +#else /* !INK_USE_MUTEX_FOR_FREELISTS */ +void * +ink_freelist_new(InkFreeList * f) +#endif /* !INK_USE_MUTEX_FOR_FREELISTS */ +{ //static uint32_t cntf = 0; + +#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) + void *foo; + uint32_t type_size = f->type_size; + + ink_mutex_acquire(&(f->freelist_mutex)); + ink_assert(f->type_size != 0); + + //printf("ink_freelist_new %d - %d - %u\n",f ->type_size,(f->head != NULL) ? 1 : 0,cntf++); + + + if (f->head != NULL) { + /* + * We have something on the free list.. + */ + void_p *h = (void_p *) f->head; +#ifdef CHECK_FOR_DOUBLE_FREE + if (f->head == f->tail) + f->tail = NULL; +#endif /* CHECK_FOR_DOUBLE_FREE */ + + foo = (void *) h; + f->head = (volatile void_p *) *h; + f->count += 1; + ink_mutex_release(&(f->freelist_mutex)); + return foo; + } else { + /* + * Might as well unlock the freelist mutex, since + * we're just going to do a malloc now.. + */ + uint32_t alignment; + +#ifdef MEMPROTECT + if (type_size >= MEMPROTECT_SIZE) { + if (f->alignment < page_size) + f->alignment = page_size; + type_size = ((type_size + page_size - 1) / page_size) * page_size * 2; + } +#endif /* MEMPROTECT */ + + alignment = f->alignment; + ink_mutex_release(&(f->freelist_mutex)); + + if (alignment) { + foo = ink_memalign(alignment, type_size); + } else { + foo = ink_malloc(type_size); + } + if (likely(foo)) + fl_memadd(type_size); + + +#ifdef MEMPROTECT + if (type_size >= MEMPROTECT_SIZE) { + if (mprotect((char *) foo + type_size - page_size, page_size, PROT_NONE) < 0) + perror("mprotect"); + } +#endif /* MEMPROTECT */ + return foo; + } + +#else /* #if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) */ + head_p item; + head_p next; + int result = 0; + + //printf("ink_freelist_new %d - %d - %u\n",f ->type_size,(f->head != NULL) ? 1 : 0,cntf++); + + + do { + INK_QUEUE_LD64(item, f->head); + if (TO_PTR(FREELIST_POINTER(item)) == NULL) { + uint32_t type_size = f->type_size; + uint32_t i; + +#ifdef MEMPROTECT + if (type_size >= MEMPROTECT_SIZE) { + if (f->alignment < page_size) + f->alignment = page_size; + type_size = ((type_size + page_size - 1) / page_size) * page_size * 2; + } +#endif /* MEMPROTECT */ + + void *newp = NULL; +#ifndef NO_MEMALIGN +#ifdef DEBUG + char *oldsbrk = (char *) sbrk(0), *newsbrk = NULL; +#endif + if (f->alignment) + newp = ink_memalign(f->alignment, f->chunk_size * type_size); + else + newp = ink_malloc(f->chunk_size * type_size); + if (newp) + fl_memadd(f->chunk_size * type_size); +#ifdef DEBUG + newsbrk = (char *) sbrk(0); + ink_atomic_increment(&fastmemtotal, newsbrk - oldsbrk); + /* printf("fastmem %d, %d, %d\n", f->chunk_size * type_size, + newsbrk - oldsbrk, fastmemtotal); */ +#endif + SET_FREELIST_POINTER_VERSION(item, newp, 0); +#else + uintptr_t add; + uintptr_t mask; + if (f->alignment) { + add = f->alignment - 1; + mask = ~(uintptr_t) add; + } else { + add = 0; + mask = ~0; + } + newp = ink_malloc(f->chunk_size * type_size + add); + if (newp) + fl_memadd(f->chunk_size * type_size + add); + newp = (void *) ((((uintptr_t) newp) + add) & mask); + SET_FREELIST_POINTER_VERSION(item, newp, 0); +#endif + +#if !defined(INK_USE_MUTEX_FOR_FREELISTS) + ink_atomic_increment((int *) &f->allocated, f->chunk_size); + ink_atomic_increment64(&fastalloc_mem_total, (int64_t) f->chunk_size * f->type_size); +#else + f->allocated += f->chunk_size; + fastalloc_mem_total += f->chunk_size * f->type_size; +#endif + + /* free each of the new elements */ + for (i = 0; i < f->chunk_size; i++) { + char *a = ((char *) FREELIST_POINTER(item)) + i * type_size; +#ifdef DEADBEEF + const char str[4] = { (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef }; + for (int j = 0; j < (int)type_size; j++) + a[j] = str[j % 4]; +#endif + ink_freelist_free(f, a); +#ifdef MEMPROTECT + if (f->type_size >= MEMPROTECT_SIZE) { + a += type_size - page_size; + if (mprotect(a, page_size, PROT_NONE) < 0) + perror("mprotect"); + } +#endif /* MEMPROTECT */ + + } +#if !defined(INK_USE_MUTEX_FOR_FREELISTS) + ink_atomic_increment((int *) &f->count, f->chunk_size); + ink_atomic_increment64(&fastalloc_mem_in_use, (int64_t) f->chunk_size * f->type_size); +#else + f->count += f->chunk_size; + fastalloc_mem_in_use += f->chunk_size * f->type_size; +#endif + + } else { + SET_FREELIST_POINTER_VERSION(next, *ADDRESS_OF_NEXT(TO_PTR(FREELIST_POINTER(item)), f->offset), + FREELIST_VERSION(item) + 1); +#if !defined(INK_USE_MUTEX_FOR_FREELISTS) + result = ink_atomic_cas64((int64_t *) & f->head.data, item.data, next.data); +#else + f->head.data = next.data; + result = 1; +#endif + +#ifdef SANITY + if (result) { + if (FREELIST_POINTER(item) == TO_PTR(FREELIST_POINTER(next))) + ink_fatal(1, "ink_freelist_new: loop detected"); + if (((uintptr_t) (TO_PTR(FREELIST_POINTER(next)))) & 3) + ink_fatal(1, "ink_freelist_new: bad list"); + if (TO_PTR(FREELIST_POINTER(next))) + fake_global_for_ink_queue = *(int *) TO_PTR(FREELIST_POINTER(next)); + } +#endif /* SANITY */ + + } + } + while (result == 0); + ink_assert(!((uintptr_t)TO_PTR(FREELIST_POINTER(item))&(((uintptr_t)f->alignment)-1))); + + ink_atomic_increment((int *) &f->count, 1); + ink_atomic_increment64(&fastalloc_mem_in_use, (int64_t) f->type_size); + + return TO_PTR(FREELIST_POINTER(item)); +#endif /* #if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) */ +} +typedef volatile void *volatile_void_p; + +#if defined(INK_USE_MUTEX_FOR_FREELISTS) +void +ink_freelist_free_wrap(InkFreeList * f, void *item) +#else /* !INK_USE_MUTEX_FOR_FREELISTS */ +void +ink_freelist_free(InkFreeList * f, void *item) +#endif /* !INK_USE_MUTEX_FOR_FREELISTS */ +{ +#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) + void_p *foo; + + //printf("ink_freelist_free\n"); + ink_mutex_acquire(&(f->freelist_mutex)); + + foo = (void_p *) item; +#ifdef CHECK_FOR_DOUBLE_FREE + void_p *p = (void_p *) f->head; + while (p) { + if (p == (void_p *) item) + ink_release_assert(!"ink_freelist_free: Double free"); + p = (void_p *) * p; + } + + if (f->tail) + *f->tail = foo; + *foo = (void_p) NULL; + + if (f->head == NULL) + f->head = foo; + f->tail = foo; +#else + *foo = (void_p) f->head; + f->head = foo; +#endif + f->count -= 1; + + ink_mutex_release(&(f->freelist_mutex)); +#else + + volatile_void_p *adr_of_next = (volatile_void_p *) ADDRESS_OF_NEXT(item, f->offset); + head_p h; + head_p item_pair; + int result; + + // ink_assert(!((long)item&(f->alignment-1))); XXX - why is this no longer working? -bcall + +#ifdef DEADBEEF + { + // set string to DEADBEEF + const char str[4] = { (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef }; +#ifdef CHECK_DEADBEEF + // search for DEADBEEF anywhere after a pointer offset in the item + char *position = (char *) item + sizeof(void *); // start + char *end = (char *) item + f->type_size; // end + + int i, j; + for (i = sizeof(void *) & 0x3, j = 0; position < end; ++position) { + if (i == j) { + if (*position == str[i]) { + if (j++ == 3) { + ink_fatal(1, "ink_freelist_free: trying to free item twice"); + } + } + } else { + j = 0; + } + i = (i + 1) & 0x3; + } +#endif + // set the entire item to DEADBEEF + for (int j = 0; j < (int)f->type_size; j++) + ((char*)item)[j] = str[j % 4]; + } +#endif /* DEADBEEF */ + + result = 0; + do { + INK_QUEUE_LD64(h, f->head); +#ifdef SANITY + if (TO_PTR(FREELIST_POINTER(h)) == item) + ink_fatal(1, "ink_freelist_free: trying to free item twice"); + if (((uintptr_t) (TO_PTR(FREELIST_POINTER(h)))) & 3) + ink_fatal(1, "ink_freelist_free: bad list"); + if (TO_PTR(FREELIST_POINTER(h))) + fake_global_for_ink_queue = *(int *) TO_PTR(FREELIST_POINTER(h)); +#endif /* SANITY */ + *adr_of_next = FREELIST_POINTER(h); + SET_FREELIST_POINTER_VERSION(item_pair, FROM_PTR(item), FREELIST_VERSION(h)); + INK_MEMORY_BARRIER; +#if !defined(INK_USE_MUTEX_FOR_FREELISTS) + result = ink_atomic_cas64((int64_t *) & f->head, h.data, item_pair.data); +#else + f->head.data = item_pair.data; + result = 1; +#endif + + } + while (result == 0); + + ink_atomic_increment((int *) &f->count, -1); + ink_atomic_increment64(&fastalloc_mem_in_use, -(int64_t) f->type_size); +#endif +} + +void +ink_freelists_snap_baseline() +{ + ink_freelist_list *fll; + fll = freelists; + while (fll) { + fll->fl->allocated_base = fll->fl->allocated; + fll->fl->count_base = fll->fl->count; + fll = fll->next; + } +} + +void +ink_freelists_dump_baselinerel(FILE * f) +{ + ink_freelist_list *fll; + if (f == NULL) + f = stderr; + + fprintf(f, " allocated | in-use | count | type size | free list name\n"); + fprintf(f, " relative to base | relative to base | | | \n"); + fprintf(f, "--------------------|--------------------|---------|------------|----------------------------------\n"); + + fll = freelists; + while (fll) { + int a = fll->fl->allocated - fll->fl->allocated_base; + if (a != 0) { + fprintf(f, " %18" PRIu64 " | %18" PRIu64 " | %7u | %10u | memory/%s\n", + (uint64_t)(fll->fl->allocated - fll->fl->allocated_base) * (uint64_t)fll->fl->type_size, + (uint64_t)(fll->fl->count - fll->fl->count_base) * (uint64_t)fll->fl->type_size, + fll->fl->count - fll->fl->count_base, fll->fl->type_size, fll->fl->name ? fll->fl->name : ""); + } + fll = fll->next; + } +} + +void +ink_freelists_dump(FILE * f) +{ + ink_freelist_list *fll; + if (f == NULL) + f = stderr; + + fprintf(f, " allocated | in-use | type size | free list name\n"); + fprintf(f, "--------------------|--------------------|------------|----------------------------------\n"); + + fll = freelists; + while (fll) { + fprintf(f, " %18" PRIu64 " | %18" PRIu64 " | %10u | memory/%s\n", + (uint64_t)fll->fl->allocated * (uint64_t)fll->fl->type_size, + (uint64_t)fll->fl->count * (uint64_t)fll->fl->type_size, fll->fl->type_size, fll->fl->name ? fll->fl->name : ""); + fll = fll->next; + } +} + + +#define INK_FREELIST_CREATE(T, n) \ +ink_freelist_create("", sizeof(T), n, (uintptr_t)&((T *)0)->next, 4) + +void +ink_atomiclist_init(InkAtomicList * l, const char *name, uint32_t offset_to_next) +{ +#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + ink_mutex_init(&(l->inkatomiclist_mutex), name); +#endif + l->name = name; + l->offset = offset_to_next; + SET_FREELIST_POINTER_VERSION(l->head, FROM_PTR(0), 0); +} + +#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS) +void * +ink_atomiclist_pop_wrap(InkAtomicList * l) +#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +void * +ink_atomiclist_pop(InkAtomicList * l) +#endif /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +{ + head_p item; + head_p next; + int result = 0; + do { + INK_QUEUE_LD64(item, l->head); + if (TO_PTR(FREELIST_POINTER(item)) == NULL) + return NULL; + SET_FREELIST_POINTER_VERSION(next, *ADDRESS_OF_NEXT(TO_PTR(FREELIST_POINTER(item)), l->offset), + FREELIST_VERSION(item) + 1); +#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + result = ink_atomic_cas64((int64_t *) & l->head.data, item.data, next.data); +#else + l->head.data = next.data; + result = 1; +#endif + + } + while (result == 0); + { + void *ret = TO_PTR(FREELIST_POINTER(item)); + *ADDRESS_OF_NEXT(ret, l->offset) = NULL; + return ret; + } +} + +#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS) +void * +ink_atomiclist_popall_wrap(InkAtomicList * l) +#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +void * +ink_atomiclist_popall(InkAtomicList * l) +#endif /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +{ + head_p item; + head_p next; + int result = 0; + do { + INK_QUEUE_LD64(item, l->head); + if (TO_PTR(FREELIST_POINTER(item)) == NULL) + return NULL; + SET_FREELIST_POINTER_VERSION(next, FROM_PTR(NULL), FREELIST_VERSION(item) + 1); +#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + result = ink_atomic_cas64((int64_t *) & l->head.data, item.data, next.data); +#else + l->head.data = next.data; + result = 1; +#endif + + } + while (result == 0); + { + void *ret = TO_PTR(FREELIST_POINTER(item)); + void *e = ret; + /* fixup forward pointers */ + while (e) { + void *n = TO_PTR(*ADDRESS_OF_NEXT(e, l->offset)); + *ADDRESS_OF_NEXT(e, l->offset) = n; + e = n; + } + return ret; + } +} + +#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS) +void * +ink_atomiclist_push_wrap(InkAtomicList * l, void *item) +#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +void * +ink_atomiclist_push(InkAtomicList * l, void *item) +#endif /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +{ + volatile_void_p *adr_of_next = (volatile_void_p *) ADDRESS_OF_NEXT(item, l->offset); + head_p head; + head_p item_pair; + int result = 0; + volatile void *h = NULL; + ink_assert(*adr_of_next == NULL); + do { + INK_QUEUE_LD64(head, l->head); + h = FREELIST_POINTER(head); + *adr_of_next = h; + ink_assert(item != TO_PTR(h)); + SET_FREELIST_POINTER_VERSION(item_pair, FROM_PTR(item), FREELIST_VERSION(head)); + INK_MEMORY_BARRIER; +#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + result = ink_atomic_cas64((int64_t *) & l->head, head.data, item_pair.data); +#else + l->head.data = item_pair.data; + result = 1; +#endif + + } + while (result == 0); + + return TO_PTR(h); +} + +#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS) +void * +ink_atomiclist_remove_wrap(InkAtomicList * l, void *item) +#else /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +void * +ink_atomiclist_remove(InkAtomicList * l, void *item) +#endif /* !INK_USE_MUTEX_FOR_ATOMICLISTS */ +{ + head_p head; + void *prev = NULL; + void **addr_next = ADDRESS_OF_NEXT(item, l->offset); + void *item_next = *addr_next; + int result = 0; + + /* + * first, try to pop it if it is first + */ + INK_QUEUE_LD64(head, l->head); + while (TO_PTR(FREELIST_POINTER(head)) == item) { + head_p next; + SET_FREELIST_POINTER_VERSION(next, item_next, FREELIST_VERSION(head) + 1); +#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + result = ink_atomic_cas64((int64_t *) & l->head.data, head.data, next.data); +#else + l->head.data = next.data; + result = 1; +#endif + if (result) { + *addr_next = NULL; + return item; + } + INK_QUEUE_LD64(head, l->head); + } + + /* + * then, go down the list, trying to remove it + */ + prev = TO_PTR(FREELIST_POINTER(head)); + while (prev) { + void **prev_adr_of_next = ADDRESS_OF_NEXT(prev, l->offset); + void *prev_prev = prev; + prev = TO_PTR(*prev_adr_of_next); + if (prev == item) { + ink_assert(prev_prev != item_next); + *prev_adr_of_next = item_next; + *addr_next = NULL; + return item; + } + } + return NULL; +} diff --git a/lib/ts/ink_queue.h b/lib/ts/ink_queue.h new file mode 100644 index 00000000..9fa70be4 --- /dev/null +++ b/lib/ts/ink_queue.h @@ -0,0 +1,262 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_queue_h_ +#define _ink_queue_h_ + +/*********************************************************************** + + Generic Queue Implementation (for pointer data types only) + + Uses atomic memory operations to avoid blocking. + Intended as a replacement for llqueue. + + +***********************************************************************/ + +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_apidefs.h" +#include "ink_unused.h" + +/* + For information on the structure of the x86_64 memory map: + + http://en.wikipedia.org/wiki/X86-64#Linux + + Essentially, in the current 48-bit implementations, the + top bit as well as the lower 47 bits are used, leaving + the upper-but one 16 bits free to be used for the version. + We will use the top-but-one 15 and sign extend when generating + the pointer was required by the standard. +*/ + +/* +#if defined(POSIX_THREAD) +#include +#include +#endif +*/ + +/* #define USE_SPINLOCK_FOR_FREELIST */ +/* #define CHECK_FOR_DOUBLE_FREE */ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + void ink_queue_load_64(void *dst, void *src); + +/* + * Generic Free List Manager + */ + + typedef union + { +#if (defined(__i386__) || defined(__arm__)) && (SIZEOF_VOIDP == 4) + struct + { + volatile void *pointer; + volatile int32_t version; + } s; +#endif + volatile int64_t data; + } head_p; + +/* + * Why is version required? One scenario is described below + * Think of a list like this -> A -> C -> D + * and you are popping from the list + * Between the time you take the ptr(A) and swap the head pointer + * the list could start looking like this + * -> A -> B -> C -> D + * If the version check is not there, the list will look like + * -> C -> D after the pop, which will result in the loss of "B" + */ +#define ZERO_HEAD_P(_x) + +#ifdef DEBUG +#define FROM_PTR(_x) (void*)(((uintptr_t)_x)+1) +#define TO_PTR(_x) (void*)(((uintptr_t)_x)-1) +#else +#define FROM_PTR(_x) ((void*)(_x)) +#define TO_PTR(_x) ((void*)(_x)) +#endif + +#if (defined(__i386__) || defined(__arm__)) && (SIZEOF_VOIDP == 4) +#define FREELIST_POINTER(_x) (_x).s.pointer +#define FREELIST_VERSION(_x) (_x).s.version +#define SET_FREELIST_POINTER_VERSION(_x,_p,_v) \ +(_x).s.pointer = _p; (_x).s.version = _v +#elif defined(__x86_64__) || defined(__ia64__) +#define FREELIST_POINTER(_x) ((void*)(((((intptr_t)(_x).data)<<16)>>16) | \ + (((~((((intptr_t)(_x).data)<<16>>63)-1))>>48)<<48))) // sign extend +#define FREELIST_VERSION(_x) (((intptr_t)(_x).data)>>48) +#define SET_FREELIST_POINTER_VERSION(_x,_p,_v) \ + (_x).data = ((((intptr_t)(_p))&0x0000FFFFFFFFFFFFULL) | (((_v)&0xFFFFULL) << 48)) +#else +#error "unsupported processor" +#endif + + typedef void *void_p; + + typedef struct + { +#if (defined(INK_USE_MUTEX_FOR_FREELISTS) || defined(CHECK_FOR_DOUBLE_FREE)) + ink_mutex inkfreelist_mutex; +#endif +#if (defined(USE_SPINLOCK_FOR_FREELIST) || defined(CHECK_FOR_DOUBLE_FREE)) + /* + This assumes we will never use anything other than Pthreads + on alpha + */ + ink_mutex freelist_mutex; + volatile void_p *head; +#ifdef CHECK_FOR_DOUBLE_FREE + volatile void_p *tail; +#endif +#else + volatile head_p head; +#endif + + const char *name; + uint32_t type_size, chunk_size, count, allocated, offset, alignment; + uint32_t allocated_base, count_base; + } InkFreeList, *PInkFreeList; + + inkcoreapi extern volatile int64_t fastalloc_mem_in_use; + inkcoreapi extern volatile int64_t fastalloc_mem_total; + inkcoreapi extern volatile int64_t freelist_allocated_mem; + +/* + * alignment must be a power of 2 + */ + InkFreeList *ink_freelist_create(const char *name, uint32_t type_size, + uint32_t chunk_size, uint32_t offset_to_next, uint32_t alignment); + + inkcoreapi void ink_freelist_init(InkFreeList * fl, const char *name, + uint32_t type_size, uint32_t chunk_size, + uint32_t offset_to_next, uint32_t alignment); +#if !defined(INK_USE_MUTEX_FOR_FREELISTS) + inkcoreapi void *ink_freelist_new(InkFreeList * f); + inkcoreapi void ink_freelist_free(InkFreeList * f, void *item); +#else /* INK_USE_MUTEX_FOR_FREELISTS */ + inkcoreapi void *ink_freelist_new_wrap(InkFreeList * f); + static inline void *ink_freelist_new(InkFreeList * f) + { + void *retval = NULL; + + ink_mutex_acquire(&(f->inkfreelist_mutex)); + retval = ink_freelist_new_wrap(f); + ink_mutex_release(&(f->inkfreelist_mutex)); + return retval; + } + + inkcoreapi void ink_freelist_free_wrap(InkFreeList * f, void *item); + static inline void ink_freelist_free(InkFreeList * f, void *item) + { + ink_mutex_acquire(&(f->inkfreelist_mutex)); + ink_freelist_free_wrap(f, item); + ink_mutex_release(&(f->inkfreelist_mutex)); + } +#endif /* INK_USE_MUTEX_FOR_FREELISTS */ + void ink_freelists_dump(FILE * f); + void ink_freelists_dump_baselinerel(FILE * f); + void ink_freelists_snap_baseline(); + + typedef struct + { +#if defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + ink_mutex inkatomiclist_mutex; +#endif + volatile head_p head; + const char *name; + uint32_t offset; + } InkAtomicList; + +#if !defined(INK_QUEUE_NT) +#define INK_ATOMICLIST_EMPTY(_x) (!(TO_PTR(FREELIST_POINTER((_x.head))))) +#else + /* ink_queue_nt.c doesn't do the FROM/TO pointer swizzling */ +#define INK_ATOMICLIST_EMPTY(_x) (!( (FREELIST_POINTER((_x.head))))) +#endif + + inkcoreapi void ink_atomiclist_init(InkAtomicList * l, const char *name, uint32_t offset_to_next); +#if !defined(INK_USE_MUTEX_FOR_ATOMICLISTS) + inkcoreapi void *ink_atomiclist_push(InkAtomicList * l, void *item); + void *ink_atomiclist_pop(InkAtomicList * l); + inkcoreapi void *ink_atomiclist_popall(InkAtomicList * l); +/* + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * only if only one thread is doing pops it is possible to have a "remove" + * which only that thread can use as well. + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + void *ink_atomiclist_remove(InkAtomicList * l, void *item); +#else /* INK_USE_MUTEX_FOR_ATOMICLISTS */ + void *ink_atomiclist_push_wrap(InkAtomicList * l, void *item); + static inline void *ink_atomiclist_push(InkAtomicList * l, void *item) + { + void *ret_value = NULL; + ink_mutex_acquire(&(l->inkatomiclist_mutex)); + ret_value = ink_atomiclist_push_wrap(l, item); + ink_mutex_release(&(l->inkatomiclist_mutex)); + return ret_value; + } + + void *ink_atomiclist_pop_wrap(InkAtomicList * l); + static inline void *ink_atomiclist_pop(InkAtomicList * l) + { + void *ret_value = NULL; + ink_mutex_acquire(&(l->inkatomiclist_mutex)); + ret_value = ink_atomiclist_pop_wrap(l); + ink_mutex_release(&(l->inkatomiclist_mutex)); + return ret_value; + } + + void *ink_atomiclist_popall_wrap(InkAtomicList * l); + static inline void *ink_atomiclist_popall(InkAtomicList * l) + { + void *ret_value = NULL; + ink_mutex_acquire(&(l->inkatomiclist_mutex)); + ret_value = ink_atomiclist_popall_wrap(l); + ink_mutex_release(&(l->inkatomiclist_mutex)); + return ret_value; + } + + void *ink_atomiclist_remove_wrap(InkAtomicList * l, void *item); + static inline void *ink_atomiclist_remove(InkAtomicList * l, void *item) + { + void *ret_value = NULL; + ink_mutex_acquire(&(l->inkatomiclist_mutex)); + ret_value = ink_atomiclist_remove_wrap(l, item); + ink_mutex_release(&(l->inkatomiclist_mutex)); + return ret_value; + } +#endif /* INK_USE_MUTEX_FOR_ATOMICLISTS */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _ink_queue_h_ */ diff --git a/lib/ts/ink_queue_utils.cc b/lib/ts/ink_queue_utils.cc new file mode 100644 index 00000000..c249e77c --- /dev/null +++ b/lib/ts/ink_queue_utils.cc @@ -0,0 +1,81 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_config.h" +#include + +#include "ink_atomic.h" +#include "ink_unused.h" +#include "ink_queue.h" + +/* + * This file was added during the debugging of Bug 50475. + * It was found that a race condition was introduced on the sparc architecture + * when the ink_queue.c file was moved over to ink_queue.cc. Debugging this + * problem resulted in the discovery that gcc was spitting out the + * "ldd" (load double) instruction for loading of the 64 bit field "data" + * while CC was spitting out two "ld" (load) instructions. The old code + * was calling item.data = head.data on sparcs and not putting any restriction + * on the order of loading of the fields. + * + * This is a problem on the sparcs because the "pointer" field was being loaded + * before the "version" field. This can result in a very subtle race condition + * which subverts the addition of the "version" field. + * + * Take this scenario + * item.ptr = head.ptr + * (call to ink_freelist_new ) + * next.ptr = *(item.ptr) <---- Error + * (call to ink_freelist_free ) + * item.version = head.version + * next.version = item.version ++; + * cas64(head, item, next) + + * Note, that the cas64 call will be succesful and the next.ptr will probably + * be a pointer into the vtable entry. The next alloc will result in a write into + * the vtable area. + * + * The fix for this problem is to read the version before reading the pointer + * on 32 bit architectures (currently everything other than alphas). This is + * done using the following function. This file only contains one function + * to make looking at the assembly code simple. + * + * If you ever change the compiler or the compiler options to this file, make + * sure you look at the assembly generated to see if the version is read first. + * Also, make sure that you run the test_freelist microbenchmark for at least + * 24 hours on a dual processor box. + */ + +void +ink_queue_load_64(void *dst, void *src) +{ +#if (defined(__i386__) || defined(__arm__)) && (SIZEOF_VOIDP == 4) + volatile int32_t src_version = (*(head_p *) src).s.version; + volatile void *src_pointer = (*(head_p *) src).s.pointer; + + (*(head_p *) dst).s.version = src_version; + (*(head_p *) dst).s.pointer = src_pointer; +#else + *(void**)dst = *(void**)src; +#endif +} diff --git a/lib/ts/ink_rand.cc b/lib/ts/ink_rand.cc new file mode 100644 index 00000000..1736ee7f --- /dev/null +++ b/lib/ts/ink_rand.cc @@ -0,0 +1,109 @@ +/** @file + + A C-program for MT19937-64 (2004/9/29 version). + Coded by Takuji Nishimura and Makoto Matsumoto. + + This is a 64-bit version of Mersenne Twister pseudorandom number + generator. + + Before using, initialize the state by using init_genrand64(seed) + or init_by_array64(init_key, key_length). + + Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + References: + T. Nishimura, ``Tables of 64-bit Mersenne Twisters'' + ACM Transactions on Modeling and + Computer Simulation 10. (2000) 348--357. + M. Matsumoto and T. Nishimura, + ``Mersenne Twister: a 623-dimensionally equidistributed + uniform pseudorandom number generator'' + ACM Transactions on Modeling and + Computer Simulation 8. (Jan. 1998) 3--30. + + Any feedback is very welcome. + http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces) +*/ + + +#include "libts.h" + +#define NN 312 +#define MM 156 +#define MATRIX_A 0xB5026F5AA96619E9ULL +#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */ +#define LM 0x7FFFFFFFULL /* Least significant 31 bits */ + +static uint64_t mag01[2]={0ULL, MATRIX_A}; + +InkRand::InkRand(uint64_t d) { + seed(d); +} + +void InkRand::seed(uint64_t seed) { + mt[0] = seed; + for (mti=1; mti> 62)) + mti); +} + +uint64_t InkRand::random() { + int i; + uint64_t x; + + if (mti >= NN) { /* generate NN words at one time */ + for (i=0;i>1) ^ mag01[(int)(x&1ULL)]; + } + for (;i>1) ^ mag01[(int)(x&1ULL)]; + } + x = (mt[NN-1]&UM)|(mt[0]&LM); + mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)]; + + mti = 0; + } + + x = mt[mti++]; + + x ^= (x >> 29) & 0x5555555555555555ULL; + x ^= (x << 17) & 0x71D67FFFEDA60000ULL; + x ^= (x << 37) & 0xFFF7EEE000000000ULL; + x ^= (x >> 43); + + return x; +} + +double InkRand::drandom() { + return (random() >> 11) * (1.0/9007199254740991.0); +} diff --git a/lib/ts/ink_rand.h b/lib/ts/ink_rand.h new file mode 100644 index 00000000..2e5e3985 --- /dev/null +++ b/lib/ts/ink_rand.h @@ -0,0 +1,88 @@ +/** @file + + Mersenne Twister declarations adapted for Traffic Server + + @section license License + + A C-program for MT19937-64 (2004/9/29 version). + Coded by Takuji Nishimura and Makoto Matsumoto. + + This is a 64-bit version of Mersenne Twister pseudorandom number + generator. + + Before using, initialize the state by using init_genrand64(seed) + or init_by_array64(init_key, key_length). + + Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + References: + T. Nishimura, ``Tables of 64-bit Mersenne Twisters'' + ACM Transactions on Modeling and + Computer Simulation 10. (2000) 348--357. + M. Matsumoto and T. Nishimura, + ``Mersenne Twister: a 623-dimensionally equidistributed + uniform pseudorandom number generator'' + ACM Transactions on Modeling and + Computer Simulation 8. (Jan. 1998) 3--30. + + Any feedback is very welcome. + http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces) +*/ + +#ifndef __INK_RAND_H__ +#define __INK_RAND_H__ + + +#include "ink_port.h" +#include "ink_apidefs.h" + + +class InkRand +{ +public: + InkRand(uint64_t d); + + void seed(uint64_t d); + inkcoreapi uint64_t random(); + double drandom(); + +private: + uint64_t mt[312]; + int mti; +}; + +inline int ink_rand_r(uint32_t * p) { + return (((*p) = (*p) * 1103515245 + 12345) % ((uint32_t) 0x7fffffff + 1)); +} + +#endif /* __INK_RAND_H__ */ + diff --git a/lib/ts/ink_res_init.cc b/lib/ts/ink_res_init.cc new file mode 100644 index 00000000..e56fc105 --- /dev/null +++ b/lib/ts/ink_res_init.cc @@ -0,0 +1,653 @@ +/* + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#if !defined (_WIN32) + +#include "ink_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif +#include +#include +#include +#include +#include +#include + +#include "ink_string.h" +#include "ink_resolver.h" + +#if !defined(linux) +int inet_aton(register const char *cp, struct in_addr *addr); +#endif + +#if !defined(isascii) /* XXX - could be a function */ +# define isascii(c) (!(c & 0200)) +#endif + +#define DOT_SEPARATED(_x) \ + ((unsigned char*)&(_x))[0], ((unsigned char*)&(_x))[1], \ + ((unsigned char*)&(_x))[2], ((unsigned char*)&(_x))[3] + +/*% + * This routine is for closing the socket if a virtual circuit is used and + * the program wants to close it. This provides support for endhostent() + * which expects to close the socket. + * + * This routine is not expected to be user visible. + */ +static void +ink_res_nclose(ink_res_state statp) { + if (statp->_vcsock >= 0) { + (void) close(statp->_vcsock); + statp->_vcsock = -1; + statp->_flags &= ~(INK_RES_F_VC | INK_RES_F_CONN); + } +} + +static void +ink_res_ndestroy(ink_res_state statp) { + ink_res_nclose(statp); + if (statp->_u._ext.ext != NULL) + free(statp->_u._ext.ext); + statp->options &= ~INK_RES_INIT; + statp->_u._ext.ext = NULL; +} + +static void +ink_res_setservers(ink_res_state statp, const union ink_res_sockaddr_union *set, int cnt) { + int i, nserv; + size_t size; + + /* close open servers */ + ink_res_nclose(statp); + + /* cause rtt times to be forgotten */ + statp->_u._ext.nscount = 0; + + nserv = 0; + for (i = 0; i < cnt && nserv < INK_MAXNS; i++) { + switch (set->sin.sin_family) { + case AF_INET: + size = sizeof(set->sin); + if (statp->_u._ext.ext) + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &set->sin, size); + if (size <= sizeof(statp->nsaddr_list[nserv].sin)) + memcpy(&statp->nsaddr_list[nserv].sin, &set->sin, size); + else + statp->nsaddr_list[nserv].sin.sin_family = 0; + nserv++; + break; + +#ifdef HAS_INET6_STRUCTS + case AF_INET6: + size = sizeof(set->sin6); + if (statp->_u._ext.ext) + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &set->sin6, size); + if (size <= sizeof(statp->nsaddr_list[nserv].sin6)) + memcpy(&statp->nsaddr_list[nserv].sin6, &set->sin6, size); + else + statp->nsaddr_list[nserv].sin6.sin6_family = 0; + nserv++; + break; +#endif + + default: + break; + } + set++; + } + statp->nscount = nserv; +} + +int +ink_res_getservers(ink_res_state statp, union ink_res_sockaddr_union *set, int cnt) { + int i; + size_t size; + u_int16_t family; + + for (i = 0; i < statp->nscount && i < cnt; i++) { + if (statp->_u._ext.ext) + family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; + else + family = statp->nsaddr_list[i].sin.sin_family; + + switch (family) { + case AF_INET: + size = sizeof(set->sin); + if (statp->_u._ext.ext) + memcpy(&set->sin, &statp->_u._ext.ext->nsaddrs[i], size); + else + memcpy(&set->sin, &statp->nsaddr_list[i].sin, size); + break; + +#ifdef HAS_INET6_STRUCTS + case AF_INET6: + size = sizeof(set->sin6); + if (statp->_u._ext.ext) + memcpy(&set->sin6, &statp->_u._ext.ext->nsaddrs[i], size); + else + memcpy(&set->sin6, &statp->nsaddr_list[i].sin6, size); + break; +#endif + + default: + set->sin.sin_family = 0; + break; + } + set++; + } + return (statp->nscount); +} + +static void +ink_res_setoptions(ink_res_state statp, const char *options, const char *source) +{ + NOWARN_UNUSED(source); + const char *cp = options; + int i; + +#ifdef DEBUG + if (statp->options & INK_RES_DEBUG) + printf(";; res_setoptions(\"%s\", \"%s\")...\n", options, source); +#endif + while (*cp) { + /* skip leading and inner runs of spaces */ + while (*cp == ' ' || *cp == '\t') + cp++; + /* search for and process individual options */ + if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { + i = atoi(cp + sizeof("ndots:") - 1); + if (i <= INK_RES_MAXNDOTS) + statp->ndots = i; + else + statp->ndots = INK_RES_MAXNDOTS; +#ifdef DEBUG + if (statp->options & INK_RES_DEBUG) + printf(";;\tndots=%d\n", statp->ndots); +#endif + } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { + i = atoi(cp + sizeof("timeout:") - 1); + if (i <= INK_RES_MAXRETRANS) + statp->retrans = i; + else + statp->retrans = INK_RES_MAXRETRANS; +#ifdef DEBUG + if (statp->options & INK_RES_DEBUG) + printf(";;\ttimeout=%d\n", statp->retrans); +#endif +#ifdef SOLARIS2 + } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) { + /* + * For backward compatibility, 'retrans' is + * supported as an alias for 'timeout', though + * without an imposed maximum. + */ + statp->retrans = atoi(cp + sizeof("retrans:") - 1); + } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){ + /* + * For backward compatibility, 'retry' is + * supported as an alias for 'attempts', though + * without an imposed maximum. + */ + statp->retry = atoi(cp + sizeof("retry:") - 1); +#endif /* SOLARIS2 */ + } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ + i = atoi(cp + sizeof("attempts:") - 1); + if (i <= INK_RES_MAXRETRY) + statp->retry = i; + else + statp->retry = INK_RES_MAXRETRY; +#ifdef DEBUG + if (statp->options & INK_RES_DEBUG) + printf(";;\tattempts=%d\n", statp->retry); +#endif + } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { +#ifdef DEBUG + if (!(statp->options & INK_RES_DEBUG)) { + printf(";; res_setoptions(\"%s\", \"%s\")..\n", options, source); + statp->options |= INK_RES_DEBUG; + } + printf(";;\tdebug\n"); +#endif + } else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1) || + !strncmp(cp, "no-tld-query", sizeof("no-tld-query") - 1)) { + statp->options |= INK_RES_NOTLDQUERY; + } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { + statp->options |= INK_RES_USE_INET6; + } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { + statp->options |= INK_RES_ROTATE; + } else if (!strncmp(cp, "no-check-names", sizeof("no-check-names") - 1)) { + statp->options |= INK_RES_NOCHECKNAME; + } +#ifdef INK_RES_USE_EDNS0 + else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { + statp->options |= INK_RES_USE_EDNS0; + } +#endif + else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { + statp->options |= INK_RES_USE_DNAME; + } + else { + /* XXX - print a warning here? */ + } + /* skip to next run of spaces */ + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } +} + +static u_int +ink_res_randomid(void) { + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} + +/*% + * Set up default settings. If the configuration file exist, the values + * there will have precedence. Otherwise, the server address is set to + * INADDR_ANY and the default domain name comes from the gethostname(). + * + * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 + * rather than INADDR_ANY ("0.0.0.0") as the default name server address + * since it was noted that INADDR_ANY actually meant ``the first interface + * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, + * it had to be "up" in order for you to reach your own name server. It + * was later decided that since the recommended practice is to always + * install local static routes through 127.0.0.1 for all your network + * interfaces, that we could solve this problem without a code change. + * + * The configuration file should always be used, since it is the only way + * to specify a default domain. If you are running a server on your local + * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" + * in the configuration file. + * + * Return 0 if completes successfully, -1 on error + */ +/*% This function has to be reachable by res_data.c but not publically. */ +int +ink_res_init(ink_res_state statp, const unsigned int *pHostList, const int *pPort, const char *pDefDomain, const char *pSearchList, + const char *pResolvConf) { + register FILE *fp; + register char *cp, **pp; + register int n; + char buf[BUFSIZ]; + int nserv = 0; + int haveenv = 0; + int havesearch = 0; + int dots; + int maxns = INK_MAXNS; + + // INK_RES_SET_H_ERRNO(statp, 0); + statp->res_h_errno = 0; + if (statp->_u._ext.ext != NULL) + ink_res_ndestroy(statp); + + statp->retrans = INK_RES_TIMEOUT; + statp->retry = INK_RES_DFLRETRY; + statp->options = INK_RES_DEFAULT; + statp->id = ink_res_randomid(); + + statp->nscount = 0; + statp->ndots = 1; + statp->pfcode = 0; + statp->_vcsock = -1; + statp->_flags = 0; + statp->qhook = NULL; + statp->rhook = NULL; + statp->_u._ext.nscount = 0; + statp->_u._ext.ext = (struct __ink_res_state_ext*)malloc(sizeof(*statp->_u._ext.ext)); + if (statp->_u._ext.ext != NULL) { + memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); + statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr_list[0].sin; + } else { + /* + * Historically res_init() rarely, if at all, failed. + * Examples and applications exist which do not check + * our return code. Furthermore several applications + * simply call us to get the systems domainname. So + * rather then immediately fail here we store the + * failure, which is returned later, in h_errno. And + * prevent the collection of 'nameserver' information + * by setting maxns to 0. Thus applications that fail + * to check our return code wont be able to make + * queries anyhow. + */ + // INK_RES_SET_H_ERRNO(statp, NETDB_INTERNAL); + statp->res_h_errno = NETDB_INTERNAL; + maxns = 0; + } + +#ifdef SOLARIS2 + /* + * The old libresolv derived the defaultdomain from NIS/NIS+. + * We want to keep this behaviour + */ + { + char buf[sizeof(statp->defdname)], *cp; + int ret; + + if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 && + (unsigned int)ret <= sizeof(buf)) { + if (buf[0] == '+') + buf[0] = '.'; + cp = strchr(buf, '.'); + cp = (cp == NULL) ? buf : (cp + 1); + strncpy(statp->defdname, cp, + sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + } + } +#endif /* SOLARIS2 */ + + /* Allow user to override the local domain definition */ + if ((cp = getenv("LOCALDOMAIN")) != NULL) { + (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + haveenv++; + + /* + * Set search list to be blank-separated strings + * from rest of env value. Permits users of LOCALDOMAIN + * to still have a search list, and anyone to set the + * one that they want to use as an individual (even more + * important now that the rfc1535 stuff restricts searches) + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + INK_MAXDNSRCH; cp++) { + if (*cp == '\n') /*%< silly backwards compat */ + break; + else if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + havesearch = 1; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp = '\0'; + *pp++ = 0; + } + + /* --------------------------------------------- + Default domain name and doamin Search list: + + if we are supplied a default domain name, + and/or search list we will use it. Otherwise, + we will skip to using what is present in the + conf file + ---------------------------------------------- */ + + if (pDefDomain && '\0' != *pDefDomain && '\n' != *pDefDomain) { + strncpy(statp->defdname, pDefDomain, sizeof(statp->defdname) - 1); + if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) + *cp = '\0'; + } + if (pSearchList && '\0' != *pSearchList && '\n' != *pSearchList) { + strncpy(statp->defdname, pSearchList, sizeof(statp->defdname) - 1); + if ((cp = strchr(statp->defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + INK_MAXDNSRCH; cp++) { + if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cp = '\0'; + *pp++ = 0; + havesearch = 1; + } + + /* ------------------------------------------- + we must be provided with atleast a named! + ------------------------------------------- */ + /* TODO we should figure out the IPV6 resolvers here. */ + while (pHostList && pHostList[nserv] != 0 && nserv < INK_MAXNS) { + statp->nsaddr_list[nserv].sin.sin_addr.s_addr = pHostList[nserv]; + statp->nsaddr_list[nserv].sin.sin_family = AF_INET; + statp->nsaddr_list[nserv].sin.sin_port = htons(pPort[nserv]); + nserv++; + } + +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + + if ((fp = fopen(pResolvConf, "r")) != NULL) { + /* read the config file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* skip comments */ + if (*buf == ';' || *buf == '#') + continue; + /* read default domain name */ + if (MATCH(buf, "domain")) { + if (haveenv) /*%< skip if have from environ */ + continue; + cp = buf + sizeof("domain") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) + *cp = '\0'; + havesearch = 0; + continue; + } + /* set search list */ + if (MATCH(buf, "search")) { + if (haveenv) /*%< skip if have from environ */ + continue; + cp = buf + sizeof("search") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); + statp->defdname[sizeof(statp->defdname) - 1] = '\0'; + if ((cp = strchr(statp->defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = statp->defdname; + pp = statp->dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < statp->dnsrch + INK_MAXDNSRCH; cp++) { + if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cp = '\0'; + *pp++ = 0; + havesearch = 1; + continue; + } + /* read nameservers to query */ + if (MATCH(buf, "nameserver") && nserv < maxns) { + struct addrinfo hints, *ai; + char sbuf[NI_MAXSERV]; + const size_t minsiz = + sizeof(statp->_u._ext.ext->nsaddrs[0]); + + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + cp[strcspn(cp, ";# \t\n")] = '\0'; + if ((*cp != '\0') && (*cp != '\n')) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + sprintf(sbuf, "%d", NAMESERVER_PORT); + if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && + ai->ai_addrlen <= minsiz) { + if (statp->_u._ext.ext != NULL) { + memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); + } + if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv].sin)) { + memcpy(&statp->nsaddr_list[nserv].sin, ai->ai_addr, ai->ai_addrlen); + } else + statp->nsaddr_list[nserv].sin.sin_family = 0; + freeaddrinfo(ai); + nserv++; + } + } + continue; + } + if (MATCH(buf, "options")) { + ink_res_setoptions(statp, buf + sizeof("options") - 1, "conf"); + continue; + } + } + (void) fclose(fp); + } + + if (nserv > 0) + statp->nscount = nserv; + + if (statp->defdname[0] == 0 && gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) + strcpy(statp->defdname, cp + 1); + + /* find components of local domain that might be searched */ + if (havesearch == 0) { + pp = statp->dnsrch; + *pp++ = statp->defdname; + *pp = NULL; + + dots = 0; + for (cp = statp->defdname; *cp; cp++) + dots += (*cp == '.'); + + cp = statp->defdname; + while (pp < statp->dnsrch + INK_MAXDFLSRCH) { + if (dots < INK_LOCALDOMAINPARTS) + break; + cp = strchr(cp, '.') + 1; /*%< we know there is one */ + *pp++ = cp; + dots--; + } + *pp = NULL; +#ifdef DEBUG + if (statp->options & INK_RES_DEBUG) { + printf(";; res_init()... default dnsrch list:\n"); + for (pp = statp->dnsrch; *pp; pp++) + printf(";;\t%s\n", *pp); + printf(";;\t..END..\n"); + } +#endif + } + + /* export all ns servers to DNSprocessor. */ + ink_res_setservers(statp, &statp->nsaddr_list[0], statp->nscount); + + if ((cp = getenv("RES_OPTIONS")) != NULL) + ink_res_setoptions(statp, cp, "env"); + statp->options |= INK_RES_INIT; + return (statp->res_h_errno); +} + +#endif diff --git a/lib/ts/ink_res_mkquery.cc b/lib/ts/ink_res_mkquery.cc new file mode 100644 index 00000000..3bd73f8b --- /dev/null +++ b/lib/ts/ink_res_mkquery.cc @@ -0,0 +1,503 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + + +#include "ink_config.h" + +#include +#include +#include +#include +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif +#include +#include +#include +#include + +#include "ink_defs.h" +#include "ink_resolver.h" + +#define SPRINTF(x) (sprintf x) + +/*% + * Form all types of queries. + * Returns the size of the result or -1. + */ +int +ink_res_mkquery(ink_res_state statp, + int op, /*!< opcode of query */ + const char *dname, /*!< domain name */ + int _class, int type, /*!< _class and type of query */ + const u_char *data, /*!< resource record data */ + int datalen, /*!< length of data */ + const u_char *newrr_in, /*!< new rr for modify or append */ + u_char *buf, /*!< buffer to put query */ + int buflen) /*!< size of buffer */ +{ + register HEADER *hp; + register u_char *cp, *ep; + register int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + + NOWARN_UNUSED(newrr_in); + + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + memset(buf, 0, HFIXEDSZ); + hp = (HEADER *) buf; + hp->id = htons(++statp->id); + hp->opcode = op; + hp->rd = (statp->options & INK_RES_RECURSE) != 0U; + hp->rcode = NOERROR; + cp = buf + HFIXEDSZ; + ep = buf + buflen; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: + if (ep - cp < QFIXEDSZ) + return (-1); + if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, + lastdnptr)) < 0) + return (-1); + cp += n; + NS_PUT16(type, cp); + NS_PUT16(_class, cp); + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + if ((ep - cp) < RRFIXEDSZ) + return (-1); + n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ, + dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + NS_PUT16(T_NULL, cp); + NS_PUT16(_class, cp); + NS_PUT32(0, cp); + NS_PUT16(0, cp); + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (ep - cp < 1 + RRFIXEDSZ + datalen) + return (-1); + *cp++ = '\0'; /*%< no domain name */ + NS_PUT16(type, cp); + NS_PUT16(_class, cp); + NS_PUT32(0, cp); + NS_PUT16(datalen, cp); + if (datalen) { + memcpy(cp, data, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return (-1); + } + return (cp - buf); +} + +/* Public. */ + +/*% + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * + * return: + *\li boolean. + */ +static int +printable(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +static const char digits[] = "0123456789"; + +static int +labellen(const u_char *lp) +{ + int bitlen; + u_char l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* should be avoided by the caller */ + return(-1); + } + + if ((l & NS_CMPRSFLGS) == INK_NS_TYPE_ELT) { + if (l == INK_DNS_LABELTYPE_BITSTRING) { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return((bitlen + 7 ) / 8 + 1); + } + return(-1); /*%< unknwon ELT */ + } + return(l); +} + +static int +decode_bitstring(const unsigned char **cpp, char *dn, const char *eom) +{ + const unsigned char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen, i; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return(-1); + + cp++; + i = SPRINTF((dn, "\\[x")); + if (i < 0) + return (-1); + dn += i; + for (b = blen; b > 7; b -= 8, cp++) { + i = SPRINTF((dn, "%02x", *cp & 0xff)); + if (i < 0) + return (-1); + dn += i; + } + if (b > 4) { + tc = *cp++; + i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); + if (i < 0) + return (-1); + dn += i; + } else if (b > 0) { + tc = *cp++; + i = SPRINTF((dn, "%1x", + ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); + if (i < 0) + return (-1); + dn += i; + } + i = SPRINTF((dn, "/%d]", blen)); + if (i < 0) + return (-1); + dn += i; + + *cpp = cp; + return(dn - beg); +} + +/*% + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * + * return: + *\li boolean. + */ +static int +special(int ch) { + switch (ch) { + case 0x22: /*%< '"' */ + case 0x2E: /*%< '.' */ + case 0x3B: /*%< ';' */ + case 0x5C: /*%< '\\' */ + case 0x28: /*%< '(' */ + case 0x29: /*%< ')' */ + /* Special modifiers in zone files. */ + case 0x40: /*%< '@' */ + case 0x24: /*%< '$' */ + return (1); + default: + return (0); + } +} + +/*% + * Convert an encoded domain name to printable ascii as per RFC1035. + + * return: + *\li Number of bytes written to buffer, or -1 (with errno set) + * + * notes: + *\li The root is returned as "." + *\li All other domains are returned in non absolute form + */ +int +ink_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) +{ + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /*%< XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == INK_NS_TYPE_ELT) { + int m; + + if (n != INK_DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for ((void)NULL; l > 0; l--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +/*% + * Convert an encoded domain name to printable ascii as per RFC1035. + + * return: + *\li Number of bytes written to buffer, or -1 (with errno set) + * + * notes: + *\li The root is returned as "." + *\li All other domains are returned in non absolute form + */ +#if defined(linux) +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) __THROW +#else +int +ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) +#endif +{ + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen(cp - 1)) < 0) { + errno = EMSGSIZE; /*%< XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == INK_NS_TYPE_ELT) { + int m; + + if (n != INK_DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = decode_bitstring(&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for ((void)NULL; l > 0; l--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} diff --git a/lib/ts/ink_resolver.h b/lib/ts/ink_resolver.h new file mode 100644 index 00000000..52de2e21 --- /dev/null +++ b/lib/ts/ink_resolver.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 1983, 1987, 1989 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + Imported from Bind-9.5.2-P2 + + Changes: + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef _ink_resolver_h_ +#define _ink_resolver_h_ + +#include "ink_platform.h" +#include +#include +#ifdef HAVE_NET_PPP_DEFS_H +#include +#endif + +#define INK_RES_F_VC 0x00000001 /*%< socket is TCP */ +#define INK_RES_F_CONN 0x00000002 /*%< socket is connected */ +#define INK_RES_F_EDNS0ERR 0x00000004 /*%< EDNS0 caused errors */ +#define INK_RES_F__UNUSED 0x00000008 /*%< (unused) */ +#define INK_RES_F_LASTMASK 0x000000F0 /*%< ordinal server of last res_nsend */ +#define INK_RES_F_LASTSHIFT 4 /*%< bit position of LASTMASK "flag" */ +#define INK_RES_GETLAST(res) (((res)._flags & INK_RES_F_LASTMASK) >> INK_RES_F_LASTSHIFT) + +/* res_findzonecut2() options */ +#define INK_RES_EXHAUSTIVE 0x00000001 /*%< always do all queries */ +#define INK_RES_IPV4ONLY 0x00000002 /*%< IPv4 only */ +#define INK_RES_IPV6ONLY 0x00000004 /*%< IPv6 only */ + +/*% + * * Resolver options (keep these in synch with res_debug.c, please) + * */ +#define INK_RES_INIT 0x00000001 /*%< address initialized */ +#define INK_RES_DEBUG 0x00000002 /*%< print debug messages */ +#define INK_RES_AAONLY 0x00000004 /*%< authoritative answers only (!IMPL)*/ +#define INK_RES_USEVC 0x00000008 /*%< use virtual circuit */ +#define INK_RES_PRIMARY 0x00000010 /*%< query primary server only (!IMPL) */ +#define INK_RES_IGNTC 0x00000020 /*%< ignore trucation errors */ +#define INK_RES_RECURSE 0x00000040 /*%< recursion desired */ +#define INK_RES_DEFNAMES 0x00000080 /*%< use default domain name */ +#define INK_RES_STAYOPEN 0x00000100 /*%< Keep TCP socket open */ +#define INK_RES_DNSRCH 0x00000200 /*%< search up local domain tree */ +#define INK_RES_INSECURE1 0x00000400 /*%< type 1 security disabled */ +#define INK_RES_INSECURE2 0x00000800 /*%< type 2 security disabled */ +#define INK_RES_NOALIASES 0x00001000 /*%< shuts off HOSTALIASES feature */ +#define INK_RES_USE_INET6 0x00002000 /*%< use/map IPv6 in gethostbyname() */ +#define INK_RES_ROTATE 0x00004000 /*%< rotate ns list after each query */ +#define INK_RES_NOCHECKNAME 0x00008000 /*%< do not check names for sanity. */ +#define INK_RES_KEEPTSIG 0x00010000 /*%< do not strip TSIG records */ +#define INK_RES_BLAST 0x00020000 /*%< blast all recursive servers */ +#define INK_RES_NSID 0x00040000 /*%< request name server ID */ +#define INK_RES_NOTLDQUERY 0x00100000 /*%< don't unqualified name as a tld */ +#define INK_RES_USE_DNSSEC 0x00200000 /*%< use DNSSEC using OK bit in OPT */ +/* #define INK_RES_DEBUG2 0x00400000 */ /* nslookup internal */ +/* KAME extensions: use higher bit to avoid conflict with ISC use */ +#define INK_RES_USE_DNAME 0x10000000 /*%< use DNAME */ +#define INK_RES_USE_EDNS0 0x40000000 /*%< use EDNS0 if configured */ + +#define INK_RES_DEFAULT (INK_RES_RECURSE | INK_RES_DEFNAMES | \ + INK_RES_DNSRCH) + +#define INK_MAXNS 32 /*%< max # name servers we'll track */ +#define INK_MAXDFLSRCH 3 /*%< # default domain levels to try */ +#define INK_MAXDNSRCH 6 /*%< max # domains in search path */ +#define INK_LOCALDOMAINPARTS 2 /*%< min levels in name that is "local" */ +#define INK_RES_TIMEOUT 5 /*%< min. seconds between retries */ +#define INK_RES_TIMEOUT 5 /*%< min. seconds between retries */ +#define INK_RES_MAXNDOTS 15 /*%< should reflect bit field size */ +#define INK_RES_MAXRETRANS 30 /*%< only for resolv.conf/RES_OPTIONS */ +#define INK_RES_MAXRETRY 5 /*%< only for resolv.conf/RES_OPTIONS */ +#define INK_RES_DFLRETRY 2 /*%< Default #/tries. */ +#define INK_RES_MAXTIME 65535 /*%< Infinity, in milliseconds. */ + +#define INK_NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */ +#define INK_DNS_LABELTYPE_BITSTRING 0x41 + +#ifndef NS_GET16 +#define NS_GET16(s, cp) do { \ + register const u_char *t_cp = (const u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += NS_INT16SZ; \ +} while (0) +#endif + +#ifndef NS_GET32 +#define NS_GET32(l, cp) do { \ + register const u_char *t_cp = (const u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += NS_INT32SZ; \ +} while (0) +#endif + +#ifndef NS_PUT16 +#define NS_PUT16(s, cp) do { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += NS_INT16SZ; \ +} while (0) +#endif + +#ifndef NS_PUT32 +#define NS_PUT32(l, cp) do { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += NS_INT32SZ; \ +} while (0) +#endif + +union ink_res_sockaddr_union { + struct sockaddr_in sin; +#ifdef IN6ADDR_ANY_INIT + struct sockaddr_in6 sin6; +#endif +#ifdef ISC_ALIGN64 + int64_t __align64; /*%< 64bit alignment */ +#else + int32_t __align32; /*%< 32bit alignment */ +#endif + char __space[128]; /*%< max size */ +}; + +struct __ink_res_state { + int retrans; /*%< retransmission time interval */ + int retry; /*%< number of times to retransmit */ +#ifdef sun + u_int options; /*%< option flags - see below. */ +#else + u_long options; /*%< option flags - see below. */ +#endif + int nscount; /*%< number of name servers */ + union ink_res_sockaddr_union nsaddr_list[INK_MAXNS]; /*%< address of name server */ +#define nsaddr nsaddr_list[0] /*%< for backward compatibility */ + u_short id; /*%< current message id */ + char *dnsrch[MAXDNSRCH+1]; /*%< components of domain to search */ + char defdname[256]; /*%< default domain (deprecated) */ +#ifdef sun + u_int pfcode; /*%< RES_PRF_ flags - see below. */ +#else + u_long pfcode; /*%< RES_PRF_ flags - see below. */ +#endif + unsigned ndots:4; /*%< threshold for initial abs. query */ + unsigned nsort:4; /*%< number of elements in sort_list[] */ + char unused[3]; + res_send_qhook qhook; /*%< query hook */ + res_send_rhook rhook; /*%< response hook */ + int res_h_errno; /*%< last one set for this context */ + int _vcsock; /*%< PRIVATE: for res_send VC i/o */ + u_int _flags; /*%< PRIVATE: see below */ + u_int _pad; /*%< make _u 64 bit aligned */ + union { + /* On an 32-bit arch this means 512b total. */ + char pad[72 - 4*sizeof (int) - 2*sizeof (void *)]; + struct { + u_int16_t nscount; + u_int16_t nstimes[INK_MAXNS]; /*%< ms. */ + struct __ink_res_state_ext *ext; /*%< extention for IPv6 */ + } _ext; + } _u; +}; +typedef __ink_res_state *ink_res_state; + +struct __ink_res_state_ext { + union ink_res_sockaddr_union nsaddrs[INK_MAXNS]; +}; + + +int ink_res_init(ink_res_state, const unsigned int *pHostList, const int *pPort = NULL, const char *pDefDomain = NULL, + const char *pSearchList = NULL, const char *pResolvConf = NULL); +int ink_res_mkquery(ink_res_state, int, const char *, int, int, + const unsigned char *, int, const unsigned char *, unsigned char *, int); + +#if !defined(linux) +int inet_aton(register const char *cp, struct in_addr *addr); +#endif + +int ink_ns_name_ntop(const u_char *src, char *dst, size_t dstsiz); + + +#endif /* _ink_resolver_h_ */ + diff --git a/lib/ts/ink_resource.cc b/lib/ts/ink_resource.cc new file mode 100644 index 00000000..3b96a91a --- /dev/null +++ b/lib/ts/ink_resource.cc @@ -0,0 +1,775 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#include "ink_assert.h" +#include "ink_atomic.h" +#include "ink_port.h" +#include "ink_resource.h" +#include "ink_stack_trace.h" + +volatile int64_t resource_allocated_mem = 0; +volatile int res_track_memory = RES_TRACK_MEMORY_DEFAULT; + +#ifdef TRACK_MEMORY + +#define FENCE_POST_SIZE 16 + +// TODO: Move this to ink_align.h +#define ADJUST(mem,x) (((char*) (mem)) + x) +// TODO: Use INK_ALIGN instead +#define ROUND(x,l) (((x) + ((l) - 1L)) & ~((l) - 1L)) +#define TSIZE 16387 + +#define MAKE_MAGIC(m) (((char*) (m)) - 1) +#define CHECK_MAGIC(m,c) ((char*) (m) == MAKE_MAGIC (c)) + + +typedef struct ResMemInfo ResMemInfo; +typedef struct Resource Resource; + +struct ResMemInfo +{ + void *magic; + unsigned int size:31; + unsigned int fence_post:1; + Resource *res; +}; + + +static unsigned int res_hash(const char *s); +Resource *res_lookup(const char *path); + + +static const int res_extra_space = ROUND(sizeof(ResMemInfo), sizeof(double)); +static volatile Resource *res_table[TSIZE]; + +static const char fence_post_pattern[FENCE_POST_SIZE] = { + (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef, + (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef, + (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef, + (char) 0xde, (char) 0xad, (char) 0xbe, (char) 0xef, +}; + + +volatile int res_zorch_mem = 0; +volatile int res_fence_post = 0; + +#define res_memadd(_x_) \ + ink_atomic_increment64(&resource_allocated_mem, (int64_t) (_x_)); + +#define res_memsub(_x_) \ + ink_atomic_increment64(&resource_allocated_mem, (int64_t) -(_x_)); + +static int +_xres_init() +{ + res_zorch_mem = (getenv("ZORCH_MEM") != NULL); + res_fence_post = (getenv("FENCE_POST") != NULL); + + if (res_zorch_mem) { + fprintf(stderr, "memory zorching enabled\n"); + } + + if (res_fence_post) { + fprintf(stderr, "memory fence posting enabled\n"); + } + + return 0; +} + +static int dummy_var = _xres_init(); + + +/* INKqa03012 - Digital OSF seems to issue some bad frees in + * the iostream destructor. These variables and the the exit_cb() + * let us know if exit has been called. If exit has been, called + * we will refrain from issuing warnings regarding bad frees + */ +static int exit_called = 0; +static void +exit_cb() +{ + exit_called = 1; +} +static int unused = atexit(exit_cb); + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +#define res_inc(res,delta) \ + ink_atomic_increment64 (&res->value, delta); \ + res_memadd(delta) + +#define res_check(res) \ + if (res && !CHECK_MAGIC ((res)->magic, (res))) { \ + fprintf (stderr, "FATAL: resource table is corrupt [%d]\n", __LINE__); \ + abort (); \ + } + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + + +unsigned int +res_hash(const char *s) +{ +#if !defined(linux) && !defined(freebsd) && !defined(__i386__) +#define HASH_ONE(h,one) ((h << 3) + (one) + (h >> 29)) +#define WORD_HAS_NULLBYTE(w) ((((w) - 0x01010101) ^ (w)) & 0x80808080) + + unsigned int h; + unsigned int ibp; + + ink_assert(!((uintptr_t) s & 3)); + + for (h = 0;;) { + ibp = *(unsigned int *) s; + + if (WORD_HAS_NULLBYTE(ibp)) { + unsigned char t[4]; + + if (!s[0]) { + return h; + } else if (!s[1]) { + *(unsigned int *) &t[0] = ibp; + t[2] = 0; + t[3] = 0; + h = HASH_ONE(h, *(unsigned int *) &t[0]); + return h; + } else if (!s[2]) { + *(unsigned int *) &t[0] = ibp; + t[3] = 0; + h = HASH_ONE(h, *(unsigned int *) &t[0]); + return h; + } else if (!s[3]) { + h = HASH_ONE(h, ibp); + return h; + } + } else { + h = HASH_ONE(h, ibp); + } + s += 4; + } + +#undef HASH_ONE +#undef WORD_HAS_NULLBYTE +#else + unsigned int h = 0, g; + + for (; *s; s++) { + h = (h << 4) + *s; + if ((g = h & 0xf0000000)) + h = (h ^ (g >> 24)) ^ g; + } + return h; +#endif +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +Resource * +res_lookup(const char *path) +{ + unsigned int hash_val; + Resource *node; + Resource *old; + + hash_val = res_hash(path) % TSIZE; + + for (;;) { + old = (Resource *) res_table[hash_val]; + node = old; + + while (node) { + res_check(node); + if ((path == node->path) || (strcmp(path, node->path) == 0)) { + return node; + } + node = node->next; + } + + if (old == res_table[hash_val]) { + node = (Resource *) _xmalloc(sizeof(Resource), NULL); + node->magic = MAKE_MAGIC(node); + node->path = path; + node->value = 0; + node->snapshot = 0; + node->baseline = 0; + node->next = old; + + if (ink_atomic_cas_ptr((pvvoidp) & res_table[hash_val], old, node)) + return node; + + _xfree(node); + node = NULL; + } + } + return NULL; // DEC compiler complains +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +static Resource * +res_stat(const char *path, int64_t value) +{ + if (path) { + Resource *res; + + res = res_lookup(path); + res_inc(res, value); + + return res; + } else { + return NULL; + } +} + + +#if defined(linux) || defined(freebsd) +static const int magic_array_offset = 0; +#else +#error "I do not know about this platform." +#endif + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +_xcheck_fence_post(char *mem, unsigned int size) +{ + if (memcmp(mem, fence_post_pattern, FENCE_POST_SIZE) != 0) { + return 1; + } + if (memcmp(mem + size - FENCE_POST_SIZE, fence_post_pattern, FENCE_POST_SIZE) != 0) { + return 1; + } + return 0; +} + +void +_xvalidate(void *ptr, char *file, int line) +{ + ResMemInfo *info; + + info = (ResMemInfo *) ADJUST(ptr, -res_extra_space); + if (!CHECK_MAGIC(info->magic, info)) { + info = (ResMemInfo *) ADJUST(info, -magic_array_offset); + } + if (!CHECK_MAGIC(info->magic, info)) { + ink_debug_assert(!"bad pointer"); + } else { + if (info->res) { + res_check(info->res); + } + char *mem = (char *) info; + + if (info->fence_post) { + mem -= FENCE_POST_SIZE; + if (_xcheck_fence_post(mem, info->size + res_extra_space + FENCE_POST_SIZE * 2)) { + fprintf(stderr, "MEMORY: free: fence-post mangled [%s]\n", info->res ? info->res->path : ""); + abort(); + } + } + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +_xfree(void *ptr) +{ + if (!ptr) { + // fprintf (stderr, "WARNING: freeing NULL pointer\n"); + } else { + ResMemInfo *info; + + info = (ResMemInfo *) ADJUST(ptr, -res_extra_space); + if (!CHECK_MAGIC(info->magic, info)) { + info = (ResMemInfo *) ADJUST(info, -magic_array_offset); + } + + if (CHECK_MAGIC(info->magic, info)) { + char *mem; + + if (info->res) { + res_check(info->res); + res_inc(info->res, -((int64_t) info->size)); + } + + mem = (char *) info; + + if (info->fence_post) { + mem -= FENCE_POST_SIZE; + if (_xcheck_fence_post(mem, info->size + res_extra_space + FENCE_POST_SIZE * 2)) { + fprintf(stderr, "MEMORY: free: fence-post mangled [%s]\n", info->res ? info->res->path : ""); + abort(); + } + } + + if (res_zorch_mem) { + memset(info, 0x81, info->size + res_extra_space); + } + + memset(info, 0, res_extra_space); + + free(mem); + + } else { + /* This is a bad free. Let it leak. Issue a + * warning if we are not in an exit routine + * (INKqa03012) + */ + if (exit_called == 0) { + fprintf(stderr, "WARNING: freeing bad pointer\n"); + ink_debug_assert(!"WARNING: freeing bad pointer"); + } + } + } +} + +void * +_xfree_null(void *ptr) +{ + _xfree(ptr); + return NULL; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void * +_xmalloc(unsigned int size, const char *path) +{ + ResMemInfo *info; + char *mem; + int extra; + int fence_post; + + extra = res_extra_space; + + fence_post = res_fence_post; + + if (fence_post) { + extra += FENCE_POST_SIZE * 2; + } + + mem = (char *) malloc(size + extra); + + if (unlikely(mem == NULL)) { + fprintf(stderr, "FATAL: _xmalloc could not allocate %u + %u bytes [%s]\n", + size, extra, path ? path : "memory/anonymous"); + xdump(); + _exit(1); + } + + if (fence_post) { + memcpy(mem, fence_post_pattern, FENCE_POST_SIZE); + memcpy(mem + size + extra - FENCE_POST_SIZE, fence_post_pattern, FENCE_POST_SIZE); + mem += FENCE_POST_SIZE; + } + + memset(mem, 0, res_extra_space); + + info = (ResMemInfo *) mem; + info->magic = MAKE_MAGIC(mem); + info->size = size; + info->fence_post = fence_post; + + if (res_track_memory) { + info->res = res_stat(path, size); + res_check(info->res); + } else { + info->res = NULL; + } + + mem = mem + res_extra_space; + + return mem; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +char * +_xstrdup(const char *str, int64_t length, const char *path) +{ + char *newstr; + + if (unlikely(str == NULL)) { + return NULL; + } + + if (length < 0) { + length = (int) strlen(str); + } + + newstr = (char *) _xmalloc(length + 1, path); + strncpy(newstr, str, length); + newstr[length] = '\0'; + + return newstr; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void * +_xrealloc(void *ptr, unsigned int size, const char *path) +{ + if (!ptr) { + return _xmalloc(size, path); + } else { + ResMemInfo *info; + char *mem; + int extra; + int fence_post; + + info = (ResMemInfo *) ADJUST(ptr, -res_extra_space); + if (!CHECK_MAGIC(info->magic, info)) { + info = (ResMemInfo *) ADJUST(info, -magic_array_offset); + } + + if (info->res) { + res_check(info->res); + res_inc(info->res, -((int64_t) info->size)); + } + + mem = (char *) info; + extra = res_extra_space; + + if (info->fence_post) { + mem -= FENCE_POST_SIZE; + if (_xcheck_fence_post(mem, info->size + res_extra_space + FENCE_POST_SIZE * 2)) { + fprintf(stderr, "MEMORY: realloc: fence-post mangled [%s] [%s]\n", + info->res ? info->res->path : "", path); + abort(); + } + } + + memset(info, 0, res_extra_space); + + fence_post = res_fence_post; + + if (fence_post) { + extra += FENCE_POST_SIZE * 2; + } + + mem = (char *) realloc(mem, size + extra); + if (unlikely(mem == NULL)) { + fprintf(stderr, "FATAL: could not reallocate %u + %u bytes [%s]\n", + size, extra, path ? path : "memory/anonymous"); + xdump(); + _exit(1); + } + + if (fence_post) { + memcpy(mem, fence_post_pattern, FENCE_POST_SIZE); + memcpy(mem + size + extra - FENCE_POST_SIZE, fence_post_pattern, FENCE_POST_SIZE); + mem += FENCE_POST_SIZE; + } + + memset(mem, 0, res_extra_space); + + info = (ResMemInfo *) mem; + info->magic = MAKE_MAGIC(mem); + info->size = size; + info->fence_post = fence_post; + + if (res_track_memory) { + info->res = res_stat(path, size); + res_check(info->res); + } else { + info->res = NULL; + } + + mem = mem + res_extra_space; + + return mem; + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void * +_xtrack(void *ptr, const char *path) +{ + if (unlikely(ptr == NULL)) { + fprintf(stderr, "WARNING: cannot track NULL pointer\n"); + return ptr; + } else { + ResMemInfo *info; + + info = (ResMemInfo *) ADJUST(ptr, -res_extra_space); + if (!CHECK_MAGIC(info->magic, info)) { + info = (ResMemInfo *) ADJUST(info, -magic_array_offset); + } + + if (!CHECK_MAGIC(info->magic, info)) { + return ptr; + } + + if (info->res) { + res_check(info->res); + res_inc(info->res, -((int64_t) info->size)); + } + + if (res_track_memory) { + info->res = res_stat(path, info->size); + res_check(info->res); + } else { + info->res = NULL; + } + + return ptr; + } +} + +void +xdump_snap_baseline() +{ + int i; + Resource *res; + + for (i = 0; i < TSIZE; i++) { + res = (Resource *) res_table[i]; + while (res) { + res_check(res); + res->baseline = res->value; + res = res->next; + } + } +} + +void +xdump_to_file_baseline_rel(FILE * fp) +{ + Resource *res; + int64_t value; + int64_t diff; + int i; + struct timeval timestamp; + char time_string[32], *time_str; + int length_to_write; + + ink_gethrtimeofday(×tamp, NULL); + time_str = ctime((time_t *) & timestamp.tv_sec); + + length_to_write = squid_timestamp_to_buf(time_string, 32, timestamp.tv_sec, timestamp.tv_usec); + time_string[length_to_write] = '\0'; + + fprintf(fp, "PID: %d %s %s", getpid(), time_string, time_str); + fprintf(fp, " value | delta | location\n"); + fprintf(fp, "rel. to base| | \n"); + fprintf(fp, "------------|------------|-----------------------------------------------\n"); + + for (i = 0; i < TSIZE; i++) { + res = (Resource *) res_table[i]; + while (res) { + res_check(res); + + value = res->value - res->baseline; + diff = res->value - res->snapshot; + if (value != 0) { + fprintf(fp, " % 10d | % 10d | %s\n", (int) value, (int) diff, res->path); + } + + res->snapshot = res->value; + res = res->next; + } + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +xdump_to_file(FILE * fp) +{ + Resource *res; + int64_t value; + int64_t diff; + int i; + struct timeval timestamp; + char time_string[32], *time_str; + int length_to_write; + + ink_gethrtimeofday(×tamp, NULL); + time_str = ctime((time_t *) & timestamp.tv_sec); + + length_to_write = squid_timestamp_to_buf(time_string, 32, timestamp.tv_sec, timestamp.tv_usec); + time_string[length_to_write] = '\0'; + + fprintf(fp, "PID: %d %s %s", getpid(), time_string, time_str); + fprintf(fp, " value | delta | location\n"); + fprintf(fp, "------------|------------|-----------------------------------------------\n"); + + for (i = 0; i < TSIZE; i++) { + res = (Resource *) res_table[i]; + while (res) { + res_check(res); + if (strncmp(res->path, "memory/IOBuffer/", strlen("memory/IOBuffer/")) + != 0) { + value = res->value; + diff = value - res->snapshot; + if (diff != 0) { + fprintf(fp, " % 10d | % 10d | %s\n", (int) value, (int) diff, res->path); + } + res->snapshot = res->value; + } + res = res->next; + } + } + + fprintf(fp, " value | delta | location\n"); + fprintf(fp, "------------|------------|-----------------------------------------------\n"); + for (i = 0; i < TSIZE; i++) { + res = (Resource *) res_table[i]; + while (res) { + res_check(res); + if (strncmp(res->path, "memory/IOBuffer/", strlen("memory/IOBuffer/")) + == 0) { + value = res->value; + diff = value - res->snapshot; + if (diff != 0) { + fprintf(fp, " % 10d | % 10d | %s\n", (int) value, (int) diff, res->path); + } + res->snapshot = res->value; + } + res = res->next; + } + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +xdump() +{ + ink_stack_trace_dump(); + xdump_to_file(stderr); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +xsnap() +{ + Resource *res; + int i; + + for (i = 0; i < TSIZE; i++) { + res = (Resource *) res_table[i]; + while (res) { + res_check(res); + res->snapshot = res->value; + res = res->next; + } + } +} + + +#else /* TRACK_MEMORY */ + +/*------------------------------------------------------------------------- +-------------------------------------------------------------------------*/ +void +_xfree(void *mem) +{ + if (likely(mem)) + ink_free(mem); +} + +void * +_xfree_null(void *mem) +{ + if (likely(mem)) + ink_free(mem); + return NULL; +} + + +void * +_xmalloc(unsigned int size, const char *path) +{ + NOWARN_UNUSED(path); + return ink_malloc(size); +} + +void * +_xrealloc(void *ptr, unsigned int size, const char *path) +{ + NOWARN_UNUSED(path); + return ink_realloc(ptr, size); +} + +char * +_xstrdup(const char *str, int length, const char *path) +{ + NOWARN_UNUSED(path); + char *newstr; + + if (likely(str)) { + if (length < 0) { + length = strlen(str); + } + newstr = (char *) ink_malloc(length + 1); + if (likely(newstr != NULL)) { + strncpy(newstr, str, length); + newstr[length] = '\0'; + return newstr; + } + fprintf(stderr, "FATAL: could not allocate %d bytes in _xstrdup\n", length + 1); + ink_stack_trace_dump(); + _exit(1); + } + return NULL; +} + +typedef struct Resource Resource; + +Resource * +res_lookup(const char *path) +{ + NOWARN_UNUSED(path); + return NULL; +} + +void +xdump(void) +{ + ink_stack_trace_dump(); +} + + +#endif /* TRACK_MEMORY */ diff --git a/lib/ts/ink_resource.h b/lib/ts/ink_resource.h new file mode 100644 index 00000000..c93be4ab --- /dev/null +++ b/lib/ts/ink_resource.h @@ -0,0 +1,205 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __INK_RESOURCE_H__ +#define __INK_RESOURCE_H__ + +#include +#include +#include + +#include "ink_apidefs.h" +#include "ink_port.h" +#include "ink_memory.h" + +extern volatile int64_t resource_allocated_mem; +extern volatile int res_track_memory; /* set this to zero to disable resource tracking */ + +#define __RES_PATH(x) #x +#define _RES_PATH(x) __RES_PATH (x) +#define RES_PATH(x) x __FILE__ ":" _RES_PATH (__LINE__) +#define RES_MEM_PATH RES_PATH ("memory/") +#define RES_DESC_PATH RES_PATH ("descriptor/") + +struct Resource +{ + void *magic; + struct Resource *next; + const char *path; + int64_t value; + int64_t snapshot; + int64_t baseline; +}; + +//#define TRACK_MEMORY + +#if defined(TRACK_MEMORY) +#define RES_TRACK_MEMORY_DEFAULT 1 /* default value for res_track_memory variable */ + +#define xfree(p) _xfree(p) +#define xfree_null(p) _xfree_null(p) +#define xmalloc(s) _xmalloc((s), RES_MEM_PATH) +#define xrealloc(p,s) _xrealloc((p), (s), RES_MEM_PATH) +#define xstrdup(p) _xstrdup((p), -1, RES_MEM_PATH) +#define xstrndup(p,n) _xstrdup((p), (n), RES_MEM_PATH) +#define xtrack(p) _xtrack((p), RES_MEM_PATH) +#define xvalidate(p) _xvalidate((p),__FILE__,__LINE__) + +void _xvalidate(void *ptr, char *file, int line); +void _xfree(void *ptr); +void *_xfree_null(void *ptr); +void *_xmalloc(unsigned int size, const char *path); +void *_xrealloc(void *ptr, unsigned int size, const char *path); +char *_xstrdup(const char *str, int length, const char *path); +void *_xtrack(void *ptr, const char *path); +void xdump_snap_baseline(); +void xdump_to_file_baseline_rel(FILE * fp); +void xdump_to_file(FILE * fp); +void xdump(void); +void xsnap(void); + +#else /* #if defined(TRACK_MEMORY) */ +#define RES_TRACK_MEMORY_DEFAULT 0 /* default value for res_track_memory variable */ + +#ifdef __cplusplus +static inline void +xfree(void *mem) +{ + if (mem) + ink_free(mem); +} +static inline void * +xfree_null(void *mem) +{ + if (mem) + ink_free(mem); + return NULL; +} + +//#else +//#define xfree(_mem) if(_mem){ink_free((_mem));} +//#define xfree_null(_mem) if(_mem){ink_free((_mem));_mem = NULL;} +#endif + +#define xmalloc(s) ink_malloc ((s)) +#define xrealloc(p,s) ink_realloc ((p),(s)) +#define xstrdup(p) _xstrdup ((p), -1, NULL) +#define xstrndup(p,n) _xstrdup ((p), n, NULL) +#define xtrack(p) p +#define xdump_snap_baseline() do { } while (0) +#define xdump_to_file_baseline_rel(f) do { } while (0) +#define xdump_to_file(f) do { } while (0) +#define xsnap() do { } while (0) +#define xvalidate(p) do {} while (0) + +void *_xmalloc(unsigned int size, const char *path); +void *_xrealloc(void *ptr, unsigned int size, const char *path); +char *_xstrdup(const char *str, int length, const char *path); +void _xfree(void *ptr); +void *_xfree_null(void *ptr); + +void xdump(void); + +#if defined(__cplusplus) +/** Locally scoped holder for a chunk of memory allocated via these functions. + If this pointer is assigned the current memory (if any) is freed. + The memory is also freed when the object is destructed. This makes + handling temporary memory in a function more robust. + + @internal A poor substitute for a real shared pointer copy on write + class but one step at a time. It's better than doing this by + hand every time. +*/ +template < + typename T ///< Type of pointer. +> class xptr { +public: + typedef xptr self; ///< Self reference type. + /// Default constructor, zero initialized. + xptr() : m_ptr(0) { } + /// Construct from allocated memory. + /// @note @a ptr must refer to memory allocated @c xmalloc. + explicit xptr(T* ptr) : m_ptr(ptr) { } + /// Construct and initialized with memory for @a n instances of @a T. + explicit xptr(size_t n) : m_ptr(xmalloc(sizeof(T) * n)) { } + /// Destructor - free memory held by this instance. + ~xptr() { xfree(m_ptr); } + /// Assign memory. + /// @note @a ptr must be allocated via @c xmalloc. + self& operator = (T* ptr) { + xfree(m_ptr); + m_ptr = ptr; + return *this; + } + /// Auto convert to a raw pointer. + operator T* () { return m_ptr; } + /// Auto conver to raw pointer. + operator T const* () const { return m_ptr; } + /** Release memory from control of this instance. + + @note Although direct assignment is forbidden due to the + non-obvious semantics, a pointer can be moved (@b not copied) from + one instance to another using this method. + @code + new_ptr = old_ptr.release(); + @endcode + This is by design so any such transfer is always explicit. + */ + T* release() { + T* zret = m_ptr; + m_ptr = 0; + return zret; + } +private: + T* m_ptr; ///< Pointer to allocated memory. + /// Copy constructor - forbidden. + xptr(self const& that); + /// Self assignment - forbidden. + self& operator = (self const& that); +}; + +// Special operators for xptr +/** Combine two strings as file paths. + Trailing and leading separators for @a lhs and @a rhs respectively + are handled to yield exactly one separator. + @return A newly @x xmalloc string of the combined paths. +*/ +inline char* path_join (xptr const& lhs, xptr const& rhs) { + size_t ln = strlen(lhs); + size_t rn = strlen(rhs); + char const* rptr = rhs; // May need to be modified. + if (ln && lhs[ln-1] == '/') --ln; // drop trailing separator. + if (rn && *rptr == '/') --rn, ++rptr; // drop leading separator. + char* x = static_cast(xmalloc(ln + rn + 2)); + memcpy(x, lhs, ln); + x[ln] = '/'; + memcpy(x + ln + 1, rptr, rn); + x[ln+rn+1] = 0; // terminate string. + return x; +} + +#endif // c++ + +#endif /* TRACK_MEMORY */ + +#endif /* __INK_RESOURCE_H__ */ diff --git a/lib/ts/ink_rwlock.cc b/lib/ts/ink_rwlock.cc new file mode 100644 index 00000000..0a6b6e33 --- /dev/null +++ b/lib/ts/ink_rwlock.cc @@ -0,0 +1,167 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_config.h" +#include "ink_rwlock.h" + +//------------------------------------------------------------------------- +// ink_rwlock_init +//------------------------------------------------------------------------- + +int +ink_rwlock_init(ink_rwlock * rw) +{ + + int result; + + if ((result = ink_mutex_init(&rw->rw_mutex, NULL)) != 0) + goto Lerror; + ink_cond_init(&rw->rw_condreaders); + ink_cond_init(&rw->rw_condwriters); + rw->rw_nwaitreaders = 0; + rw->rw_nwaitwriters = 0; + rw->rw_refcount = 0; + rw->rw_magic = RW_MAGIC; + + return (0); + +Lerror: + return (result); /* an errno value */ + +} + +//------------------------------------------------------------------------- +// ink_rwlock_destroy +//------------------------------------------------------------------------- + +int +ink_rwlock_destroy(ink_rwlock * rw) +{ + + if (rw->rw_magic != RW_MAGIC) + return (EINVAL); + if (rw->rw_refcount != 0 || rw->rw_nwaitreaders != 0 || rw->rw_nwaitwriters != 0) + return (EBUSY); + + ink_mutex_destroy(&rw->rw_mutex); + ink_cond_destroy(&rw->rw_condreaders); + ink_cond_destroy(&rw->rw_condwriters); + rw->rw_magic = 0; + + return (0); +} + +//------------------------------------------------------------------------- +// ink_rwlock_rdlock +//------------------------------------------------------------------------- + +int +ink_rwlock_rdlock(ink_rwlock * rw) +{ + + int result; + + if (rw->rw_magic != RW_MAGIC) + return (EINVAL); + + if ((result = ink_mutex_acquire(&rw->rw_mutex)) != 0) + return (result); + + /* give preference to waiting writers */ + while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) { + rw->rw_nwaitreaders++; + ink_cond_wait(&rw->rw_condreaders, &rw->rw_mutex); + rw->rw_nwaitreaders--; + } + rw->rw_refcount++; /* another reader has a read lock */ + + ink_mutex_release(&rw->rw_mutex); + + return (0); + +} + +//------------------------------------------------------------------------- +// ink_rwlock_wrlock +//------------------------------------------------------------------------- + +int +ink_rwlock_wrlock(ink_rwlock * rw) +{ + + int result; + + if (rw->rw_magic != RW_MAGIC) + return (EINVAL); + + if ((result = ink_mutex_acquire(&rw->rw_mutex)) != 0) + return (result); + + while (rw->rw_refcount != 0) { + rw->rw_nwaitwriters++; + ink_cond_wait(&rw->rw_condwriters, &rw->rw_mutex); + rw->rw_nwaitwriters--; + } + rw->rw_refcount = -1; + + ink_mutex_release(&rw->rw_mutex); + + return (0); + +} + +//------------------------------------------------------------------------- +// ink_rwlock_unlock +//------------------------------------------------------------------------- + +int +ink_rwlock_unlock(ink_rwlock * rw) +{ + + int result; + + if (rw->rw_magic != RW_MAGIC) + return (EINVAL); + + if ((result = ink_mutex_acquire(&rw->rw_mutex)) != 0) + return (result); + + if (rw->rw_refcount > 0) + rw->rw_refcount--; /* releasing a reader */ + else if (rw->rw_refcount == -1) + rw->rw_refcount = 0; /* releasing a reader */ + else + ink_release_assert("invalid rw_refcount!"); + + /* give preference to waiting writers over waiting readers */ + if (rw->rw_nwaitwriters > 0) { + if (rw->rw_refcount == 0) + ink_cond_signal(&rw->rw_condwriters); + } else if (rw->rw_nwaitreaders > 0) + ink_cond_broadcast(&rw->rw_condreaders); + + ink_mutex_release(&rw->rw_mutex); + + return (0); + +} diff --git a/lib/ts/ink_rwlock.h b/lib/ts/ink_rwlock.h new file mode 100644 index 00000000..06a732e6 --- /dev/null +++ b/lib/ts/ink_rwlock.h @@ -0,0 +1,55 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +//------------------------------------------------------------------------- +// Read-Write Lock -- Code from Stevens' Unix Network Programming - +// Interprocess Communications. This is the simple implementation and +// will not work if used in conjunction with ink_thread_cancel(). +//------------------------------------------------------------------------- + +#ifndef _INK_RWLOCK_H_ +#define _INK_RWLOCK_H_ + +#include "ink_mutex.h" +#include "ink_thread.h" + +#define RW_MAGIC 0x19283746 + +struct ink_rwlock +{ + ink_mutex rw_mutex; /* basic lock on this struct */ + ink_cond rw_condreaders; /* for reader threads waiting */ + ink_cond rw_condwriters; /* for writer threads waiting */ + int rw_magic; /* for error checking */ + int rw_nwaitreaders; /* the number waiting */ + int rw_nwaitwriters; /* the number waiting */ + int rw_refcount; +}; + +int ink_rwlock_init(ink_rwlock * rw); +int ink_rwlock_destroy(ink_rwlock * rw); +int ink_rwlock_rdlock(ink_rwlock * rw); +int ink_rwlock_wrlock(ink_rwlock * rw); +int ink_rwlock_unlock(ink_rwlock * rw); + +#endif diff --git a/lib/ts/ink_sock.cc b/lib/ts/ink_sock.cc new file mode 100644 index 00000000..f0b851f8 --- /dev/null +++ b/lib/ts/ink_sock.cc @@ -0,0 +1,256 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************************************************************** + Socket operations + + + +***************************************************************************/ +#include "libts.h" + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +// +// Compilation options +// + +// #define CHECK_PLAUSIBILITY_OF_SOCKADDR + + +#ifdef CHECK_PLAUSIBILITY_OF_SOCKADDR +#define CHECK_PLAUSIBLE_SOCKADDR(_n,_f,_l) check_plausible_sockaddr(_n,_f,_n) +inline void +check_valid_sockaddr(sockaddr * sa, char *file, int line) +{ + sockaddr_in *si = (sockaddr_in *) sa; + unsigned short port = ntohs(si->sin_port); + unsigned short addr = ntohl(si->sin_addr.s_addr); + + if (port > 20000) { + cerr << "[byteordering] In " << file << ", line " << line << " the IP port "; + cerr << "was found to be " << port << "(in host byte order).\n"; + cerr << "[byteordering] This seems inplausible, so check for byte order problems\n"; + } +} +#else +#define CHECK_PLAUSIBLE_SOCKADDR(_n,_f,_l) +#endif + +int +safe_setsockopt(int s, int level, int optname, char *optval, int optlevel) +{ + int r; + do { + r = setsockopt(s, level, optname, optval, optlevel); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +int +safe_getsockopt(int s, int level, int optname, char *optval, int *optlevel) +{ + int r; + do { + r = getsockopt(s, level, optname, optval, (socklen_t *) optlevel); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +int +safe_fcntl(int fd, int cmd, int arg) +{ + int r = 0; + do { + r = fcntl(fd, cmd, arg); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +int +safe_set_fl(int fd, int arg) +{ + int flags = safe_fcntl(fd, F_GETFL, 0); + if (flags < 0) + return flags; + flags |= arg; + flags = safe_fcntl(fd, F_SETFL, flags); + return flags; +} + +int +safe_clr_fl(int fd, int arg) +{ + int flags = safe_fcntl(fd, F_GETFL, 0); + if (flags < 0) + return flags; + flags &= ~arg; + flags = safe_fcntl(fd, F_SETFL, flags); + return flags; +} + +int +safe_nonblocking(int fd) +{ + return safe_set_fl(fd, O_NONBLOCK); +} + +int +safe_blocking(int fd) +{ + return safe_clr_fl(fd, O_NONBLOCK); +} + +int +write_ready(int fd) +{ + struct pollfd p; + p.events = POLLOUT; + p.fd = fd; + int r = poll(&p, 1, 0); + if (r <= 0) + return r; + if (p.revents & (POLLERR | POLLNVAL)) + return -1; + if (p.revents & (POLLOUT | POLLHUP)) + return 1; + return 0; +} + +int +read_ready(int fd) +{ + struct pollfd p; + p.events = POLLIN; + p.fd = fd; + int r = poll(&p, 1, 0); + if (r <= 0) + return r; + if (p.revents & (POLLERR | POLLNVAL)) + return -1; + if (p.revents & (POLLIN | POLLHUP)) + return 1; + return 0; +} + +int +safe_ioctl(int fd, int request, char *arg) +{ + int r = -1; + do { + r = ioctl(fd, request, arg); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +int +safe_bind(int s, struct sockaddr *name, int namelen) +{ + int r; + CHECK_PLAUSIBLE_SOCKADDR(name, __FILE__, __LINE__); + do { + r = bind(s, name, namelen); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +int +safe_listen(int s, int backlog) +{ + int r; + do { + r = listen(s, backlog); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +int +safe_getsockname(int s, struct sockaddr *name, int *namelen) +{ + int r; + do { + r = getsockname(s, name, (socklen_t *) namelen); + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + return r; +} + +char +fd_read_char(int fd) +{ + char c; + int r; + do { + r = read(fd, &c, 1); + if (r > 0) + return c; + } while (r < 0 && (errno == EAGAIN || errno == EINTR)); + perror("fd_read_char"); + ink_assert(!"fd_read_char"); + return c; +} + +int +fd_read_line(int fd, char *s, int len) +{ + char c; + int numread = 0, r; + //char *buf = s; + do { + do + r = read(fd, &c, 1); + while (r < 0 && (errno == EAGAIN || errno == EINTR)); + + if (r <= 0 && numread) + break; + + if (r <= 0) + return r; + + if (c == '\n') + break; + + s[numread++] = c; + } while (numread < len - 1); + + s[numread] = 0; + return numread; +} + + +int +close_socket(int s) +{ + return close(s); +} + +int +write_socket(int s, const char *buffer, int length) +{ + return write(s, (const void *) buffer, length); +} + +int +read_socket(int s, char *buffer, int length) +{ + return read(s, (void *) buffer, length); +} diff --git a/lib/ts/ink_sock.h b/lib/ts/ink_sock.h new file mode 100644 index 00000000..6920fcfb --- /dev/null +++ b/lib/ts/ink_sock.h @@ -0,0 +1,66 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/*************************************************************************** + Socket operations + + + +***************************************************************************/ +#if !defined (_ink_sock_h_) +#define _ink_sock_h_ + +#include "ink_platform.h" +#include "ink_port.h" + +#include "ink_apidefs.h" + +int safe_setsockopt(int s, int level, int optname, char *optval, int optlevel); +int safe_getsockopt(int s, int level, int optname, char *optval, int *optlevel); +int safe_bind(int s, struct sockaddr *name, int namelen); +int safe_listen(int s, int backlog); +int safe_getsockname(int s, struct sockaddr *name, int *namelen); + +int safe_fcntl(int fd, int cmd, int arg); +int safe_ioctl(int fd, int request, char *arg); + +int safe_set_fl(int fd, int arg); +int safe_clr_fl(int fd, int arg); + +int safe_blocking(int fd); +int safe_nonblocking(int fd); + +int write_ready(int fd); +int read_ready(int fd); + +char fd_read_char(int fd); +int fd_read_line(int fd, char *s, int len); + +int close_socket(int s); +int write_socket(int s, const char *buffer, int length); +int read_socket(int s, char *buffer, int length); + +inkcoreapi uint32_t ink_inet_addr(const char *s); + + +#endif /* _ink_sock_h_ */ diff --git a/lib/ts/ink_sprintf.cc b/lib/ts/ink_sprintf.cc new file mode 100644 index 00000000..6cbe0c2d --- /dev/null +++ b/lib/ts/ink_sprintf.cc @@ -0,0 +1,153 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + + ink_sprintf.cc + + This file implements some Inktomi variants of sprintf, to do bounds + checking and length counting. + + + ****************************************************************************/ + +#include "ink_sprintf.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +#define NUL '\0' + +////////////////////////////////////////////////////////////////////////////// +// +// int ink_bsprintf(char *buffer, char *format, ...) +// int ink_bvsprintf(char *buffer, char *format, va_list ap) +// +// This is a very simplified version of sprintf that has the following +// behavior: +// +// (1) the length in output characters is returned, including final NUL +// (2) buffer can be NULL, for just counting the output chars +// (3) only %s and %d are supported, with no field modifiers +// +////////////////////////////////////////////////////////////////////////////// + +int +ink_bsprintf(char *buffer, const char *format, ...) +{ + int l; + + va_list ap; + va_start(ap, format); + l = ink_bvsprintf(buffer, format, ap); + va_end(ap); + + return (l); +} + + +int +ink_bvsprintf(char *buffer, const char *format, va_list ap) +{ + int d_val; + const char *s; + char *d, *p, *s_val, d_buffer[32]; + va_list ap_local; + va_copy(ap_local, ap); + + s = format; + d = buffer; + + while (*s) { + ///////////////////////////// + // handle non-% characters // + ///////////////////////////// + + if (buffer) // if have output buffer + while (*s && (*s != '%')) { + *d++ = *s++; + } // really copy, else + else + while (*s && (*s != '%')) { + d++; + s++; + } // pass over string + + /////////////////////////// + // handle NUL characters // + /////////////////////////// + + if (*s == NUL) + break; // end of string + + ///////////////////////// + // handle % characters // + ///////////////////////// + + ++s; // consume % character + + switch (*s) // dispatch on flag + { + case 's': // %s pattern + ++s; // consume 's' + s_val = va_arg(ap_local, char *); // grab string argument + p = s_val; // temporary pointer + if (buffer) // if have output buffer + while (*p) { + *d++ = *p++; + } // copy value + else // else + while (*p) { + d++; + p++; + } // pass over value + break; + case 'd': // %d pattern + ++s; // consume 'd' + d_val = va_arg(ap_local, int); // grab integer argument + snprintf(d_buffer, sizeof(d_buffer), "%d", d_val); // stringify integer + p = d_buffer; // temporary pointer + if (buffer) // if have output buffer + while (*p) { + *d++ = *p++; + } // copy value + else // else + while (*p) { + d++; + p++; + } // pass over value + break; + default: // something else + if (buffer) + *d = *s; // copy unknown character + ++d; + ++s; + break; + } + } + + if (buffer) + *d = NUL; + ++d; + + va_end(ap_local); + return (int) (d - buffer); +} diff --git a/lib/ts/ink_sprintf.h b/lib/ts/ink_sprintf.h new file mode 100644 index 00000000..322bb126 --- /dev/null +++ b/lib/ts/ink_sprintf.h @@ -0,0 +1,47 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + + ink_sprintf.h + + This file implements some Inktomi variants of sprintf, to do bounds + checking and length counting. + + + ****************************************************************************/ + +#ifndef _ink_sprintf_h_ +#define _ink_sprintf_h_ + +#include +#include +#include "ink_defs.h" + +int +ink_bsprintf(char *buffer, const char *format, ...) +PRINTFLIKE(2, 3); +int +ink_bvsprintf(char *buffer, const char *format, va_list ap); + +#endif diff --git a/lib/ts/ink_stack_trace.cc b/lib/ts/ink_stack_trace.cc new file mode 100644 index 00000000..d1ab6576 --- /dev/null +++ b/lib/ts/ink_stack_trace.cc @@ -0,0 +1,70 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "ink_stack_trace.h" + +#include +#include +#include +#include + +#if TS_HAS_BACKTRACE + +#include /* for backtrace_symbols, etc. */ +#include + +void +ink_stack_trace_dump(int sighandler_frame) +{ + int btl; + + // Recopy and re-terminate the app name in case it has been trashed. + char name[256]; + const char *msg = " - STACK TRACE: \n"; + ink_strncpy(name, program_name, sizeof(name) - 2); + if (write(2, name, strlen(name)) == -1) + return; + if (write(2, msg, strlen(msg)) == -1) + return; + + void *stack[INK_STACK_TRACE_MAX_LEVELS + 1]; + memset(stack, 0, sizeof(stack)); + + if ((btl = backtrace(stack, INK_STACK_TRACE_MAX_LEVELS)) > 2) { + // dump the backtrace to stderr + backtrace_symbols_fd(stack + 2, btl - 2, 2); + } +} + +#else /* !TS_HAS_BACKTRACE */ + +void +ink_stack_trace_dump(int sighandler_frame) +{ + const char msg[] = "ink_stack_trace_dump not implemented on this operating system\n"; + if (write(2, msg, sizeof(msg) - 1) == -1) + return; +} + +#endif /* TS_HAS_BACKTRACE */ diff --git a/lib/ts/ink_stack_trace.h b/lib/ts/ink_stack_trace.h new file mode 100644 index 00000000..2b322287 --- /dev/null +++ b/lib/ts/ink_stack_trace.h @@ -0,0 +1,40 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef ink_stack_trace_h +#define ink_stack_trace_h + +// The max number of levels in the stack trace +#define INK_STACK_TRACE_MAX_LEVELS 100 + +#ifdef __cplusplus +extern "C" +{ +#endif +/* dumps the current back trace to stderr */ + void ink_stack_trace_dump(int sighandler_frame = 0); +#ifdef __cplusplus +} +#endif + +#endif /* ink_stack_trace_h */ diff --git a/lib/ts/ink_string++.cc b/lib/ts/ink_string++.cc new file mode 100644 index 00000000..ed830af5 --- /dev/null +++ b/lib/ts/ink_string++.cc @@ -0,0 +1,195 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_string++.cc + + C++ support for string manipulation. + + + ****************************************************************************/ + +#include "libts.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +char * +ink_memcpy_until_char(char *dst, char *src, unsigned int n, unsigned char c) +{ + unsigned int i = 0; + for (; ((i < n) && (((unsigned char) src[i]) != c)); i++) + dst[i] = src[i]; + return &src[i]; +} + +/*********************************************************************** + * * + * StrList (doubly-linked list of string/length list cells) * + * * + ***********************************************************************/ + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +StrList::dump(FILE * fp) +{ + Str *str; + + for (str = head; str != NULL; str = str->next) + str->dump(fp); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +Str * +StrList::_new_cell(const char *s, int len_not_counting_nul) +{ + Str *cell; + char *p; + int l = len_not_counting_nul; + + // allocate a cell from the array or heap + if (cells_allocated < STRLIST_BASE_CELLS) { + cell = &(base_cells[cells_allocated]); + } else { + p = (char *) alloc(sizeof(Str) + 7); + if (p == NULL) + return (NULL); // FIX: scale heap + p = (char *) ((((uintptr_t)p) + 7) & ~7); // round up to multiple of 8 + cell = (Str *) p; + } + ++cells_allocated; + + // are we supposed to copy the string? + if (copy_when_adding_string) { + char *buf = (char *) alloc(l + 1); + if (buf == NULL) + return (NULL); // FIX: need to grow heap! + memcpy(buf, s, l); + buf[l] = '\0'; + + cell->str = (const char *) buf; + } else { + cell->str = s; + } + + cell->len = l; + + return (cell); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void * +StrList::overflow_heap_alloc(int size) +{ + if (!overflow_first) { + overflow_first = overflow_current = StrListOverflow::create_heap(STRLIST_OVERFLOW_HEAP_SIZE); + } + + return overflow_current->alloc(size, &overflow_current); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +StrList::overflow_heap_clean() +{ + if (overflow_first) + overflow_first->clean(); +} + + +#define INIT_OVERFLOW_ALIGNMENT 8 +// XXX: This is basically INK_ALIGN_DEFAULT +const int overflow_head_hdr_size = INK_ALIGN(sizeof(StrListOverflow), INIT_OVERFLOW_ALIGNMENT); + +void +StrListOverflow::init() +{ + next = NULL; + heap_size = 0; + heap_used = 0; +} + +void +StrListOverflow::clean() +{ + StrListOverflow *current_free = this; + StrListOverflow *next_free; + + while (current_free) { + next_free = current_free->next; + xfree(current_free); + current_free = next_free; + } +} + +void * +StrListOverflow::alloc(int size, StrListOverflow ** new_heap_ptr) +{ + + if (size > (heap_size - heap_used)) { + int new_heap_size = heap_size * 2; + + if (new_heap_size < size) { + new_heap_size = INK_ALIGN(size, 2048); + ink_release_assert(new_heap_size >= size); + } + + ink_assert(next == NULL); + *new_heap_ptr = next = create_heap(new_heap_size); + return next->alloc(size, new_heap_ptr); + } + + char *start = ((char *) this) + overflow_head_hdr_size; + char *rval = start + heap_used; + heap_used += size; + ink_assert(heap_used <= heap_size); + return (void *) rval; +} + +StrListOverflow * +StrListOverflow::create_heap(int user_size) +{ + // I'm aligning the first allocation since the old implementation + // used to do this by calling xmalloc. I assume it doesn't + // matter since we are talking about strings but since this is a + // last minute emergency bug fix, I'm not take any changes. If + // allocations are not of aligned values then subsequents allocations + // aren't aligned, again mirroring the previous implemnetation + int total_size = overflow_head_hdr_size + user_size; + + StrListOverflow *o = (StrListOverflow *) xmalloc(total_size); + o->init(); + o->heap_size = user_size; + + return o; +} diff --git a/lib/ts/ink_string++.h b/lib/ts/ink_string++.h new file mode 100644 index 00000000..768303e1 --- /dev/null +++ b/lib/ts/ink_string++.h @@ -0,0 +1,335 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_string++.h + + C++ support for string manipulation. + + + ****************************************************************************/ + +#if !defined (_ink_string_pp_h_) +#define _ink_string_pp_h_ +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// +// mem_copy +// +////////////////////////////////////////////////////////////////////////////// + +static inline void +_memcpy(char *dest, const char *src, int nbytes) +{ + for (int i = 0; i < nbytes; i++) + dest[i] = src[i]; +} + + +////////////////////////////////////////////////////////////////////////////// +// +// mem_len +// +////////////////////////////////////////////////////////////////////////////// + +static inline int +_strlen(const char *src) +{ + const char *old_src = src; + while (*src) + src++; + return (int) (src - old_src); +} + +/*********************************************************************** + * * + * Str (string/length list cell) * + * * + ***********************************************************************/ + +struct Str +{ + const char *str; // string pointer + size_t len; // length of string (not counting NUL) + struct Str *next; // next in list + struct Str *prev; // prev in list + + Str():str(NULL), len(0), next(NULL), prev(NULL) + { + } + Str(char *s) + { + str = s; + len = strlen(s); + next = NULL; + prev = NULL; + } + Str(char *s, int l) + { + str = s; + len = l; + next = NULL; + prev = NULL; + } + + void clean() + { + str = NULL; + len = 0; + next = NULL; + prev = NULL; + } + + void dump(FILE * fp = stderr) { + fprintf(fp, "Str [\"%.*s\", len %d]\n", (int) len, str, (int) len); + } +}; + +/*********************************************************************** + * * + * StrList (doubly-linked list of string/length list cells) * + * * + ***********************************************************************/ + +#define STRLIST_BASE_HEAP_SIZE 128 +#define STRLIST_OVERFLOW_HEAP_SIZE 1024 +#define STRLIST_BASE_CELLS 5 + +struct StrListOverflow; + +struct StrList +{ +public: + int count; + Str *head; + Str *tail; + +public: + StrList(bool do_copy_when_adding_string = true); + ~StrList(); + + Str *get_idx(int i); + void append(Str * str); + void prepend(Str * str); + void add_after(Str * prev, Str * str); + void detach(Str * str); + + Str *new_cell(const char *s, int len_not_counting_nul); + Str *append_string(const char *s, int len_not_counting_nul); + + void dump(FILE * fp = stderr); + +private: + void init(); + void clean(); + + void *base_heap_alloc(int size); + void *alloc(int size); + Str *_new_cell(const char *s, int len_not_counting_nul); + void *overflow_heap_alloc(int size); + void overflow_heap_clean(); + + Str base_cells[STRLIST_BASE_CELLS]; + char base_heap[STRLIST_BASE_HEAP_SIZE]; + int cells_allocated; + int base_heap_size; + int base_heap_used; + StrListOverflow *overflow_current; + StrListOverflow *overflow_first; + bool copy_when_adding_string; +}; + +struct StrListOverflow +{ + StrListOverflow *next; + int heap_size; + int heap_used; + + void init(); + void clean(); + void *alloc(int size, StrListOverflow ** new_heap_ptr); + static StrListOverflow *create_heap(int user_size); +}; + +inline void +StrList::init() +{ + count = 0; + cells_allocated = 0; + head = tail = NULL; + base_heap_size = STRLIST_BASE_HEAP_SIZE; + base_heap_used = 0; + overflow_first = NULL; + overflow_current = NULL; +} + +inline void +StrList::clean() +{ + if (overflow_first) + overflow_heap_clean(); + init(); +} + +inline +StrList::StrList(bool do_copy_when_adding_string) +{ + memset(base_heap, 0, sizeof(base_heap)); + copy_when_adding_string = do_copy_when_adding_string; + init(); +} + +inline +StrList::~ +StrList() +{ + clean(); +} + +inline void * +StrList::base_heap_alloc(int size) +{ + char *p; + + if (size <= (base_heap_size - base_heap_used)) { + p = &(base_heap[base_heap_used]); + base_heap_used += size; + return ((void *) p); + } else + return (NULL); +} + +inline void * +StrList::alloc(int size) +{ + void *p = base_heap_alloc(size); + if (p == NULL) + p = overflow_heap_alloc(size); + return (p); +} + +inline Str * +StrList::new_cell(const char *s, int len_not_counting_nul) +{ + Str *cell; + int l = len_not_counting_nul; + + // allocate a cell from the array or heap + if ((cells_allocated < STRLIST_BASE_CELLS) && (!copy_when_adding_string)) { + cell = &(base_cells[cells_allocated++]); + cell->str = s; + cell->len = l; + return (cell); + } else { + return (_new_cell(s, len_not_counting_nul)); + } +} + +inline Str * +StrList::get_idx(int i) +{ + Str *s; + + for (s = head; ((s != NULL) && i); s = s->next, i--); + return ((i == 0) ? s : NULL); +} + +inline void +StrList::append(Str * str) +{ + // do nothing if str is NULL to avoid pointer chasing below + if (str == NULL) + return; + ++count; + str->next = NULL; + str->prev = tail; + + if (tail == NULL) { + head = tail = str; + } else { + tail->next = str; + tail = str; + } +} + +inline void +StrList::prepend(Str * str) +{ + if (str == NULL) + return; + ++count; + str->next = head; + str->prev = NULL; + + if (tail == NULL) { + head = tail = str; + } else { + head->prev = str; + head = str; + } +} + +inline void +StrList::add_after(Str * prev, Str * str) +{ + if (str == NULL || prev == NULL) + return; + ++count; + str->next = prev->next; + str->prev = prev; + prev->next = str; + if (tail == prev) + tail = str; +} + +inline void +StrList::detach(Str * str) +{ + if (str == NULL) + return; + --count; + + if (head == str) + head = str->next; + if (tail == str) + tail = str->prev; + if (str->prev) + str->prev->next = str->next; + if (str->next) + str->next->prev = str->prev; +} + +inline Str * +StrList::append_string(const char *s, int len_not_counting_nul) +{ + Str *cell; + + cell = new_cell(s, len_not_counting_nul); + append(cell); + return (cell); +} + +#endif diff --git a/lib/ts/ink_string.cc b/lib/ts/ink_string.cc new file mode 100644 index 00000000..06f03fac --- /dev/null +++ b/lib/ts/ink_string.cc @@ -0,0 +1,532 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_string.c + + String and text processing routines for libts + + ****************************************************************************/ + +#include "libts.h" /* MAGIC_EDITING_TAG */ + +#include +#include +#include +#include + + +#define INK_MAX_STRING_ARRAY_SIZE 128 + +/*---------------------------------------------------------------------------* + + char *ink_strncpy(char *dest, char *src, int n) + + This routine is a safer version of strncpy which always NUL terminates + the destination string. Note that this routine has the SAME semantics + as strncpy, such as copying exactly n bytes, padding dest with NULs + is necessary. Use ink_string_copy for a non-padding version. + + *---------------------------------------------------------------------------*/ + +char * +ink_strncpy(char *dest, const char *src, int n) +{ + if (likely(src && dest)) { + if (n > 1) + strncpy(dest, src, (n - 1)); + if (n > 0) + dest[n - 1] = '\0'; + } + + return (dest); +} /* End ink_strncpy */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_concatenate_strings(char *dest, ...) + + This routine concatenates a variable number of strings into the buffer + , returning the pointer to . The sequence of strings must end + with NULL. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_concatenate_strings(char *dest, ...) +{ + va_list ap; + register char *s, *d; + + va_start(ap, dest); + + d = dest; + + while (1) { + s = va_arg(ap, char *); + if (s == NULL) + break; + + while (*s) + *d++ = *s++; + } + *d++ = '\0'; + va_end(ap); + return (dest); +} /* End ink_string_concatenate_strings */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_concatenate_strings_n(char *dest, int n, ...) + + This routine concatenates a variable number of strings into the buffer + , returning the pointer to . The sequence of strings must end + with NULL. A NUL will always be placed after , and no more than + - 1 characters will ever be written to . + + *---------------------------------------------------------------------------*/ + +char * +ink_string_concatenate_strings_n(char *dest, int n, ...) +{ + va_list ap; + register char *s, *d; + + va_start(ap, n); + + d = dest; + + while (n > 1) { + s = va_arg(ap, char *); + if (s == NULL) + break; + while (*s && (n > 1)) { + *d++ = *s++; + n--; + } + } + if (n >= 1) + *d = '\0'; + va_end(ap); + return (dest); +} /* End ink_string_concatenate_strings_n */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_append(char *dest, char *src, int n) + + This routine appends to the end of , but it insures the + string pointed to by never grows beyond characters, including + the terminating NUL. A NUL is always written if n > 0. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_append(char *dest, char *src, int n) +{ + char *d, *s, *last_valid_char; + + ink_assert(src != NULL); + ink_assert(dest != NULL); + ink_assert(n >= 0); + + if (n == 0) + return (dest); + + last_valid_char = dest + n - 1; + + /* Scan For End Of Dest */ + + for (d = dest; (d <= last_valid_char) && (*d != '\0'); d++); + + /* If At End Of String, NUL Terminate & Exit */ + + if (d > last_valid_char) { + dest[n - 1] = '\0'; + return (dest); + } + + /* Append src To String */ + + s = src; + while ((d < last_valid_char) && (*s != '\0')) + *d++ = *s++; + + /* If At End Of String, NUL Terminate & Exit */ + + if (d > last_valid_char) + dest[n - 1] = '\0'; + else + *d = '\0'; + + return (dest); +} /* End ink_string_append */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_duplicate(char *ptr) + + This routine allocates memory for the string , and copies the string + into the new buffer. The pointer to the new buffer is returned. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_duplicate(char *ptr) +{ + char *n = NULL; + + if (likely(ptr)) { + const size_t nSize = strlen(ptr) + 1; + n = (char *) ink_malloc(nSize); + ink_strncpy(n, ptr, nSize); + } + return (n); +} /* End ink_string_duplicate */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_find_dotted_extension(char *str, char *ext, int max_ext_len) + + This routine takes a string , copies the period-separated extension to + (up to characters) NUL terminates , and + returns a pointer into the string where the '.' of the extension + begins, or NULL if there is no extension. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_find_dotted_extension(char *str, char *ext, int max_ext_len) +{ + char *p = NULL; + + if (ext) { + *ext = '\0'; + if (str) { + for (p = (str + strlen(str)) - 1; p >= str; p--) + if (*p == '.') + break; + + if (p <= str) + return (NULL); + + ink_string_copy(ext, (p + 1), max_ext_len); + } + } + return (p); +} /* End ink_string_find_dotted_extension */ + +/*---------------------------------------------------------------------------* + + char *ink_string_mpath(int nstrings, char *str1, bool free1, + char *str2, bool free2, ...); + + This routine joins multiple path components together to make + a new path. Each component can optionally start with a / in which + case all the preceeding components are ignored. + + Each component can optionally be free()d. + + Space is malloc()d to hold the resulting path. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_mpath(int nstrings, ...) +{ + va_list ap; + + char *e[INK_MAX_STRING_ARRAY_SIZE]; + bool f[INK_MAX_STRING_ARRAY_SIZE]; + size_t s[INK_MAX_STRING_ARRAY_SIZE]; + int slash = 0; + size_t ts = 0; + char *ns = NULL; + char *p; + int i; + + if (likely(nstrings < INK_MAX_STRING_ARRAY_SIZE)) { + va_start(ap, nstrings); + + for (i = 0; i < nstrings; i++) { + e[i] = va_arg(ap, char *); + f[i] = va_arg(ap, int); + } + + for (i = nstrings - 1; i >= 0; i--) { + if (!e[i]) + continue; + s[i] = strlen(e[i]); + ts += s[i] + 1; + if (e[i][0] == '/') { + slash = i; + break; + } + } + if ((slash == nstrings - 1) && f[slash]) { + for (i = 0; i < nstrings - 1; i++) { + if (f[i]) + xfree(e[i]); + } + va_end(ap); + return e[slash]; + } else { + const size_t nsSize = ts + 1; + p = (ns = (char *) xmalloc(nsSize)); + ink_assert(ns); + for (i = slash; i < nstrings - 1; i++) { + ink_strncpy(p, e[i], (nsSize - (p - ns))); + p += s[i]; + *p++ = '/'; + } + ink_strncpy(p, e[nstrings - 1], (nsSize - (p - ns))); + } + for (i = 0; i < nstrings; i++) { + if (f[i]) + xfree(e[i]); + } + va_end(ap); + } + return ns; +} + +/*---------------------------------------------------------------------------* + + char *ink_string_mcopy(char *source); + + This simply makes a copy of a string into freshly malloc()ed space. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_mcopy(char *source) +{ + char *n = NULL; + + if (likely(source)) { + const size_t nSize = strlen(source) + 1; + n = (char *) xmalloc(nSize); + ink_strncpy(n, source, nSize); + } + return n; +} + +/*---------------------------------------------------------------------------* + + char *ink_string_mjoin(int nstrings, char *str1, bool free1, + char *str2, bool free2, ...); + + This routine joins multiple strings components together to make + a new string. Each component can optionally be free()d. + + Space is malloc()d to hold the resulting path. + + *---------------------------------------------------------------------------*/ + +char * +ink_string_mjoin(int nstrings, ...) +{ + va_list ap; + + char *e[INK_MAX_STRING_ARRAY_SIZE]; + bool f[INK_MAX_STRING_ARRAY_SIZE]; + + size_t s[INK_MAX_STRING_ARRAY_SIZE]; + int slash = 0; + size_t ts = 0; + char *ns = NULL; + char *p; + int i; + + if (likely(nstrings < INK_MAX_STRING_ARRAY_SIZE)) { + va_start(ap, nstrings); + + for (i = 0; i < nstrings; i++) { + e[i] = va_arg(ap, char *); + f[i] = va_arg(ap, int); + if (e[i]) { + s[i] = strlen(e[i]); + ts += s[i]; + } + } + const size_t nsSize = ts + 1; + p = (ns = (char *) xmalloc(nsSize)); + for (i = slash; i < nstrings - 1; i++) { + ink_strncpy(p, e[i], (nsSize - (p - ns))); + p += s[i]; + } + ink_strncpy(p, e[nstrings - 1], (nsSize - (p - ns))); + for (i = 0; i < nstrings; i++) { + if (f[i]) + xfree(e[i]); + } + va_end(ap); + } + return ns; +} + +#if !TS_HAS_STRNDUP +char * +ink_strndup(const char *str, size_t n) +{ + char *cstr = NULL; + + if (likely(str)) { + size_t len = strlen(str); + cstr = (char *)xmalloc(len + 1); + if (cstr == NULL) + return (NULL); + memcpy(cstr, str, len); + cstr[len] = '\0'; + } + return (cstr); +} +#endif + +#if !TS_HAS_STRLCPY +size_t +ink_strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) { + while (--n != 0) { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return (s - src - 1); /* count does not include NUL */ +} +#endif + +#if !TS_HAS_STRLCAT +size_t +ink_strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return (dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return (dlen + (s - src)); /* count does not include NUL */ +} +#endif + +char * +ink_strtok_r(char *s1, const char *s2, char **lasts) +{ + return strtok_r(s1, s2, lasts); +} + +// XXX/lomew this might not be portable. If not check in configure +// and always squash if no iconv available. +#include + +/* + * This is a front-end to iconv(3). + * + * latin-1 is a subset of utf-8 so the output string len you pass + * can be the same as the input string len. + */ +void +ink_utf8_to_latin1(const char *in, int inlen, char *out, int *outlen) +{ + size_t inbytesleft, outbytesleft; + iconv_t ic; + + // XXX/lomew should have a configure test for the first arg + ic = iconv_open("8859-1", "UTF-8"); // solaris + if (ic == (iconv_t) - 1) { + ic = iconv_open("iso-8859-1", "UTF-8"); // linux + if (ic == (iconv_t) - 1) { + goto strip; + } + } + + inbytesleft = inlen; + outbytesleft = *outlen; +#if !defined(kfreebsd) && (defined(freebsd) || defined(solaris)) + if (iconv(ic, &in, &inbytesleft, &out, &outbytesleft) == (size_t) - 1) +#else + if (iconv(ic, (char **) &in, &inbytesleft, &out, &outbytesleft) == (size_t) - 1) +#endif + { + iconv_close(ic); + goto strip; + } + + *outlen -= outbytesleft; + iconv_close(ic); + return; + +strip: + + /* Strip out chars with the high bit set. + This only happens if iconv can't convert. */ + inbytesleft = inlen; + outbytesleft = *outlen; + while (inbytesleft && outbytesleft) { + if (!(*in & 0x80)) { + *out++ = *in; + outbytesleft--; + } + in++; + inbytesleft--; + } + *outlen -= outbytesleft; +} diff --git a/lib/ts/ink_string.h b/lib/ts/ink_string.h new file mode 100644 index 00000000..5886caf3 --- /dev/null +++ b/lib/ts/ink_string.h @@ -0,0 +1,780 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_string.h + + String and text processing routines for libts + + ****************************************************************************/ + +#ifndef _ink_string_h_ +#define _ink_string_h_ + +#include +#include +#include + +#include "ink_assert.h" +#include "ink_error.h" +#include "ParseRules.h" +#include "ink_apidefs.h" + + +/*===========================================================================* + + Function Prototypes + + *===========================================================================*/ +/* these are supposed to be fast */ + +inkcoreapi char *ink_strncpy(char *dest, const char *src, int n); +inkcoreapi char *ink_string_concatenate_strings(char *dest, ...); +inkcoreapi char *ink_string_concatenate_strings_n(char *dest, int n, ...); +inkcoreapi char *ink_string_append(char *dest, char *src, int n); +inkcoreapi char *ink_string_duplicate(char *ptr); +inkcoreapi char *ink_string_find_dotted_extension(char *str, char *ext, int max_ext_len); + +/* these are supposed to make your life easier */ + +/* + * the results of all of these are put in freshly malloc()ed memory + */ + + /* + * s = ink_string_mpath(2, "/foo", false, "bar", false); + */ +char *ink_string_mpath(int nstrings, ...); + /* + * s = ink_string_mcopy(old); + */ +char *ink_string_mcopy(char *source); + /* + * s = ink_string_mjoin(2, "/foo", false, "/bar", false); + */ +char *ink_string_mjoin(int nstrings, ...); + +/* Missing fcns */ +#if TS_HAS_STRNDUP +#define ink_strndup strndup +#else +char *ink_strndup(const char *str, size_t n); +#endif +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +#if TS_HAS_STRLCPY +#define ink_strlcpy strlcpy +#else +size_t ink_strlcpy(char *dst, const char *str, size_t siz); +#endif +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +#if TS_HAS_STRLCAT +#define ink_strlcat strlcat +#else +size_t ink_strlcat(char *dst, const char *str, size_t siz); +#endif + +/* 9/3/98 elam: Added this because NT doesn't have strtok_r() */ +char *ink_strtok_r(char *s1, const char *s2, char **lasts); + +inkcoreapi int ink_strcasecmp(const char *a, const char *b); +inkcoreapi int ink_strncasecmp(const char *a, const char *b, unsigned int max); + +/* Convert from UTF-8 to latin-1/iso-8859-1. This can be lossy. */ +void ink_utf8_to_latin1(const char *in, int inlen, char *out, int *outlen); + +/*===========================================================================* + + Inline Functions + + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + + char *ink_strchr(char *s, char c) + + A faster version of strchr. + + *---------------------------------------------------------------------------*/ + +static inline char * +ink_strchr(char *s, char c) +{ + while (*s) { + if (*s == c) + return (s); + else + ++s; + } + return (NULL); +} /* End ink_strchr */ + + +/*---------------------------------------------------------------------------* + + int ink_string_is_prefix(char *prefix, char *str) + + Returns 1 is is a strict prefix of , 0 otherwise. + + *---------------------------------------------------------------------------*/ + +static inline int +ink_string_is_prefix(char *prefix, char *str) +{ + while (*prefix && *str && *prefix == *str) { + ++prefix; + ++str; + } + if (*prefix == '\0') + return (1); + else + return (0); +} /* End ink_string_is_prefix */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_copy(char *dest, char *src, int n) + + This routine is like ink_strncpy, but it stops writing to + after the first NUL from is written, even if bytes are + not copied. A NUL is always written if n > 0. Returns . + + *---------------------------------------------------------------------------*/ + +static inline char * +ink_string_copy(char *dest, char *src, int n) +{ + register char *s, *d; + + s = src; + d = dest; + + while ((n > 1) && *s) { + *d++ = *s++; + --n; + } + + if (n > 0) + *d = '\0'; + + return (dest); +} /* End ink_string_copy */ + + +/*---------------------------------------------------------------------------* + + char *ink_string_concatenate_two_strings(char *dest, char *s1, char *s2) + + This routine concatenates the two strings and into the buffer + , returning the pointer to . + + *---------------------------------------------------------------------------*/ + +static inline char * +ink_string_concatenate_two_strings(char *dest, register char *s1, register char *s2) +{ + register char *d; + + d = dest; + while (*s1) + *d++ = *s1++; + while (*s2) + *d++ = *s2++; + *d++ = '\0'; + + return (dest); +} /* End ink_string_concatenate_two_strings */ + + +static inline void +ink_string_fast_strncpy(char *dest, char *src, int src_size, int nbytes) +{ + int to_copy = nbytes < src_size ? nbytes : src_size; + + ink_assert(nbytes >= 0); + ink_assert(src_size >= 0); + + if (to_copy <= 10) { + switch (to_copy) { + case 1: + dest[0] = '\0'; + break; + case 2: + dest[0] = src[0]; + dest[1] = '\0'; + break; + case 3: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = '\0'; + break; + case 4: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = '\0'; + break; + case 5: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest[4] = '\0'; + break; + case 6: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest[4] = src[4]; + dest[5] = '\0'; + break; + case 7: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest[4] = src[4]; + dest[5] = src[5]; + dest[6] = '\0'; + break; + case 8: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest[4] = src[4]; + dest[5] = src[5]; + dest[6] = src[6]; + dest[7] = '\0'; + break; + case 9: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest[4] = src[4]; + dest[5] = src[5]; + dest[6] = src[6]; + dest[7] = src[7]; + dest[8] = '\0'; + break; + case 10: + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; + dest[4] = src[4]; + dest[5] = src[5]; + dest[6] = src[6]; + dest[7] = src[7]; + dest[8] = src[8]; + dest[9] = '\0'; + break; + default: + ink_warning("Error in ink_string_fast_strncpy no copy performed d: %s s: %s n: %d\n", dest, src, nbytes); + break; + } + } else if (to_copy <= 1500) { + int i; + for (i = 0; i < (to_copy - 1); i++) { + dest[i] = src[i]; + } + dest[i] = '\0'; + } else { + memcpy(dest, src, (to_copy - 1)); + dest[to_copy] = '\0'; + } + return; +} + +static inline int +ink_string_fast_strncasecmp(const char *s0, const char *s1, int n) +{ + int i; + for (i = 0; (i < n) && (ParseRules::ink_tolower(s0[i]) == ParseRules::ink_tolower(s1[i])); i++); + if (i == n) + return 0; + else + return 1; +} + +static inline int +ink_string_fast_strcasecmp(const char *s0, const char *s1) +{ + const char *s = s0, *p = s1; + while (*s && *p && (ParseRules::ink_tolower(*s) == ParseRules::ink_tolower(*p))) { + s++; + p++; + } + if (!(*s) && !(*p)) + return 0; + else + return 1; +} + +static inline int +ink_string_fast_strcmp(const char *s0, const char *s1) +{ + const char *s = s0, *p = s1; + + while (*s && *p && *s == *p) { + s++; + p++; + } + if (!(*s) && !(*p)) + return 0; + else + return 1; +} + +static inline char * +ink_string_fast_strcpy(char *dest, char *src) +{ + char *s = src, *d = dest; + + while (*s != '\0') + *d++ = *s++; + *d = '\0'; + return dest; +} + +static inline int +ink_string_strlen(const char *str) +{ + int i; + + if (str[0] == '\0') + return (0); + else if (str[1] == '\0') + return (1); + else if (str[2] == '\0') + return (2); + else if (str[3] == '\0') + return (3); + else if (str[4] == '\0') + return (4); + else { + for (i = 5; i < 16; i++) + if (str[i] == '\0') + return (i); + return ((int) (16 + strlen(&(str[16])))); + } +} + +static inline int +ink_string_fast_strlen(char *src) +{ + int i; + if (!src) { + return -1; + } + for (i = 0; src[i] != '\0'; i++); + return i; +} + +static inline char * +ink_string_fast_max_strcpy(char *s0, char *s1, int max) +{ + int i, rmax = max - 1; + char *s = s0, *p = s1; + for (i = 0; i < rmax && *p != '\0'; i++) + *s++ = *p++; + *s = '\0'; + return s0; +} + +// inline int ptr_len_cmp(const char* p1, int l1, const char* p2, int l2) +// +// strcmp() functionality for two ptr length pairs +// +inline int +ptr_len_cmp(const char *p1, int l1, const char *p2, int l2) +{ + if (l1 == l2) { + return memcmp(p1, p2, l1); + } else if (l1 < l2) { + return -1; + } else { + return 1; + } +} + +// inline int ptr_len_cmp(const char* p1, int l1, const char* p2, int l2) +// +// strcasecmp() functionality for two ptr length pairs +// +inline int +ptr_len_casecmp(const char *p1, int l1, const char *p2, int l2) +{ + if (l1 < l2) { + return -1; + } else if (l1 > l2) { + return 1; + } + + while (l1) { + char p1c = ParseRules::ink_tolower(*p1); + char p2c = ParseRules::ink_tolower(*p2); + + if (p1c != p2c) { + if (p1c > p2c) { + return 1; + } else { + return -1; + } + } + + p1++; + p2++; + l1--; + } + + return 0; +} + +// inline const char* ptr_len_str(const char* p1, int l1, const char* str) +// +// strstr() like functionality for the ptr, len pairs +// +inline const char * +ptr_len_str(const char *p1, int l1, const char *str) +{ + + if (str && str[0]) { + int str_index = 0; + const char *match_start = NULL; + + while (l1 > 0) { + if (*p1 == str[str_index]) { + + // If this is the start of a match, + // record it; + if (str_index == 0) { + match_start = p1; + } + // Check to see if we are finished; + str_index++; + if (str[str_index] == '\0') { + return match_start; + } + } else if (str_index > 0) { + l1 += (p1 - match_start); + p1 = match_start; + str_index = 0; + } + + p1++; + l1--; + } + } + return NULL; +} + +// int ptr_len_ncmp(const char* p1, int l1, const char* str, int n) { +// +// strncmp like functionality for comparing a ptr,len pair with +// a null terminated string for n chars +// +inline int +ptr_len_ncmp(const char *p1, int l1, const char *str, int n) +{ + + + while (l1 > 0 && n > 0) { + if (*str == '\0') { + return 1; + } + + char p1c = *p1; + char strc = *str; + + if (p1c != strc) { + if (p1c > strc) { + return 1; + } else if (p1c < strc) { + return -1; + } + } + + p1++; + l1--; + n--; + str++; + } + + // If we've scanned our nchars, the match + // otherwise we're here because str is longer + // than p1 + + if (n == 0) { + return 0; + } else { + return -1; + } +} + + +// int ptr_len_ncasecmp(const char* p1, int l1, const char* str, int n) { +// +// strncasecmp like functionality for comparing a ptr,len pair with +// a null terminated string for n chars +// +inline int +ptr_len_ncasecmp(const char *p1, int l1, const char *str, int n) +{ + + + while (l1 > 0 && n > 0) { + if (*str == '\0') { + return 1; + } + + char p1c = ParseRules::ink_tolower(*p1); + char strc = ParseRules::ink_tolower(*str); + + if (p1c != strc) { + if (p1c > strc) { + return 1; + } else if (p1c < strc) { + return -1; + } + } + + p1++; + l1--; + n--; + str++; + } + + // If we've scanned our nchars, the match + // otherwise we're here because str is longer + // than p1 + + if (n == 0) { + return 0; + } else { + return -1; + } +} + +// int ptr_len_casecmp(const char* p1, int l1, const char* str) { +// +// strcasecmp like functionality for comparing a ptr,len pair with +// a null terminated string +// +inline int +ptr_len_casecmp(const char *p1, int l1, const char *str) +{ + + while (l1 > 0) { + if (*str == '\0') { + return 1; + } + + char p1c = ParseRules::ink_tolower(*p1); + char strc = ParseRules::ink_tolower(*str); + + if (p1c != strc) { + if (p1c > strc) { + return 1; + } else if (p1c < strc) { + return -1; + } + } + + p1++; + l1--; + str++; + } + + // Since we're out of characters in p1 + // str needs to be finished for the strings + // to get equal + if (*str == '\0') { + return 0; + } else { + return -1; + } +} + + +// int ptr_len_cmp(const char* p1, int l1, const char* str) { +// +// strcmp like functionality for comparing a ptr,len pair with +// a null terminated string +// +inline int +ptr_len_cmp(const char *p1, int l1, const char *str) +{ + + while (l1 > 0) { + if (*str == '\0') { + return 1; + } + + char p1c = *p1; + char strc = *str; + + if (p1c != strc) { + if (p1c > strc) { + return 1; + } else if (p1c < strc) { + return -1; + } + } + + p1++; + l1--; + str++; + } + + // Since we're out of characters in p1 + // str needs to be finished for the strings + // to get equal + if (*str == '\0') { + return 0; + } else { + return -1; + } +} + +// char* ptr_len_pbrk(const char* p1, int l1, const char* str) +// +// strpbrk() like functionality for ptr & len pair strings +// +inline char * +ptr_len_pbrk(const char *p1, int l1, const char *str) +{ + while (l1 > 0) { + const char *str_cur = str; + + while (*str_cur != '\0') { + if (*p1 == *str_cur) { + return (char *) p1; + } + str_cur++; + } + + p1++; + l1--; + } + + return NULL; +} + +// Specialized "itoa", that is optimized for small integers, and use snprintf() otherwise. +// On error, we'll return 0, and nothing is written to the buffer. +// TODO: Do these really need to be inline? +inline int +ink_small_itoa(int val, char* buf, int buf_len) +{ + ink_assert(buf_len > 5); + ink_assert((val >= 0) && (val < 100000)); + + if (val < 10) { // 0 - 9 + buf[0] = '0' + val; + return 1; + } else if (val < 100) { // 10 - 99 + buf[1] = '0' + (val % 10); + val /= 10; + buf[0] = '0' + (val % 10); + return 2; + } else if (val < 1000) { // 100 - 999 + buf[2] = '0' + (val % 10); + val /= 10; + buf[1] = '0' + (val % 10); + val /= 10; + buf[0] = '0' + (val % 10); + return 3; + } else if (val < 10000) { // 1000 - 9999 + buf[3] = '0' + (val % 10); + val /= 10; + buf[2] = '0' + (val % 10); + val /= 10; + buf[1] = '0' + (val % 10); + val /= 10; + buf[0] = '0' + (val % 10); + return 4; + } else { // 10000 - 99999 + buf[4] = '0' + (val % 10); + val /= 10; + buf[3] = '0' + (val % 10); + val /= 10; + buf[2] = '0' + (val % 10); + val /= 10; + buf[1] = '0' + (val % 10); + val /= 10; + buf[0] = '0' + (val % 10); + return 5; + } +} + +inline int +ink_fast_itoa(int32_t val, char* buf, int buf_len) +{ + if ((val < 0) || (val > 99999)) { + int ret = snprintf(buf, buf_len, "%d", val); + + return (ret >= 0 ? ret : 0); + } + + return ink_small_itoa((int)val, buf, buf_len); +} + +inline int +ink_fast_uitoa(uint32_t val, char* buf, int buf_len) +{ + if (val > 99999) { + int ret = snprintf(buf, buf_len, "%u", val); + + return (ret >= 0 ? ret : 0); + } + + return ink_small_itoa((int)val, buf, buf_len); +} + +inline int +ink_fast_ltoa(int64_t val, char* buf, int buf_len) +{ + if ((val < 0) || (val > 99999)) { + int ret = snprintf(buf, buf_len, "%" PRId64 "", val); + + return (ret >= 0 ? ret : 0); + } + + return ink_small_itoa((int)val, buf, buf_len); +} + +#endif diff --git a/lib/ts/ink_sys_control.cc b/lib/ts/ink_sys_control.cc new file mode 100644 index 00000000..8e8f62ca --- /dev/null +++ b/lib/ts/ink_sys_control.cc @@ -0,0 +1,65 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_sys_control.h" +#include "ink_platform.h" +#include "ink_assert.h" + +rlim_t +ink_max_out_rlimit(int which, bool max_it, bool unlim_it) +{ + struct rlimit rl; + +#if defined(linux) +# define MAGIC_CAST(x) (enum __rlimit_resource)(x) +#else +# define MAGIC_CAST(x) x +#endif + + if (max_it) { + ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0); + if (rl.rlim_cur != rl.rlim_max) { +#if defined(darwin) + if (which == RLIMIT_NOFILE) + rl.rlim_cur = fmin(OPEN_MAX, rl.rlim_max); + else + rl.rlim_cur = rl.rlim_max; +#else + rl.rlim_cur = rl.rlim_max; +#endif + ink_release_assert(setrlimit(MAGIC_CAST(which), &rl) >= 0); + } + } + +#if !defined(darwin) + if (unlim_it) { + ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0); + if (rl.rlim_cur != (rlim_t)RLIM_INFINITY) { + rl.rlim_cur = (rl.rlim_max = RLIM_INFINITY); + ink_release_assert(setrlimit(MAGIC_CAST(which), &rl) >= 0); + } + } +#endif + ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0); + return rl.rlim_cur; +} diff --git a/lib/ts/ink_sys_control.h b/lib/ts/ink_sys_control.h new file mode 100644 index 00000000..01f2fbba --- /dev/null +++ b/lib/ts/ink_sys_control.h @@ -0,0 +1,40 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _INK_SYS_CONTROL_H +#define _INK_SYS_CONTROL_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +rlim_t ink_max_out_rlimit(int which, bool max_it=true, bool unlim_it=true); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /*_INK_SYS_CONTROL_H*/ diff --git a/lib/ts/ink_syslog.cc b/lib/ts/ink_syslog.cc new file mode 100644 index 00000000..5d82322c --- /dev/null +++ b/lib/ts/ink_syslog.cc @@ -0,0 +1,88 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************/ +/**************************************************************************** + * + * ink_syslog.cc + * + * + ****************************************************************************/ + + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +#include "libts.h" + +struct syslog_fac +{ + char *long_str; + char *short_str; + int fac_int; +}; + +static const syslog_fac convert_table[] = { + {(char *) "LOG_KERN", (char *) "KERN", LOG_KERN}, + {(char *) "LOG_USER", (char *) "USER", LOG_USER}, + {(char *) "LOG_MAIL", (char *) "MAIL", LOG_MAIL}, + {(char *) "LOG_DAEMON", (char *) "DAEMON", LOG_DAEMON}, + {(char *) "LOG_AUTH", (char *) "AUTH", LOG_AUTH}, + {(char *) "LOG_LPR", (char *) "LPR", LOG_LPR}, + {(char *) "LOG_NEWS", (char *) "NEWS", LOG_NEWS}, + {(char *) "LOG_UUCP", (char *) "UUCP", LOG_UUCP}, + {(char *) "LOG_CRON", (char *) "CRON", LOG_CRON}, + {(char *) "LOG_LOCAL0", (char *) "LOCAL0", LOG_LOCAL0}, + {(char *) "LOG_LOCAL1", (char *) "LOCAL1", LOG_LOCAL1}, + {(char *) "LOG_LOCAL2", (char *) "LOCAL2", LOG_LOCAL2}, + {(char *) "LOG_LOCAL3", (char *) "LOCAL3", LOG_LOCAL3}, + {(char *) "LOG_LOCAL4", (char *) "LOCAL4", LOG_LOCAL4}, + {(char *) "LOG_LOCAL5", (char *) "LOCAL5", LOG_LOCAL5}, + {(char *) "LOG_LOCAL6", (char *) "LOCAL6", LOG_LOCAL6}, + {(char *) "LOG_LOCAL7", (char *) "LOCAL7", LOG_LOCAL7}, + {(char *) "INVALID_LOG_FAC", (char *) "INVALID", -1} +}; +static const int convert_table_size = sizeof(convert_table) / sizeof(syslog_fac) - 1; + +// int facility_string_to_int(const char* str) +// Converts a string for a syslog to an int for that +// facility, suitable for passing to openlog() +// +// If the string can not be converted, returns +// a negative value +// +int +facility_string_to_int(const char *str) +{ + + if (str == NULL) { + return -1; + } + // Loop Through to see if the string has a valid conversion + for (int i = 0; i < convert_table_size; i++) { + if (strcasecmp(convert_table[i].long_str, str) == 0 || strcasecmp(convert_table[i].short_str, str) == 0) { + return convert_table[i].fac_int; + } + + } + return -1; +} diff --git a/lib/ts/ink_syslog.h b/lib/ts/ink_syslog.h new file mode 100644 index 00000000..450a08a7 --- /dev/null +++ b/lib/ts/ink_syslog.h @@ -0,0 +1,37 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************/ +/**************************************************************************** + * + * ink_syslog.h + * + * + ****************************************************************************/ + +#ifndef _INK_SYSLOG_H_ +#define _INK_SYSLOG_H_ + +int facility_string_to_int(const char *str); + +#endif diff --git a/lib/ts/ink_thread.cc b/lib/ts/ink_thread.cc new file mode 100644 index 00000000..bd0e3343 --- /dev/null +++ b/lib/ts/ink_thread.cc @@ -0,0 +1,40 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + + ink_thread.cc + + Generic threads interface. +**************************************************************************/ + +#include "libts.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +// // ignore the compiler warning... so that this can be used +// // in the face of changes to the Solaris header files (see "man thread") +// +// ink_mutex ink_mutex_initializer = INK_MUTEX_INIT; +// +// Put a bracketed initializer in ink_thread.h --- 9/19/96, bri +ink_mutex ink_mutex_initializer = INK_MUTEX_INIT; diff --git a/lib/ts/ink_thread.h b/lib/ts/ink_thread.h new file mode 100644 index 00000000..2aadc0a0 --- /dev/null +++ b/lib/ts/ink_thread.h @@ -0,0 +1,327 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/************************************************************************** + Generic threads interface + +**************************************************************************/ + +#ifndef _INK_THREAD_H +#define _INK_THREAD_H + + +#include "ink_port.h" +#include "ink_hrtime.h" +#include + + +////////////////////////////////////////////////////////////////////////////// +// +// The POSIX threads interface +// +////////////////////////////////////////////////////////////////////////////// + +#if defined(POSIX_THREAD) +#include +#include +#include + +#define INK_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER + +typedef pthread_t ink_thread; +typedef pthread_cond_t ink_cond; +typedef sem_t ink_sem; +typedef pthread_key_t ink_thread_key; +#endif /* #if defined(POSIX_THREAD) */ + +/******************************************************************* + *** Condition variables + ******************************************************************/ + +#ifdef POSIX_THREAD_10031c +typedef struct timespec ink_timestruc; +#else +typedef timestruc_t ink_timestruc; +#endif + +#include "ink_mutex.h" +#include +#include "ink_assert.h" + +////////////////////////////////////////////////////////////////////////////// +// +// The POSIX threads interface +// +////////////////////////////////////////////////////////////////////////////// +#if defined(POSIX_THREAD) + +static inline void +ink_thread_key_create(ink_thread_key * key, void (*destructor) (void *value)) +{ + ink_assert(!pthread_key_create(key, destructor)); +} + +static inline void +ink_thread_setspecific(ink_thread_key key, void *value) +{ + ink_assert(!pthread_setspecific(key, value)); +} + +static inline void * +ink_thread_getspecific(ink_thread_key key) +{ + return pthread_getspecific(key); +} + +static inline void +ink_thread_key_delete(ink_thread_key key) +{ + ink_assert(!pthread_key_delete(key)); +} + + +static inline ink_thread +ink_thread_create(void *(*f) (void *), void *a, int detached = 0, size_t stacksize = 0) +{ + ink_thread t; + int ret; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + + if (stacksize) { + pthread_attr_setstacksize(&attr, stacksize); + } + + if (detached) { + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + } + + ret = pthread_create(&t, &attr, f, a); + ink_assert(ret == 0); + pthread_attr_destroy(&attr); + + /** + * Fix for INKqa10118. + * If the thread has not been created successfully return 0. + */ + return ret ? (ink_thread) 0 : t; +} + +static inline void +ink_thread_cancel(ink_thread who) +{ +#if defined(freebsd) + (void) who; + ink_assert(!"not supported"); +#else + int ret = pthread_cancel(who); + ink_assert(ret == 0); +#endif +} + +static inline void * +ink_thread_join(ink_thread t) +{ + void *r; + ink_assert(!pthread_join(t, &r)); + return r; +} + +static inline ink_thread +ink_thread_self() +{ + return (pthread_self()); +} + +static inline int +ink_thread_get_priority(ink_thread t, int *priority) +{ +#if defined(freebsd) + (void) t; + (void) priority; + ink_assert(!"not supported"); + return -1; +#else + int policy; + struct sched_param param; + int res = pthread_getschedparam(t, &policy, ¶m); + *priority = param.sched_priority; + return res; +#endif +} + +static inline int +ink_thread_sigsetmask(int how, const sigset_t * set, sigset_t * oset) +{ + return (pthread_sigmask(how, set, oset)); +} + +/******************************************************************* + * Posix Semaphores + ******************************************************************/ +static inline void +ink_sem_init(ink_sem * sp, unsigned int count) +{ + ink_assert(!sem_init(sp, 0, count)); +} + +static inline void +ink_process_sem_init(ink_sem * sp, unsigned int count) +{ + ink_assert(!sem_init(sp, 1, count)); +} + +static inline void +ink_sem_wait(ink_sem * sp) +{ + int r; + while (EINTR == (r = sem_wait(sp))); + ink_assert(!r); +} + +static inline int +ink_sem_trywait(ink_sem * sp) +{ + int r; + while (EINTR == (r = sem_trywait(sp))); + ink_assert(!r || (r == EAGAIN)); + return (r); +} + +static inline void +ink_sem_post(ink_sem * sp) +{ + ink_assert(!sem_post(sp)); +} + +static inline void +ink_sem_destroy(ink_sem * sp) +{ + ink_assert(!sem_destroy(sp)); +} + +#if defined(darwin) +static inline ink_sem * +ink_sem_open(const char *name , int oflag, mode_t mode, unsigned int value) +{ + ink_sem *sptr; + sptr = sem_open(name, oflag, mode, value); + ink_assert(sptr != SEM_FAILED); + return sptr; +} + +static inline void +ink_sem_close(ink_sem * sp) +{ + ink_assert(!sem_close(sp)); +} + +static inline int +ink_sem_unlink(const char *name) +{ + return sem_unlink(name); +} +#endif /* darwin */ + +/******************************************************************* + * Posix Condition Variables + ******************************************************************/ + +static inline void +ink_cond_init(ink_cond * cp) +{ + ink_assert(pthread_cond_init(cp, NULL) == 0); +} + +static inline void +ink_cond_destroy(ink_cond * cp) +{ + ink_assert(pthread_cond_destroy(cp) == 0); +} + +static inline void +ink_cond_wait(ink_cond * cp, ink_mutex * mp) +{ + ink_assert(pthread_cond_wait(cp, mp) == 0); +} +static inline int +ink_cond_timedwait(ink_cond * cp, ink_mutex * mp, ink_timestruc * t) +{ + int err; + while (EINTR == (err = pthread_cond_timedwait(cp, mp, t))); +#if defined(freebsd) + ink_assert((err == 0) || (err == ETIMEDOUT)); +#else + ink_assert((err == 0) || (err == ETIME) || (err == ETIMEDOUT)); +#endif + return err; +} + +static inline void +ink_cond_signal(ink_cond * cp) +{ + ink_assert(pthread_cond_signal(cp) == 0); +} + +static inline void +ink_cond_broadcast(ink_cond * cp) +{ + ink_assert(pthread_cond_broadcast(cp) == 0); +} + +static inline void +ink_thr_yield() +{ + ink_assert(!sched_yield()); +} + +static inline void +ink_thread_exit(void *status) +{ + pthread_exit(status); +} + +#if defined(USE_OLD_EVENTFD) +static inline void +ink_create_pipe( int pfd[2]) +{ + ink_assert(pipe(pfd)==0); +} +#endif + +// This define is from Linux's and is most likely very +// Linux specific... Feel free to add support for other platforms +// that has a feature to give a thread specific name / tag. +static inline void +ink_set_thread_name(const char* name) +{ +#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_NAME) + prctl(PR_SET_NAME, name, 0, 0, 0); +#endif /* no prctl.h and PR_SET_NAME not supported */ +} + +#endif /* #if defined(POSIX_THREAD) */ + +#endif /*_INK_THREAD_H*/ diff --git a/lib/ts/ink_time.cc b/lib/ts/ink_time.cc new file mode 100644 index 00000000..dc5ba715 --- /dev/null +++ b/lib/ts/ink_time.cc @@ -0,0 +1,831 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + ink_time.c + + Timing routines for libts + + ****************************************************************************/ + +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_time.h" +#include "ink_assert.h" +#include "ink_string.h" +#include "ink_unused.h" + +#include +#include + +/*===========================================================================* + + Timers + + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + uint64_t microseconds(which) + + returns microsecond-resolution clock info + *---------------------------------------------------------------------------*/ + +uint64_t +ink_microseconds(int which) +{ + struct timeval tp; + struct rusage ru; + + switch (which) { + case MICRO_REAL: + gettimeofday(&tp, NULL); + break; + case MICRO_USER: + getrusage(RUSAGE_SELF, &ru); + tp = ru.ru_utime; + break; + case MICRO_SYS: + getrusage(RUSAGE_SELF, &ru); + tp = ru.ru_stime; + break; + default: + return 0; + } + + return tp.tv_sec * 1000000 + tp.tv_usec; +} + +/*---------------------------------------------------------------------------* + + double ink_time_wall_seconds() + + This routine returns a double precision number of wall clock seconds + elapsed since some fixed time in the past. + + *---------------------------------------------------------------------------*/ +double +ink_time_wall_seconds() +{ + + struct timeval s_val; + + gettimeofday(&s_val, 0); + return ((double) s_val.tv_sec + 0.000001 * s_val.tv_usec); +} /* End ink_time_wall_seconds */ + +/*===========================================================================* + + High-Level Date Processing + + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + + int ink_time_gmt_string_to_tm(char *string, struct tm *broken_down_time) + + This routine takes an ASCII string representation of a date in one + of several formats, converts the string to a calendar time, and stores the + calendar time through the pointer . + + This routine currently attempts to support RFC 1123 format, RFC 850 + format, and asctime() format. The times are expected to be in GMT time. + + If the string is successfully parsed and converted to a date, the number + of characters processed from the string is returned (useful for scanning + over a string), otherwise 0 is returned. + + *---------------------------------------------------------------------------*/ +int +ink_time_gmt_string_to_tm(char *string, struct tm *bdt) +{ + char *result; + + /* This declaration isn't being found in time.h for some reason */ + + result = NULL; + + /* Try RFC 1123 Format */ + + if (!result) + result = strptime(string, (char *) "%a, %d %b %Y %T GMT", bdt); + if (!result) + result = strptime(string, (char *) "%a, %d %b %Y %T UTC", bdt); + + /* Try RFC 850 Format */ + + if (!result) + result = strptime(string, (char *) "%A, %d-%b-%y %T GMT", bdt); + if (!result) + result = strptime(string, (char *) "%A, %d-%b-%y %T UTC", bdt); + + /* Try asctime() Format */ + + if (!result) + result = strptime(string, (char *) "%a %b %d %T %Y", bdt); + + bdt->tm_isdst = -1; + + /* If No Success, You Lose, Pal */ + + if (!result) + return (0); + + return (result - string); +} /* End ink_time_gmt_string_to_tm */ + + +/*---------------------------------------------------------------------------* + + int ink_time_gmt_tm_to_rfc1123_string(struct tm *t, char *string, int maxsize) + + This routine takes a calendar time in universal time, and converts + the time to an RFC 1123 formatted string as in "Sun, 06 Nov 1994 08:49:37 GMT", + which is placed in the string up to bytes. 1 is + returned on success, else 0. + + *---------------------------------------------------------------------------*/ +int +ink_time_gmt_tm_to_rfc1123_string(struct tm *t, char *string, int maxsize) +{ + size_t size; + + size = strftime(string, maxsize, "%a, %d %b %Y %T GMT", t); + if (size == 0) { + if (maxsize > 0) + string[0] = '\0'; + return (0); + } + return (1); +} /* End ink_time_gmt_tm_to_rfc1123_string */ + + +/*---------------------------------------------------------------------------* + + InkTimeDayID ink_time_tm_to_dayid(struct tm *t) + + This routine takes a broken-down time , and converts it to an + InkTimeDayID , representing an integer number of days since a base. + + *---------------------------------------------------------------------------*/ +InkTimeDayID +ink_time_tm_to_dayid(struct tm * t) +{ + int m, dom, y; + InkTimeDayID dayid; + + ink_time_tm_to_mdy(t, &m, &dom, &y); + dayid = ink_time_mdy_to_dayid(m, dom, y); + return (dayid); +} /* End ink_time_tm_to_dayid */ + + +/*---------------------------------------------------------------------------* + + void ink_time_dump_dayid(FILE *fp, InkTimeDayID dayid) + + This routine prints an ASCII representation of onto the file + pointer . + + *---------------------------------------------------------------------------*/ +void +ink_time_dump_dayid(FILE * fp, InkTimeDayID dayid) +{ + int m, d, y; + + ink_time_dayid_to_mdy(dayid, &m, &d, &y); + fprintf(fp, "dayid %d (%d/%d/%d)\n", dayid, m, d, y); +} /* End ink_time_dump_dayid */ + + +/*---------------------------------------------------------------------------* + + void ink_time_dayid_to_tm(InkTimeDayID dayid, struct tm *t) + + This routine takes an InkTimeDayID , representing an integer number + of days since a base, and computes a broken-down time . + + *---------------------------------------------------------------------------*/ +void +ink_time_dayid_to_tm(InkTimeDayID dayid, struct tm *t) +{ + int m, dom, y; + + ink_time_dayid_to_mdy(dayid, &m, &dom, &y); + ink_time_mdy_to_tm(m, dom, y, t); +} /* End ink_time_dayid_to_tm */ + + +/*---------------------------------------------------------------------------* + + InkTimeDayRange ink_time_dayid_to_dayrange(InkTimeDayID dayid, unsigned int width) + + This routine takes a representing a particular day, and returns + an InkTimeDayRange object of width that spans the day in question. + + *---------------------------------------------------------------------------*/ +InkTimeDayRange +ink_time_dayid_to_dayrange(InkTimeDayID dayid, unsigned int width) +{ + InkTimeDayRange range; + + range.base = dayid - (dayid % width); + range.width = width; + return (range); +} /* End ink_time_dayid_to_dayrange */ + + +/*---------------------------------------------------------------------------* + + InkTimeDayRange ink_time_chomp_off_mouthful_of_dayrange + (InkTimeDayRange *dayrange_ptr, unsigned int biggest_width) + + This routine takes a dayrange pointer , and bites off the + biggest possible chunk of the dayrange pointed to by + which is less than or equal to and whose chunk is + "chomp aligned", meaning that the start of the dayrange chunk starts on + a multiple of the width. + + The value must be a positive power of two. + + On exit, the chunk chomped off will be returned, and the original + dayrange pointed to by will be modified to consist of + the data after the chunk that was chopped off. + + If the dayrange pointed to by has no size, a dayrange + of size 0 is returned, and the original data is unmodified. + + The purpose of this routine is to decompose a range of consecutive days + into a collection of variable-sized, disjoint day ranges which cover the + original space of days. + + *---------------------------------------------------------------------------*/ +InkTimeDayRange +ink_time_chomp_off_mouthful_of_dayrange(InkTimeDayRange * dayrange_ptr, unsigned int biggest_width) +{ + unsigned int width; + InkTimeDayRange chomped_chunk; + + chomped_chunk.base = dayrange_ptr->base; + + for (width = biggest_width; width >= 1; width = width / 2) { + if ((width <= dayrange_ptr->width) && ((dayrange_ptr->base % width) == 0)) { + chomped_chunk.width = width; + + dayrange_ptr->base += width; + dayrange_ptr->width -= width; + + return (chomped_chunk); + } + } + + chomped_chunk.width = 0; + + return (chomped_chunk); +} /* End ink_time_chomp_off_mouthful_of_dayrange */ + + +/*---------------------------------------------------------------------------* + + char *ink_time_dayrange_to_string(InkTimeDayRange *dayrange_ptr, char *buf) + + This routine take a day range pointer , and places a string + representation of the day range in the buffer . The buffer must be + big enough to hold the representation of the dayrange. + + Of course, you shouldn't have any idea what the representation is, so I + guess you're hosed. Something like 64 characters is probably reasonable. + + The pointer is returned. + + *---------------------------------------------------------------------------*/ +char * +ink_time_dayrange_to_string(InkTimeDayRange * dayrange_ptr, char *buf, const size_t bufSize) +{ + if (bufSize > 0) { + buf[0] = '\0'; + } + + snprintf(buf, bufSize, "range_start_%d_width_%u", dayrange_ptr->base, dayrange_ptr->width); + return (buf); +} /* End ink_time_dayrange_to_string */ + + +/*===========================================================================* + + Date Conversion Routines + + Note that both the day of month and the month number start at 1 not zero, + so January 1 is not . + + *===========================================================================*/ + +static int _base_day = 4; /* 1/1/1970 is Thursday */ +static int _base_year = 1970; + +static int _base_daysinmonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static const char *_day_names[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +static const char *_month_names[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + + +/*---------------------------------------------------------------------------* + + void ink_time_current_mdy(int *m, int *dom, int *y) + + Gets the current local date in GMT, and returns the month, day of month, + and year in GMT. + + *---------------------------------------------------------------------------*/ +void +ink_time_current_mdy(int *m, int *dom, int *y) +{ + time_t c; + struct tm t; + c = time(0); + ink_gmtime_r(&c, &t); + ink_time_tm_to_mdy(&t, m, dom, y); +} /* End ink_time_current_mdy */ + + +/*---------------------------------------------------------------------------* + + void ink_time_tm_to_mdy(struct tm *t, int *m, int *dom, int *y) + + Takes a broken down time pointer , and returns the month, day of month, + and year. + + *---------------------------------------------------------------------------*/ +void +ink_time_tm_to_mdy(struct tm *t, int *m, int *dom, int *y) +{ + *m = t->tm_mon + 1; + *dom = t->tm_mday; + *y = t->tm_year + 1900; +} /* End ink_time_tm_to_mdy */ + + +/*---------------------------------------------------------------------------* + + void ink_time_mdy_to_tm(int m, int dom, int y, struct tm *t) + + Takes a month , day of month , and year , and places a + broken-down time in the structure pointed to by . + + *---------------------------------------------------------------------------*/ +void +ink_time_mdy_to_tm(int m, int dom, int y, struct tm *t) +{ + bzero((char *) t, sizeof(*t)); + t->tm_mon = m - 1; + t->tm_mday = dom; + t->tm_year = y - 1900; + t->tm_wday = ink_time_mdy_to_dow(m, dom, y); + t->tm_yday = ink_time_mdy_to_doy(m, dom, y); +} /* End ink_time_mdy_to_tm */ + + +/*---------------------------------------------------------------------------* + + InkTimeDayID ink_time_mdy_to_dayid(int m, int dom, int y) + + Return a single integer representing encoding of the day , . + The encoding is performed with respect to the base day. + + *---------------------------------------------------------------------------*/ +InkTimeDayID +ink_time_mdy_to_dayid(int m, int dom, int y) +{ + int year, month; + InkTimeDayID dayid; + + dayid = 0; + for (year = _base_year; year < y; year++) + dayid = dayid + ink_time_days_in_year(year); + for (month = 1; month < m; month++) + dayid = dayid + ink_time_days_in_month(month, year); + dayid = dayid + dom - 1; + return (dayid); +} /* End ink_time_mdy_to_dayid */ + + +/*---------------------------------------------------------------------------* + + InkTimeDayID ink_time_current_dayid() + + Return a single integer representing encoding of the today's date. + The encoding is performed with respect to the base day. + + *---------------------------------------------------------------------------*/ +InkTimeDayID +ink_time_current_dayid() +{ + InkTimeDayID today; + int today_m, today_d, today_y; + + ink_time_current_mdy(&today_m, &today_d, &today_y); + today = ink_time_mdy_to_dayid(today_m, today_d, today_y); + + return (today); +} /* End ink_time_current_dayid */ + + +/*---------------------------------------------------------------------------* + + void ink_time_dayid_to_mdy(InkTimeDayID dayid, int *mp, int *dp, int *yp) + + Takes a single integer representation of the date, and convert to the + month , day of month , and year . + + *---------------------------------------------------------------------------*/ +void +ink_time_dayid_to_mdy(InkTimeDayID dayid, int *mp, int *dp, int *yp) +{ + dayid = dayid + 1; + for (*yp = _base_year; ink_time_days_in_year(*yp) < dayid; (*yp)++) + dayid = dayid - ink_time_days_in_year(*yp); + for (*mp = 1; ink_time_days_in_month(*mp, *yp) < dayid; (*mp)++) + dayid = dayid - ink_time_days_in_month(*mp, *yp); + *dp = dayid; +} /* End ink_time_dayid_to_mdy */ + + +/*---------------------------------------------------------------------------* + + int ink_time_mdy_to_doy(int m, int dom, int y) + + Takes a date , and returns the number of days into year . + + *---------------------------------------------------------------------------*/ +int +ink_time_mdy_to_doy(int m, int dom, int y) +{ + InkTimeDayID first, current; + + first = ink_time_mdy_to_dayid(1, 1, y); + current = ink_time_mdy_to_dayid(m, dom, y); + return (current - first); +} /* End ink_time_mdy_to_doy */ + + +/*---------------------------------------------------------------------------* + + void ink_time_doy_to_mdy(int doy, int year, int *mon, int *dom, int *dow) + + This routine take a , and a zero-based within the year, + and determines the corresponding month, day of month, and day of week. + + *---------------------------------------------------------------------------*/ +void +ink_time_doy_to_mdy(int doy, int year, int *mon, int *dom, int *dow) +{ + int month, daysinmonth, days_so_far, next_days_so_far; + + days_so_far = 1; + for (month = 1; month <= 12; month++) { + daysinmonth = ink_time_days_in_month(month, year); + next_days_so_far = days_so_far + daysinmonth; + if (doy >= days_so_far && doy < next_days_so_far) { + *mon = month; + *dom = doy - days_so_far + 1; + *dow = ink_time_mdy_to_dow(month, *dom, year); + return; + } + days_so_far = next_days_so_far; + } +} /* End ink_time_doy_to_mdy */ + + +/*---------------------------------------------------------------------------* + + int ink_time_mdy_to_dow(int month, int dom, int year) + + What day of the week does , fall on? + + *---------------------------------------------------------------------------*/ +int +ink_time_mdy_to_dow(int month, int dom, int year) +{ + int i, base; + + base = ink_time_first_day_of_year(year); + for (i = 0; i < month - 1; i++) { + base = (base + ink_time_days_in_month(i + 1, year)) % 7; + } + return ((base + dom - 1) % 7); +} /* End ink_time_mdy_to_dow */ + + +/*---------------------------------------------------------------------------* + + int ink_time_days_in_month(int month, int year) + + This routine returns the number of days in a particular and . + + *---------------------------------------------------------------------------*/ +int +ink_time_days_in_month(int month, int year) +{ + return (_base_daysinmonth[month - 1] + (month == 2 ? ink_time_leap_year_correction(year) : 0)); +} /* End ink_time_days_in_month */ + + +/*---------------------------------------------------------------------------* + + int ink_time_days_in_year(int year) + + This routine returns the number of days in the year , compensating + for leap years. + + *---------------------------------------------------------------------------*/ +int +ink_time_days_in_year(int year) +{ + return (365 + ink_time_leap_year_correction(year)); +} /* End ink_time_days_in_year */ + + +/*---------------------------------------------------------------------------* + + int ink_time_first_day_of_year(int year) + + What day is January 1 on in this year? + + *---------------------------------------------------------------------------*/ +int +ink_time_first_day_of_year(int year) +{ + int i, base; + + base = _base_day; + if (year > _base_year) { + for (i = _base_year; i < year; i++) + base = (base + ink_time_days_in_year(i)) % 7; + } else if (year < _base_year) { + for (i = _base_year - 1; i >= year; i--) + base = ((base - ink_time_days_in_year(i)) % 7 + 7) % 7; + } + return (base); +} /* End ink_time_first_day_of_year */ + + +/*---------------------------------------------------------------------------* + + void ink_time_day_to_string(int day, char *buffer) + + This routine takes a day number and places a 3 character, NUL terminated + string representing this day in the buffer pointed to by . + + *---------------------------------------------------------------------------*/ +void +ink_time_day_to_string(int day, char *buffer, const size_t bufferSize) +{ + ink_strncpy(buffer, _day_names[day], bufferSize); +} /* End ink_time_day_to_string */ + + +/*---------------------------------------------------------------------------* + + void ink_time_month_to_string(int month, char *buffer) + + This routine takes a month number and places a 3 character, NUL terminated + string representing this day in the buffer pointed to by . + + *---------------------------------------------------------------------------*/ +void +ink_time_month_to_string(int month, char *buffer, const size_t bufferSize) +{ + ink_strncpy(buffer, _month_names[month - 1], bufferSize); +} /* End ink_time_month_to_string */ + + +/*---------------------------------------------------------------------------* + + int ink_time_string_to_month(char *str) + + This routine takes a name of a month , and returns the corresponding + month number, else -1. + + *---------------------------------------------------------------------------*/ +int +ink_time_string_to_month(char *str) +{ + int i; + + for (i = 0; i < 12; i++) { + if (strcasecmp(str, _month_names[i]) == 0) + return (i + 1); + } + return (-1); +} /* End ink_time_string_to_month */ + + +/*---------------------------------------------------------------------------* + + int ink_time_leap_year_correction(int year) + + Return 1 if is a leap year, 0 if not, and -1 if negative leap year. + + *---------------------------------------------------------------------------*/ +int +ink_time_leap_year_correction(int year) +{ + return (ink_time_is_4th_year(year) - ink_time_is_100th_year(year) + ink_time_is_400th_year(year)); +} /* End ink_time_leap_year_correction */ + +/* asah #ifndef sun asah */ +struct dtconv +{ + char *abbrev_month_names[12]; + char *month_names[12]; + char *abbrev_weekday_names[7]; + char *weekday_names[7]; + char *time_format; + char *sdate_format; + char *dtime_format; + char *am_string; + char *pm_string; + char *ldate_format; +}; +/* asah #endif asah */ + + + +/* + * The man page for cftime lies. It claims that it is thread safe. + * Instead, it silently trashes the heap (by freeing things more than + * once) when used in a mulithreaded program. Gack! + */ +int +cftime_replacement(char *s, int maxsize, const char *format, const time_t * clock) +{ + struct tm tm; + + ink_assert(localtime_r(clock, &tm) != (int) NULL); /* ADK_122100 */ + + return strftime(s, maxsize, format, &tm); +} + +#undef cftime +/* Throw an error if they ever call plain-old cftime. */ +int +cftime(char *s, char *format, const time_t * clock) +{ + (void) s; + (void) format; + (void) clock; + printf("ERROR cftime is not thread safe -- call cftime_replacement\n"); + ink_assert(!"cftime"); + return 0; +} + +#define DAYS_OFFSET 25508 + +int +ink_gmtime_r(const ink_time_t * clock, struct tm *res) +{ + static const char months[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + static const int days[12] = { + 305, 336, -1, 30, 60, 91, 121, 152, 183, 213, 244, 274 + }; + + size_t t = *clock; + + size_t d, dp; + + size_t sec = t % 60; + t /= 60; + size_t min = t % 60; + t /= 60; + size_t hour = t % 24; + t /= 24; + + /* Jan 1, 1970 was a Thursday */ + size_t wday = (4 + t) % 7; + + /* guess the year and refine the guess */ + size_t yday = t; + size_t year = yday / 365 + 69; + + d = dp = (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4 - DAYS_OFFSET - 1; + + while (dp < yday) { + d = dp; + year += 1; + dp = (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4 - DAYS_OFFSET - 1; + } + + /* convert the days */ + d = yday - d; + if (d> 366) + return -1; + + size_t month = months[d]; + if (month > 1) + year -= 1; + + size_t mday = d - days[month] - 1; + // year += 1900; real year + + res->tm_sec = (int) sec; + res->tm_min = (int) min; + res->tm_hour = (int) hour; + res->tm_mday = (int) mday; + res->tm_mon = (int) month; + res->tm_year = (int) year; + res->tm_wday = (int) wday; + res->tm_yday = (int) yday; + res->tm_isdst = 0; + + return 0; +} + +ink_time_t +convert_tm(const struct tm * tp) +{ + static const int days[12] = { + 305, 336, -1, 30, 60, 91, 121, 152, 183, 213, 244, 274 + }; + + ink_time_t t; + int year; + int month; + int mday; + + year = tp->tm_year; + month = tp->tm_mon; + mday = tp->tm_mday; + + /* what should we do? */ + if ((year<70) || (year> 137)) + return (ink_time_t) UNDEFINED_TIME; + + mday += days[month]; + /* month base == march */ + if (month < 2) + year -= 1; + mday += (year * 365) + (year / 4) - (year / 100) + (year / 100 + 3) / 4; + mday -= DAYS_OFFSET; + + t = ((mday * 24 + tp->tm_hour) * 60 + tp->tm_min) * 60 + tp->tm_sec; + + return t; +} + +char * +ink_ctime_r(const ink_time_t * clock, char *buf) +{ + return ctime_r(clock, buf); +} + +struct tm * +ink_localtime_r(const ink_time_t * clock, struct tm *res) +{ + return localtime_r(clock, res); +} diff --git a/lib/ts/ink_time.h b/lib/ts/ink_time.h new file mode 100644 index 00000000..cde556f0 --- /dev/null +++ b/lib/ts/ink_time.h @@ -0,0 +1,165 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ink_time.h + + Timing routines for libts + + + + ****************************************************************************/ + +#ifndef _ink_time_h_ +#define _ink_time_h_ + +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_hrtime.h" +#include "ink_unused.h" + +/*===========================================================================* + + Data Types + + *===========================================================================*/ + +typedef time_t ink_time_t; + +typedef int InkTimeDayID; + +typedef struct +{ + InkTimeDayID base; + unsigned int width; +} InkTimeDayRange; + +/*===========================================================================* + + Prototypes + + *===========================================================================*/ + +#define MICRO_USER 1 +#define MICRO_SYS 2 +#define MICRO_REAL 3 +#define UNDEFINED_TIME ((time_t)0) + +uint64_t ink_microseconds(int which); +double ink_time_wall_seconds(); + +int ink_time_gmt_string_to_tm(char *string, struct tm *bdt); +int ink_time_gmt_tm_to_rfc1123_string(struct tm *t, char *string, int maxsize); + +InkTimeDayID ink_time_tm_to_dayid(struct tm *t); +void ink_time_dump_dayid(FILE * fp, InkTimeDayID dayid); +void ink_time_dayid_to_tm(InkTimeDayID dayid, struct tm *t); +InkTimeDayRange ink_time_dayid_to_dayrange(InkTimeDayID dayid, unsigned int width); +InkTimeDayRange ink_time_chomp_off_mouthful_of_dayrange(InkTimeDayRange * dayrange_ptr, unsigned int biggest_width); +char *ink_time_dayrange_to_string(InkTimeDayRange * dayrange_ptr, char *buf); + +void ink_time_current_mdy(int *m, int *dom, int *y); +void ink_time_tm_to_mdy(struct tm *t, int *m, int *dom, int *y); +void ink_time_mdy_to_tm(int m, int dom, int y, struct tm *t); +InkTimeDayID ink_time_mdy_to_dayid(int m, int dom, int y); +InkTimeDayID ink_time_current_dayid(); +void ink_time_dayid_to_mdy(InkTimeDayID dayid, int *mp, int *dp, int *yp); +int ink_time_mdy_to_doy(int m, int dom, int y); +void ink_time_doy_to_mdy(int doy, int year, int *mon, int *dom, int *dow); +int ink_time_mdy_to_dow(int month, int dom, int year); +int ink_time_days_in_month(int month, int year); +int ink_time_days_in_year(int year); +int ink_time_first_day_of_year(int year); +void ink_time_day_to_string(int day, char *buffer); +void ink_time_month_to_string(int month, char *buffer); +int ink_time_string_to_month(char *str); +int ink_time_leap_year_correction(int year); + +/*===========================================================================* + + Inline Stuffage + + *===========================================================================*/ + +static inline int +ink_time_is_4th_year(int year) +{ + return ((year % 4) == 0); +} /* End ink_time_is_4th_year */ + + +static inline int +ink_time_is_100th_year(int year) +{ + return ((year % 100) == 0); +} /* End ink_time_is_100th_year */ + + +static inline int +ink_time_is_400th_year(int year) +{ + return ((year % 400) == 0); +} /* End ink_time_is_400th_year */ + +int cftime_replacement(char *s, int maxsize, const char *format, const time_t * clock); +#define cftime(s, format, clock) cftime_replacement(s, 8192, format, clock) + +inkcoreapi int ink_gmtime_r(const ink_time_t * clock, struct tm *res); +ink_time_t convert_tm(const struct tm *tp); + +#if defined(freebsd) + +inline int +ink_timezone() +{ + struct timeval tp; + struct timezone tzp; + ink_assert(!gettimeofday(&tp, &tzp)); + return tzp.tz_minuteswest * 60; +} + +/* vl: not used +inline int ink_daylight() { + struct tm atm; + time_t t = time(NULL); + ink_assert(!localtime_r(&t, &atm)); + return atm.tm_isdst; +} +*/ + +#else // non-freebsd for the else + +inline int +ink_timezone() +{ + return timezone; +} + +/* vl: not used - inline int ink_daylight() { return daylight; } */ +#endif + +inkcoreapi char *ink_ctime_r(const ink_time_t * clock, char *buf); +inkcoreapi struct tm *ink_localtime_r(const ink_time_t * clock, struct tm *res); + +#endif /* #ifndef _ink_time_h_ */ diff --git a/lib/ts/ink_unused.h b/lib/ts/ink_unused.h new file mode 100644 index 00000000..732729c3 --- /dev/null +++ b/lib/ts/ink_unused.h @@ -0,0 +1,81 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _ink_unused_h +#define _ink_unused_h + +#if ((__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) +#ifdef DEBUG +#define RELEASE_UNUSED +#else +#define RELEASE_UNUSED __attribute__ ((unused)) +#endif /* #ifdef DEBUG */ +#define UNUSED __attribute__ ((unused)) +#define INK_UNUSED __attribute__ ((unused)) +#else +#define UNUSED +#define INK_UNUSED +#define RELEASE_UNUSED +#endif /* #if ((__GNUC__ >= 3) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) */ + +#if __GNUC__ >= 3 +#if 0 /* NOT USED */ +# define inline inline __attribute__ ((always_inline)) +# define __pure __attribute__ ((pure)) +# define __const __attribute__ ((const)) +# define __noreturn __attribute__ ((noreturn)) +# define __malloc __attribute__ ((malloc)) +# define __must_check __attribute__ ((warn_unused_result)) +# define __deprecated __attribute__ ((deprecated)) +# define __used __attribute__ ((used)) +# define __unused __attribute__ ((unused)) +# define __packed __attribute__ ((packed)) +#endif +#ifndef likely +#define likely(x) __builtin_expect (!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect (!!(x), 0) +#endif +#else +#if 0 /* NOT USED */ +# define inline /* no inline */ +# define __pure /* no pure */ +# define __const /* no const */ +# define __noreturn /* no noreturn */ +# define __malloc /* no malloc */ +# define __must_check /* no warn_unused_result */ +# define __deprecated /* no deprecated */ +# define __used /* no used */ +# define __unused /* no unused */ +# define __packed /* no packed */ +#endif +#ifndef likely +#define likely(x) (x) +#endif +#ifndef unlikely +#define unlikely(x) (x) +#endif +#endif /* #if __GNUC__ >= 3 */ + +#endif /* #ifndef _ink_unused_h */ diff --git a/lib/ts/libts.h b/lib/ts/libts.h new file mode 100644 index 00000000..61dcf3a7 --- /dev/null +++ b/lib/ts/libts.h @@ -0,0 +1,113 @@ +/** @file + + Primary include file for the libts C++ library + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + libts is a collection of useful functions and methods. It + includes commonly used: + - data structures like queues, dynamic arrays atomic queues, etc. + - string manipulation functions + - bit operation functions + - Fast-Allocators ... + + The library provides a uniform interface on all platforms making the + job of porting the applications written using it very easy. + + */ + +#if !defined (_inktomiplus_h_) +#define _inktomiplus_h_ + +/* Removed for now, to fix build on Solaris +#define std *** _FIXME_REMOVE_DEPENDENCY_ON_THE_STL_ *** +*/ + +#include "ink_config.h" +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_aiocb.h" +#include "ink_align.h" +#include "ink_apidefs.h" +#include "ink_args.h" +#include "ink_assert.h" +#include "ink_atomic.h" +#include "ink_base64.h" +#include "ink_bool.h" +#include "ink_code.h" +#include "ink_defs.h" +#include "ink_error.h" +#include "ink_exception.h" +#include "ink_file.h" +#include "ink_hash_table.h" +#include "ink_hrtime.h" +#include "ink_inout.h" +#include "ink_isolatin_table.h" +#include "ink_killall.h" +#include "ink_llqueue.h" +#include "ink_lockfile.h" +#include "ink_memory.h" +#include "ink_mutex.h" +#include "ink_queue.h" +#include "ink_rand.h" +#include "ink_resolver.h" +#include "ink_resource.h" +#include "ink_sock.h" +#include "ink_inet.h" +#include "ink_sprintf.h" +#include "ink_stack_trace.h" +#include "ink_string++.h" +#include "ink_string.h" +#include "ink_syslog.h" +#include "ink_thread.h" +#include "ink_time.h" +#include "ink_unused.h" +#include "fastlz.h" + +#include "Allocator.h" +#include "Arena.h" +#include "Bitops.h" +#include "Compatability.h" +#include "DAllocator.h" +#include "DynArray.h" +#include "I_Version.h" +#include "InkPool.h" +#include "List.h" +#include "INK_MD5.h" +#include "MMH.h" +#include "Map.h" +#include "MimeTable.h" +#include "ParseRules.h" +#include "Ptr.h" +#include "RawHashTable.h" +#include "Regex.h" +#include "Resource.h" +#include "SimpleTokenizer.h" +#include "TextBuffer.h" +#include "Tokenizer.h" +#include "MatcherUtils.h" +#include "Diags.h" +#include "Regression.h" +#include "HostLookup.h" +#include "InkErrno.h" +#include "Vec.h" + +#endif /*_inktomiplus_h_*/ diff --git a/lib/ts/llqueue.cc b/lib/ts/llqueue.cc new file mode 100644 index 00000000..a14fc346 --- /dev/null +++ b/lib/ts/llqueue.cc @@ -0,0 +1,295 @@ +/** @file + + Implementation of a simple linked list queue + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_config.h" + +#include +#include +#if !defined(freebsd) && !defined(darwin) +#include +#endif +#include +#include + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "ink_llqueue.h" +#include "errno.h" + +#define RECORD_CHUNK 1024 + +// These are obviously not used anywhere, I don't know if or how they +// were supposed to work, but #ifdef'ing them out of here for now. +#ifdef NOT_USED_HERE +static LLQrec * +newrec(LLQ * Q) +{ + LLQrec * new_val; + int i; + + if (Q->free != NULL) { + new_val = Q->free; + Q->free = Q->free->next; + return new_val; + } + + + Q->free = (LLQrec *) xmalloc(RECORD_CHUNK * sizeof(LLQrec)); + + if (!Q->free) + return NULL; + + for (i = 0; i < RECORD_CHUNK; i++) + Q->free[i].next = &Q->free[i + 1]; + + Q->free[RECORD_CHUNK - 1].next = NULL; + + + new_val = Q->free; + Q->free = Q->free->next; + + return new_val; +} + +// Not used either ... +static void +freerec(LLQ * Q, LLQrec * rec) +{ + rec->next = Q->free; + Q->free = rec; +} +#endif + +LLQ * +create_queue() +{ + const char *totally_bogus_name = "create_queue"; + LLQ * new_val; + + new_val = (LLQ *) xmalloc(sizeof(LLQ)); + if (!new_val) + return NULL; + +#if defined(darwin) + static int qnum = 0; + char sname[NAME_MAX]; + qnum++; + snprintf(sname,NAME_MAX,"%s%d",totally_bogus_name,qnum); + ink_sem_unlink(sname); // FIXME: remove, semaphore should be properly deleted after usage + new_val->sema = ink_sem_open(sname, O_CREAT | O_EXCL, 0777, 0); +#else /* !darwin */ + ink_sem_init(&(new_val->sema), 0); +#endif /* !darwin */ + ink_mutex_init(&(new_val->mux), totally_bogus_name); + + new_val->head = new_val->tail = new_val->free = NULL; + new_val->len = new_val->highwater = 0; + + return new_val; +} + +// matching delete function, only for empty queue! +void +delete_queue(LLQ * Q) +{ + // There seems to have been some ideas of making sure that this queue is + // actually empty ... + // + // LLQrec * qrec; + if (Q) { + xfree(Q); + } + return; +} + +int +enqueue(LLQ * Q, void *data) +{ + LLQrec * new_val; + + ink_mutex_acquire(&(Q->mux)); + +//new_val= newrec(Q); + new_val = (LLQrec *) xmalloc(sizeof(LLQrec)); + + if (!new_val) { + ink_mutex_release(&(Q->mux)); + return 0; + } + + new_val->data = data; + new_val->next = NULL; + + if (Q->tail) + Q->tail->next = new_val; + Q->tail = new_val; + + if (Q->head == NULL) + Q->head = Q->tail; + + Q->len++; + if (Q->len > Q->highwater) + Q->highwater = Q->len; + ink_mutex_release(&(Q->mux)); +#if defined(darwin) + ink_sem_post(Q->sema); +#else + ink_sem_post(&(Q->sema)); +#endif + return 1; +} + +uint64_t +queue_len(LLQ * Q) +{ + uint64_t len; + + /* Do I really need to grab the lock here? */ + /* ink_mutex_acquire(&(Q->mux)); */ + len = Q->len; + /* ink_mutex_release(&(Q->mux)); */ + return len; +} + +uint64_t +queue_highwater(LLQ * Q) +{ + uint64_t highwater; + + /* Do I really need to grab the lock here? */ + /* ink_mutex_acquire(&(Q->mux)); */ + highwater = Q->highwater; + /* ink_mutex_release(&(Q->mux)); */ + return highwater; +} + + + +/* + *--------------------------------------------------------------------------- + * + * queue_is_empty + * + * Is the queue empty? + * + * Results: + * nonzero if empty, zero else. + * + * Side Effects: + * none. + * + * Reentrancy: n/a. + * Thread Safety: safe. + * Mem Management: n/a. + * + *--------------------------------------------------------------------------- + */ +int +queue_is_empty(LLQ * Q) +{ + uint64_t len; + + len = queue_len(Q); + + if (len) + return 0; + else + return 1; +} + +void * +dequeue(LLQ * Q) +{ + LLQrec * rec; + void *d; +#if defined(darwin) + ink_sem_wait(Q->sema); +#else + ink_sem_wait(&(Q->sema)); +#endif + ink_mutex_acquire(&(Q->mux)); + + + if (Q->head == NULL) { + + ink_mutex_release(&(Q->mux)); + + return NULL; + } + + rec = Q->head; + + Q->head = Q->head->next; + if (Q->head == NULL) + Q->tail = NULL; + + d = rec->data; +//freerec(Q, rec); + xfree(rec); + + Q->len--; + ink_mutex_release(&(Q->mux)); + + return d; +} + + + +#ifdef LLQUEUE_MAIN + +void * +testfun(void *unused) +{ + int num; + LLQ *Q; + + Q = create_queue(); + assert(Q); + + do { + scanf("%d", &num); + if (num == 0) { + printf("DEQUEUE: %d\n", (int) dequeue(Q)); + } else if (num == -1) { + printf("queue_is_empty: %d\n", queue_is_empty(Q)); + } else { + printf("enqueue: %d\n", num); + enqueue(Q, (void *) num); + } + } while (num >= -1); + + return NULL; +} + +/* + * test harness-- hit Ctrl-C if it blocks or you get tired. + */ +void +main() +{ + assert(thr_create(NULL, 0, testfun, (void *) NULL, THR_NEW_LWP, NULL) == 0); + while (1) { + ; + } +} + +#endif diff --git a/lib/ts/load_http_hdr.cc b/lib/ts/load_http_hdr.cc new file mode 100644 index 00000000..cb41bcd3 --- /dev/null +++ b/lib/ts/load_http_hdr.cc @@ -0,0 +1,436 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + load_http_hdr.cc + + Description: + + Opens a file with a dbx dump of an http hdr and prints it out + + + ****************************************************************************/ + +#include "Marshal.h" +#include "MIME.h" +#include "HTTP.h" +#include "Tokenizer.h" +#include +#include +#include +#include +#include +#include + +enum hdr_type +{ + UNKNOWN_HDR, + REQUEST_HDR, + RESPONSE_HDR, + HTTP_INFO_HDR, + RAW_MBUFFER +}; + +void walk_mime_field(MIMEField f); +void walk_mstring(MBuffer * bufp, int32_t offset); +void walk_mbuffer(MBuffer * bufp); +void print_http_info_impl(HTTPInfo hi); +void print_http_hdr_impl(HTTPHdr h); + +void +print_hdr(HTTPHdr to_print) +{ + char b[4096]; + int used, tmp, offset; + int done; + offset = 0; + do { + used = 0; + tmp = offset; + done = to_print.print(b, 4095, &used, &tmp); + offset += used; + b[used] = '\0'; + printf("%s", b); + } while (!done); +} + +void +dump_hdr(char *mbuf, hdr_type h_type) +{ + HTTPHdr to_dump; + HTTPInfo to_dump_info; + + if (h_type == RESPONSE_HDR) { + to_dump.locate_resp(mbuf); + print_hdr(to_dump); + } else if (h_type == REQUEST_HDR) { + to_dump.locate_req(mbuf); + print_hdr(to_dump); + } else { + to_dump_info.locate(mbuf); + + to_dump = to_dump_info.request_get(); + if (to_dump.valid()) { + print_hdr(to_dump); + } else { + fprintf(stderr, "HttpInfo request invalid\n"); + } + + to_dump = to_dump_info.response_get(); + + if (to_dump.valid()) { + print_hdr(to_dump); + } else { + fprintf(stderr, "HttpInfo response invalid\n"); + } + } +} + +void +load_buffer(int fd, hdr_type h_type) +{ + + struct stat s_info; + + if (fstat(fd, &s_info) < 0) { + fprintf(stderr, "Failed to stat data file : %s\n", strerror(errno)); + exit(1); + } + + char *file_buf = (char *) xmalloc(sizeof(char) * (s_info.st_size + 1)); + file_buf[s_info.st_size] = '\0'; + + + // Read in the entire file + int bytes_to_read = s_info.st_size; + while (bytes_to_read > 0) { + int done = read(fd, file_buf, bytes_to_read); + + if (done < 0) { + fprintf(stderr, "Failed to read data file : %s\n", strerror(errno)); + exit(1); + } else if (done == 0) { + fprintf(stderr, "EOF encounted\n", strerror(errno)); + exit(1); + } + + bytes_to_read -= done; + } + + Tokenizer line_tok("\n"); + Tokenizer el_tok(" \t"); + + + int num_lines = line_tok.Initialize(file_buf); + int num_el = el_tok.Initialize(line_tok[0]); + + if (num_el < 3) { + fprintf(stderr, "Corrupted data file\n"); + exit(1); + } + + int mbuf_size, mbuf_length; + if (sscanf(el_tok[2], "%x", &mbuf_length) != 1) { + fprintf(stderr, "Corrupted data file\n"); + exit(1); + } + + mbuf_size = MARSHAL_DEFAULT_SIZE; + while (mbuf_size < mbuf_length) { + mbuf_size *= 2; + } + + char *mbuf = (char *) xmalloc(mbuf_size); + int bytes_read = 0; + int cur_line = 0; + + while (cur_line < num_lines && bytes_read < mbuf_size) { + + int *cur_ptr; + num_el = el_tok.Initialize(line_tok[cur_line]); + + int el; + for (int i = 1; i < num_el; i++) { + if (sscanf(el_tok[i], "%x", &el) != 1) { + fprintf(stderr, "Corrupted data file\n"); + exit(1); + } + cur_ptr = (int *) (mbuf + bytes_read); + *cur_ptr = el; + bytes_read += 4; + } + cur_line++; + } + + if (bytes_read != mbuf_length) { + fprintf(stderr, "Size mismatch: read %d mbuf_length %d mbuf_size %d\n", bytes_read, mbuf_length, mbuf_size); +// exit(1); + } + + /* + int raw_fd = open("foo", O_RDWR |O_CREAT | O_TRUNC ); + if (raw_fd > 0) { + write(raw_fd, mbuf, mbuf_size); + close(raw_fd); + } else { + perror("open: "); + } + */ + + if (h_type == RAW_MBUFFER) { + MBuffer m_buf_struct; + memset(&m_buf_struct, 0, sizeof(MBuffer)); + mbuffer_set(&m_buf_struct, mbuf); + m_buf_struct.m_ext_refcount = 1; + m_buf_struct.m_size = bytes_read; + walk_mbuffer(&m_buf_struct); + } else { + dump_hdr(mbuf, h_type); + } +} + +int +main(int argc, const char *argv[]) +{ + + hdr_type h_type = UNKNOWN_HDR; + + http_init(); + if (argc != 3) { + fprintf(stderr, "Usage: %s req|res \n", argv[0]); + exit(1); + } + + if (strcasecmp(argv[1], "req") == 0) { + h_type = REQUEST_HDR; + } else if (strcasecmp(argv[1], "resp") == 0) { + h_type = RESPONSE_HDR; + } else if (strcasecmp(argv[1], "hinfo") == 0) { + h_type = HTTP_INFO_HDR; + } else if (strcasecmp(argv[1], "mbuf") == 0) { + h_type = RAW_MBUFFER; + } else { + fprintf(stderr, "Usage: %s req|resp|hinfo|mbuf \n", argv[0]); + exit(1); + } + + int fd = open(argv[2], O_RDONLY); + + if (fd < 0) { + fprintf(stderr, "Could not open file %s : %s\n", argv[2], strerror(errno)); + exit(1); + } + load_buffer(fd, h_type); + + return 0; +} + + +/********************************************************************* + Code for manual groking the mbuf objects +*******************************************************************/ + +//extern const char *marshal_strs[]; + +char *marshal_type_strs[] = { + "EMPTY ", + "OBJ ", + "STR ", + "URL ", + "URL_F ", + "URL_H ", + "M_VALS", + "M_FLD ", + "M_HDR ", + "H_HDR ", + "H_REQ ", + "H_RESP", + "H_INFO" +}; + +void +walk_mbuffer(MBuffer * bufp) +{ + int offset = 3; + int max_offset = (*bufp->m_length) / 4; + + do { + MObjectImpl *mo = (MObjectImpl *) mbuffer_get_obj(bufp, offset); + printf("offset %.3d m_length %.2d m_type %s ", offset, (int) mo->m_length, marshal_type_strs[mo->type]); + + switch ((int) mo->type) { + case MARSHAL_MIME_FIELD: + { + MIMEField f(bufp, offset); + walk_mime_field(f); + break; + } + case MARSHAL_STRING: + { + walk_mstring(bufp, offset); + printf("\n"); + break; + } + case MARSHAL_HTTP_INFO: + { + HTTPInfo i(bufp, offset); + print_http_info_impl(i); + printf("\n"); + break; + } + case MARSHAL_HTTP_HEADER: + case MARSHAL_HTTP_HEADER_REQ: + case MARSHAL_HTTP_HEADER_RESP: + { + HTTPHdr h(bufp, offset); + print_http_hdr_impl(h); + printf("\n"); + break; + } + + + default: + printf("\n"); + } + + offset += mo->m_length; + } while (offset < max_offset); +} + +void +walk_mstring(MBuffer * bufp, int32_t offset) +{ + int bufindex = 0; + int dumpoffset = 0; + char fbuf[4096]; + +// int32_t soffset = field_offset; +// soffset <<= MARSHAL_ALIGNMENT; +// printf("offset: %d. shifted field_offset: %d\n", +// field_offset, soffset); + + memset(fbuf, 0, 4096); + mstring_print(bufp, offset, fbuf, 4095, &bufindex, &dumpoffset); + + printf("%s", fbuf); +} + +void +walk_mime_field(MIMEField f) +{ + + int bufindex = 0; + int dumpoffset = 0; + char fbuf[4096]; + +// int32_t soffset = field_offset; +// soffset <<= MARSHAL_ALIGNMENT; +// printf("offset: %d. shifted field_offset: %d\n", +// field_offset, soffset); + + MIMEFieldImpl *fi = MIMEFieldPtr(f.m_buffer, f.m_offset); + memset(fbuf, 0, 4096); + mime_field_print(f.m_buffer, f.m_offset, fbuf, 4095, &bufindex, &dumpoffset); + + printf("(%d,%d) [%d,%d,%d] %s", (int) fi->m_nvalues, (int) fi->m_flags, + (int) fi->m_name_offset, (int) fi->m_values_offset, (int) fi->m_next_offset, fbuf); +} + +void +walk_http_resp_hdr(HTTPHdr resp) +{ + HTTPHdrImpl *r = HTTPHdrPtr(resp.m_buffer, resp.m_offset); + + printf("Http Response Hdr\n"); + + if (r->type != MARSHAL_HTTP_HEADER_RESP) { + printf("Type match failed\n"); + return; + } + + int16_t field_offset = r->m_fields_offset; + + while (field_offset != MARSHAL_NULL_OFFSET) { + MIMEFieldImpl *f = MIMEFieldPtr(resp.m_buffer, field_offset); + + MIMEField field(resp.m_buffer, field_offset); + walk_mime_field(field); + + field_offset = f->m_next_offset; + } +} + +void +walk_http_info(HTTPInfo hi) +{ + HTTPInfoImpl *info = HTTPInfoPtr(hi.m_buffer, hi.m_offset); + + printf("HttpInfo\n"); + + if (info->type != MARSHAL_HTTP_INFO) { + printf("Type match failed\n"); + return; + } + + printf("id: %d rid: %d\n", info->m_id, info->m_rid); + printf("Request Sent Time %s", ctime(&info->m_request_sent_time)); + printf("Response Received Time %s\n", ctime(&info->m_response_received_time)); + printf("Request Offset: %d Response Offset: %d", info->m_request_offset, info->m_response_offset); +} + +void +print_http_info_impl(HTTPInfo hi) +{ + HTTPInfoImpl *info = HTTPInfoPtr(hi.m_buffer, hi.m_offset); + + if (info->type != MARSHAL_HTTP_INFO) { + printf("Type match failed\n"); + return; + } + + printf("id: %d rid: %d req: %d resp: %d", + info->m_id, info->m_rid, info->m_request_offset, info->m_response_offset); +} + +void +print_http_hdr_impl(HTTPHdr h) +{ + HTTPHdrImpl *hdr = HTTPHdrPtr(h.m_buffer, h.m_offset); + + if (hdr->type == MARSHAL_HTTP_HEADER) { + printf("fields: %d", (int) hdr->m_fields_offset); + return; + } else if (hdr->type == MARSHAL_HTTP_HEADER_REQ) { + printf("method: %d url: %d fields: %d", + (int) hdr->u.req.m_method_offset, (int) hdr->u.req.m_url_offset, (int) hdr->m_fields_offset); + } else if (hdr->type == MARSHAL_HTTP_HEADER_RESP) { + printf("status: %d reason: %d fields: %d", + (int) hdr->u.resp.m_status, (int) hdr->u.resp.m_reason_offset, (int) hdr->m_fields_offset); + } else { + printf("Type match failed\n"); + return; + } + + +} diff --git a/lib/ts/lockfile.cc b/lib/ts/lockfile.cc new file mode 100644 index 00000000..67d2768c --- /dev/null +++ b/lib/ts/lockfile.cc @@ -0,0 +1,311 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_platform.h" +#include "ink_lockfile.h" + +#if defined(linux) +#include "ink_killall.h" +#endif + +#define LOCKFILE_BUF_LEN 16 // 16 bytes should be enought for a pid + +int +Lockfile::Open(pid_t * holding_pid) +{ + char buf[LOCKFILE_BUF_LEN]; + pid_t val; + int err; + *holding_pid = 0; + +#define FAIL(x) \ +{ \ + if (fd > 0) \ + close (fd); \ + return (x); \ +} + + struct flock lock; + char *t; + int size; + + fd = -1; + + // Try and open the Lockfile. Create it if it does not already + // exist. + do { + fd = open(fname, O_RDWR | O_CREAT, 0644); + } while ((fd < 0) && (errno == EINTR)); + + if (fd < 0) + return (-errno); + + // Lock it. Note that if we can't get the lock EAGAIN will be the + // error we receive. + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + + do { + err = fcntl(fd, F_SETLK, &lock); + } while ((err < 0) && (errno == EINTR)); + + if (err < 0) { + // We couldn't get the lock. Try and read the process id of the + // process holding the lock from the lockfile. + t = buf; + + for (size = 15; size > 0;) { + do { + err = read(fd, t, size); + } while ((err < 0) && (errno == EINTR)); + + if (err < 0) + FAIL(-errno); + if (err == 0) + break; + + size -= err; + t += err; + } + + *t = '\0'; + + // coverity[secure_coding] + if (sscanf(buf, "%d\n", (int*)&val) != 1) { + *holding_pid = 0; + } else { + *holding_pid = val; + } + FAIL(0); + } + // If we did get the lock, then set the close on exec flag so that + // we don't accidently pass the file descriptor to a child process + // when we do a fork/exec. + do { + err = fcntl(fd, F_GETFD, 0); + } while ((err < 0) && (errno == EINTR)); + + if (err < 0) + FAIL(-errno); + + val = err | FD_CLOEXEC; + + do { + err = fcntl(fd, F_SETFD, val); + } while ((err < 0) && (errno == EINTR)); + + if (err < 0) + FAIL(-errno); + + // Return the file descriptor of the opened lockfile. When this file + // descriptor is closed the lock will be released. + + return (1); // success + +#undef FAIL +} + +int +Lockfile::Get(pid_t * holding_pid) +{ + char buf[LOCKFILE_BUF_LEN]; + int err; + *holding_pid = 0; + + + fd = -1; + + // Open the Lockfile and get the lock. If we are successful, the + // return value will be the file descriptor of the opened Lockfile. + err = Open(holding_pid); + if (err != 1) + return err; + + if (fd < 0) { + return -1; + } + // Truncate the Lockfile effectively erasing it. + do { + err = ftruncate(fd, 0); + } while ((err < 0) && (errno == EINTR)); + + if (err < 0) { + close(fd); + return (-errno); + } + // Write our process id to the Lockfile. + snprintf(buf, sizeof(buf), "%d\n", (int) getpid()); + + do { + err = write(fd, buf, strlen(buf)); + } while ((err < 0) && (errno == EINTR)); + + if (err != (int) strlen(buf)) { + close(fd); + return (-errno); + } + + return (1); // success +} + +void +Lockfile::Close(void) +{ + if (fd != -1) { + close(fd); + } +} + +//------------------------------------------------------------------------- +// Lockfile::Kill() and Lockfile::KillAll() +// +// Open the lockfile. If we succeed it means there was no process +// holding the lock. We'll just close the file and release the lock +// in that case. If we don't succeed in getting the lock, the +// process id of the process holding the lock is returned. We +// repeatedly send the KILL signal to that process until doing so +// fails. That is, until kill says that the process id is no longer +// valid (we killed the process), or that we don't have permission +// to send a signal to that process id (the process holding the lock +// is dead and a new process has replaced it). +// +// INKqa11325 (Kevlar: linux machine hosed up if specific threads +// killed): Unfortunately, it's possible on Linux that the main PID of +// the process has been successfully killed (and is waiting to be +// reaped while in a defunct state), while some of the other threads +// of the process just don't want to go away. Integrate ink_killall +// into Kill() and KillAll() just to make sure we really kill +// everything and so that we don't spin hard while trying to kill a +// defunct process. +//------------------------------------------------------------------------- + +static void +lockfile_kill_internal(pid_t init_pid, int init_sig, pid_t pid, const char *pname, int sig) +{ + int err; + +#if defined(linux) + + pid_t *pidv; + int pidvcnt; + + // Need to grab pname's pid vector before we issue any kill signals. + // Specifically, this prevents the race-condition in which + // traffic_manager spawns a new traffic_server while we still think + // we're killall'ing the old traffic_server. + if (pname) { + ink_killall_get_pidv_xmalloc(pname, &pidv, &pidvcnt); + } + + if (init_sig > 0) { + kill(init_pid, init_sig); + // sleep for a bit and give time for the first signal to be + // delivered + sleep(1); + } + + do { + if ((err = kill(pid, sig)) == 0) { + sleep(1); + } + if (pname && (pidvcnt > 0)) { + ink_killall_kill_pidv(pidv, pidvcnt, sig); + sleep(1); + } + } while ((err == 0) || ((err < 0) && (errno == EINTR))); + + if (pidv) { + xfree(pidv); + } + +#else + + if (init_sig > 0) { + kill(init_pid, init_sig); + // sleep for a bit and give time for the first signal to be + // delivered + sleep(1); + } + + do { + err = kill(pid, sig); + } while ((err == 0) || ((err < 0) && (errno == EINTR))); + +#endif // linux check + +} + +void +Lockfile::Kill(int sig, int initial_sig, const char *pname) +{ + int err; + int pid; + pid_t holding_pid; + + err = Open(&holding_pid); + if (err == 1) // success getting the lock file + { + Close(); + } else if (err == 0) // someone else has the lock + { + pid = holding_pid; + if (pid != 0) { + lockfile_kill_internal(pid, initial_sig, pid, pname, sig); + } + } +} + +void +Lockfile::KillGroup(int sig, int initial_sig, const char *pname) +{ + int err; + int pid; + pid_t holding_pid; + + err = Open(&holding_pid); + if (err == 1) // success getting the lock file + { + Close(); + } else if (err == 0) // someone else has the lock + { + do { + pid = getpgid(holding_pid); + } while ((pid < 0) && (errno == EINTR)); + + if (pid < 0) { + pid = holding_pid; + } else { + pid = -pid; + } + + if (pid != 0) { + // We kill the holding_pid instead of the process_group + // initially since there is no point trying to get core files + // from a group since the core file of one overwrites the core + // file of another one + lockfile_kill_internal(holding_pid, initial_sig, pid, pname, sig); + } + } +} diff --git a/lib/ts/mkdfa.c b/lib/ts/mkdfa.c new file mode 100644 index 00000000..fb2d4190 --- /dev/null +++ b/lib/ts/mkdfa.c @@ -0,0 +1,665 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "ink_unused.h" + +#define TRUE 1 +#define FALSE 0 + +#define SIZEOF(t) (sizeof (t) / (sizeof ((t)[0]))) + + +typedef struct _info_t info_t; +typedef struct _state_t state_t; +typedef struct _transition_t transition_t; + +struct _info_t +{ + const char *name; + const char *value; + int namelen; +}; + +struct _state_t +{ + int num; + const char *value; + transition_t *transitions; +}; + +struct _transition_t +{ + int value; + state_t *state; + transition_t *next; +}; + + +info_t fields[] = { + {"Accept", "MIME_FIELD_ACCEPT", 0}, + {"Accept-Charset", "MIME_FIELD_ACCEPT_CHARSET", 0}, + {"Accept-Encoding", "MIME_FIELD_ACCEPT_ENCODING", 0}, + {"Accept-Language", "MIME_FIELD_ACCEPT_LANGUAGE", 0}, + {"Accept-Ranges", "MIME_FIELD_ACCEPT_RANGES", 0}, + {"Age", "MIME_FIELD_AGE", 0}, + {"Allow", "MIME_FIELD_ALLOW", 0}, + {"Approved", "MIME_FIELD_APPROVED", 0}, + {"Authorization", "MIME_FIELD_AUTHORIZATION", 0}, + {"Bytes", "MIME_FIELD_BYTES", 0}, + {"Cache-Control", "MIME_FIELD_CACHE_CONTROL", 0}, + {"Connection", "MIME_FIELD_CONNECTION", 0}, + {"Content-Base", "MIME_FIELD_CONTENT_BASE", 0}, + {"Content-Encoding", "MIME_FIELD_CONTENT_ENCODING", 0}, + {"Content-Language", "MIME_FIELD_CONTENT_LANGUAGE", 0}, + {"Content-Length", "MIME_FIELD_CONTENT_LENGTH", 0}, + {"Content-Location", "MIME_FIELD_CONTENT_LOCATION", 0}, + {"Content-Md5", "MIME_FIELD_CONTENT_MD5", 0}, + {"Content-Range", "MIME_FIELD_CONTENT_RANGE", 0}, + {"Content-Type", "MIME_FIELD_CONTENT_TYPE", 0}, + {"Control", "MIME_FIELD_CONTROL", 0}, + {"Cookie", "MIME_FIELD_COOKIE", 0}, + {"Date", "MIME_FIELD_DATE", 0}, + {"Distribution", "MIME_FIELD_DISTRIBUTION", 0}, + {"Etag", "MIME_FIELD_ETAG", 0}, + {"Expires", "MIME_FIELD_EXPIRES", 0}, + {"Followup-To", "MIME_FIELD_FOLLOWUP_TO", 0}, + {"From", "MIME_FIELD_FROM", 0}, + {"Host", "MIME_FIELD_HOST", 0}, + {"If-Match", "MIME_FIELD_IF_MATCH", 0}, + {"If-Modified-Since", "MIME_FIELD_IF_MODIFIED_SINCE", 0}, + {"If-None-Match", "MIME_FIELD_IF_NONE_MATCH", 0}, + {"If-Range", "MIME_FIELD_IF_RANGE", 0}, + {"If-Unmodified-Since", "MIME_FIELD_IF_UNMODIFIED_SINCE", 0}, + {"Keywords", "MIME_FIELD_KEYWORDS", 0}, + {"Last-Modified", "MIME_FIELD_LAST_MODIFIED", 0}, + {"Lines", "MIME_FIELD_LINES", 0}, + {"Location", "MIME_FIELD_LOCATION", 0}, + {"Max-Forwards", "MIME_FIELD_MAX_FORWARDS", 0}, + {"Message-ID", "MIME_FIELD_MESSAGE_ID", 0}, + {"Newsgroups", "MIME_FIELD_NEWSGROUPS", 0}, + {"Organization", "MIME_FIELD_ORGANIZATION", 0}, + {"Path", "MIME_FIELD_PATH", 0}, + {"Pragma", "MIME_FIELD_PRAGMA", 0}, + {"Proxy-Authenticate", "MIME_FIELD_PROXY_AUTHENTICATE", 0}, + {"Proxy-Authorization", "MIME_FIELD_PROXY_AUTHORIZATION", 0}, + {"Proxy-Connection", "MIME_FIELD_PROXY_CONNECTION", 0}, + {"Public", "MIME_FIELD_PUBLIC", 0}, + {"Range", "MIME_FIELD_RANGE", 0}, + {"References", "MIME_FIELD_REFERENCES", 0}, + {"Referer", "MIME_FIELD_REFERER", 0}, + {"Reply-To", "MIME_FIELD_REPLY_TO", 0}, + {"Retry-After", "MIME_FIELD_RETRY_AFTER", 0}, + {"Sender", "MIME_FIELD_SENDER", 0}, + {"Server", "MIME_FIELD_SERVER", 0}, + {"Set-Cookie", "MIME_FIELD_SET_COOKIE", 0}, + {"Subject", "MIME_FIELD_SUBJECT", 0}, + {"Summary", "MIME_FIELD_SUMMARY", 0}, + {"Transfer-Encoding", "MIME_FIELD_TRANSFER_ENCODING", 0}, + {"Upgrade", "MIME_FIELD_UPGRADE", 0}, + {"User-Agent", "MIME_FIELD_USER_AGENT", 0}, + {"Vary", "MIME_FIELD_VARY", 0}, + {"Via", "MIME_FIELD_VIA", 0}, + {"Warning", "MIME_FIELD_WARNING", 0}, + {"Www-Authenticate", "MIME_FIELD_WWW_AUTHENTICATE", 0}, + {"Xref", "MIME_FIELD_XREF", 0}, + {NULL, "MIME_FIELD_EXTENSION", 0}, +}; + +info_t schemes[] = { + {"file", "URL_SCHEME_FILE", 0}, + {"ftp", "URL_SCHEME_FTP", 0}, + {"gopher", "URL_SCHEME_GOPHER", 0}, + {"http", "URL_SCHEME_HTTP", 0}, + {"https", "URL_SCHEME_HTTPS", 0}, + {"mailto", "URL_SCHEME_MAILTO", 0}, + {"news", "URL_SCHEME_NEWS", 0}, + {"nntp", "URL_SCHEME_NNTP", 0}, + {"prospero", "URL_SCHEME_PROSPERO", 0}, + {"telnet", "URL_SCHEME_TELNET", 0}, + {"wais", "URL_SCHEME_WAIS", 0}, + {NULL, "URL_SCHEME_NONE", 0}, +}; + +info_t methods[] = { + {"CONNECT", "HTTP_METHOD_CONNECT", -1}, + {"DELETE", "HTTP_METHOD_DELETE", -1}, + {"GET", "HTTP_METHOD_GET", -1}, + {"HEAD", "HTTP_METHOD_HEAD", -1}, + {"HTTP/", "HTTP_METHOD_HTTP", -1}, + {"OPTIONS", "HTTP_METHOD_OPTIONS", -1}, + {"POST", "HTTP_METHOD_POST", -1}, + {"PURGE", "HTTP_METHOD_PURGE", -1}, + {"PUT", "HTTP_METHOD_PUT", -1}, + {"TRACE", "HTTP_METHOD_TRACE", -1}, + {NULL, "HTTP_METHOD_NONE", 0}, +}; + +info_t statuses[] = { + {"100", "HTTP_STATUS_CONTINUE", -1}, + {"101", "HTTP_STATUS_SWITCHING_PROTOCOL", -1}, + {"200", "HTTP_STATUS_OK", -1}, + {"201", "HTTP_STATUS_CREATED", -1}, + {"202", "HTTP_STATUS_ACCEPTED", -1}, + {"203", "HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION", -1}, + {"204", "HTTP_STATUS_NO_CONTENT", -1}, + {"205", "HTTP_STATUS_RESET_CONTENT", -1}, + {"206", "HTTP_STATUS_PARTIAL_CONTENT", -1}, + {"300", "HTTP_STATUS_MULTIPLE_CHOICES", -1}, + {"301", "HTTP_STATUS_MOVED_PERMANENTLY", -1}, + {"302", "HTTP_STATUS_MOVED_TEMPORARILY", -1}, + {"303", "HTTP_STATUS_SEE_OTHER", -1}, + {"304", "HTTP_STATUS_NOT_MODIFIED", -1}, + {"305", "HTTP_STATUS_USE_PROXY", -1}, + {"400", "HTTP_STATUS_BAD_REQUEST", -1}, + {"401", "HTTP_STATUS_UNAUTHORIZED", -1}, + {"402", "HTTP_STATUS_PAYMENT_REQUIRED", -1}, + {"403", "HTTP_STATUS_FORBIDDEN", -1}, + {"404", "HTTP_STATUS_NOT_FOUND", -1}, + {"405", "HTTP_STATUS_METHOD_NOT_ALLOWED", -1}, + {"406", "HTTP_STATUS_NOT_ACCEPTABLE", -1}, + {"407", "HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED", -1}, + {"408", "HTTP_STATUS_REQUEST_TIMEOUT", -1}, + {"409", "HTTP_STATUS_CONFLICT", -1}, + {"410", "HTTP_STATUS_GONE", -1}, + {"411", "HTTP_STATUS_LENGTH_REQUIRED", -1}, + {"412", "HTTP_STATUS_PRECONDITION_FAILED", -1}, + {"413", "HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE", -1}, + {"414", "HTTP_STATUS_REQUEST_URI_TOO_LONG", -1}, + {"415", "HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE", -1}, + {"500", "HTTP_STATUS_INTERNAL_SERVER_ERROR", -1}, + {"501", "HTTP_STATUS_NOT_IMPLEMENTED", -1}, + {"502", "HTTP_STATUS_BAD_GATEWAY", -1}, + {"503", "HTTP_STATUS_SERVICE_UNAVAILABLE", -1}, + {"504", "HTTP_STATUS_GATEWAY_TIMEOUT", -1}, + {"505", "HTTP_STATUS_HTTPVER_NOT_SUPPORTED", -1}, + {NULL, "HTTP_STATUS_NONE", 0}, +}; + +info_t days[] = { + {"Fri", "FRIDAY", -1}, + {"Friday", "FRIDAY", -1}, + {"Mon", "MONDAY", -1}, + {"Monday", "MONDAY", -1}, + {"Sat", "SATURDAY", -1}, + {"Saturday", "SATURDAY", -1}, + {"Sun", "SUNDAY", -1}, + {"Sunday", "SUNDAY", -1}, + {"Thu", "THURSDAY", -1}, + {"Thursday", "THURSDAY", -1}, + {"Tue", "TUESDAY", -1}, + {"Tuesday", "TUESDAY", -1}, + {"Wed", "WEDNESDAY", -1}, + {"Wednesday", "WEDNESDAY", -1}, + {NULL, "UNKNOWN_DAY", -1}, +}; + +info_t months[] = { + {"Apr", "APRIL", -1}, + {"Aug", "AUGUST", -1}, + {"Dec", "DECEMBER", -1}, + {"Feb", "FEBRUARY", -1}, + {"Jan", "JANUARY", -1}, + {"Jul", "JULY", -1}, + {"Jun", "JUNE", -1}, + {"Mar", "MARCH", -1}, + {"May", "MAY", -1}, + {"Nov", "NOVEMBER", -1}, + {"Oct", "OCTOBER", -1}, + {"Sep", "SEPTEMBER", -1}, + {NULL, "UNKNOWN_MONTH", -1}, +}; + +info_t connections[] = { + {"CLOSE", "HTTP_CONNECTION_CLOSE", -1}, + {"KEEP-ALIVE", "HTTP_CONNECTION_KEEP_ALIVE", -1}, + {NULL, "HTTP_CONNECTION_NONE", -1}, +}; + +info_t cache_controls[] = { + {"max-age", "HTTP_CACHE_DIRECTIVE_MAX_AGE", -1}, + {"max-stale", "HTTP_CACHE_DIRECTIVE_MAX_STALE", -1}, + {"min-fresh", "HTTP_CACHE_DIRECTIVE_MIN_FRESH", -1}, + {"must-revalidate", "HTTP_CACHE_DIRECTIVE_MUST_REVALIDATE", -1}, + {"no-cache", "HTTP_CACHE_DIRECTIVE_NO_CACHE", -1}, + {"no-store", "HTTP_CACHE_DIRECTIVE_NO_STORE", -1}, + {"no-transform", "HTTP_CACHE_DIRECTIVE_NO_TRANSFORM", -1}, + {"only-if-cached", "HTTP_CACHE_DIRECTIVE_ONLY_IF_CACHED", -1}, + {"private", "HTTP_CACHE_DIRECTIVE_PRIVATE", -1}, + {"proxy-revalidate", "HTTP_CACHE_DIRECTIVE_PROXY_REVALIDATE", -1}, + {"public", "HTTP_CACHE_DIRECTIVE_PUBLIC", -1}, + {"s-maxage", "HTTP_CACHE_DIRECTIVE_S_MAX_AGE", -1}, + {NULL, "HTTP_CACHE_DIRECTIVE_CACHE_EXTENSION", -1}, +}; + + +state_t *start = NULL; +int state_count = 0; + +int *map = NULL; +int *basetbl = NULL; +int *nexttbl = NULL; +int *checktbl = NULL; +const char **accepttbl = NULL; +char **prefixtbl = NULL; + + +state_t * +mkstate() +{ + state_t *state; + + state = (state_t *) malloc(sizeof(state_t)); + state->num = state_count++; + state->value = NULL; + state->transitions = NULL; + + return state; +} + +transition_t * +mktransition() +{ + transition_t *transition; + + transition = (transition_t *) malloc(sizeof(transition_t)); + transition->value = 0; + transition->state = NULL; + transition->next = NULL; + + return transition; +} + +void +prstate(state_t * state) +{ + transition_t *transitions; + + printf("%3d:", state->num); + + if (state->value) + printf(" %s", state->value); + printf("\n"); + + transitions = state->transitions; + while (transitions) { + printf(" %c --> %d\n", tolower(transitions->value), transitions->state->num); + transitions = transitions->next; + } + + transitions = state->transitions; + while (transitions) { + prstate(transitions->state); + transitions = transitions->next; + } +} + +void +add_states(state_t * state, info_t * info, int pos) +{ + transition_t *transitions; + + if (info->namelen == pos) { + state->value = info->value; + return; + } + + transitions = state->transitions; + while (transitions) { + if (tolower(transitions->value) == tolower(info->name[pos])) { + if ((transitions->state->value && (info->namelen == (pos + 1))) || (info->namelen != (pos + 1))) { + add_states(transitions->state, info, pos + 1); + return; + } + } + + transitions = transitions->next; + } + + if (state->transitions) { + transitions = state->transitions; + while (transitions->next) + transitions = transitions->next; + + transitions->next = mktransition(); + transitions = transitions->next; + } else { + transitions = mktransition(); + state->transitions = transitions; + } + + transitions->value = info->name[pos]; + transitions->state = mkstate(); + + add_states(transitions->state, info, pos + 1); +} + +void +prtable(const char *type, const char *name, int *table, int size) +{ + int i; + + printf(" static %s %s[%d] =\n", type, name, size); + printf(" {\n"); + + for (i = 0; i < size; i++) { + if ((i % 12) == 0) + printf(" %3d,", table[i]); + else if ((i % 12) == 11) + printf(" %3d,\n", table[i]); + else + printf(" %3d,", table[i]); + } + + if ((i % 12) != 0) + printf("\n"); + + printf(" };\n"); +} + +int +mkmap(state_t * state) +{ + static int count = 1; + + transition_t *transitions; + + transitions = state->transitions; + while (transitions) { + if (map[tolower(transitions->value)] == 0) { + map[tolower(transitions->value)] = count; + map[toupper(transitions->value)] = count; + count += 1; + } + + mkmap(transitions->state); + + transitions = transitions->next; + } + + return count; +} + +void +mkaccept(state_t * state, const char *defvalue) +{ + transition_t *transitions; + + if (state->value) + accepttbl[state->num] = state->value; + else + accepttbl[state->num] = defvalue; + + transitions = state->transitions; + while (transitions) { + mkaccept(transitions->state, defvalue); + transitions = transitions->next; + } +} + +void +mkprefix(state_t * state, char *prefix, int length) +{ + transition_t *transitions; + + prefixtbl[state->num] = (char *) malloc(sizeof(char) * (length + 1)); + strncpy(prefixtbl[state->num], prefix, length); + prefixtbl[state->num][length] = '\0'; + + transitions = state->transitions; + while (transitions) { + prefix[length] = transitions->value; + mkprefix(transitions->state, prefix, length + 1); + transitions = transitions->next; + } +} + +int +checkbase(state_t * state, int base) +{ + transition_t *transitions; + + transitions = state->transitions; + while (transitions) { + if (checktbl[base + map[transitions->value]] != -1) + return 0; + transitions = transitions->next; + } + + return 1; +} + +void +mktranstables(state_t * state) +{ + transition_t *transitions; + int base; + + base = 0; + while (base < state_count) { + if (checkbase(state, base)) + break; + base += 1; + } + + assert(base < state_count); + + basetbl[state->num] = base; + + transitions = state->transitions; + while (transitions) { + assert(checktbl[basetbl[state->num] + map[transitions->value]] == -1); + + checktbl[basetbl[state->num] + map[transitions->value]] = state->num; + nexttbl[basetbl[state->num] + map[transitions->value]] = transitions->state->num; + transitions = transitions->next; + } + + transitions = state->transitions; + while (transitions) { + mktranstables(transitions->state); + transitions = transitions->next; + } +} + +void +mktables(state_t * state, const char *defvalue, int useprefix) +{ + char prefix[1024]; + int char_count; + int i; + + /* make the character map */ + map = (int *) malloc(sizeof(int) * 256); + for (i = 0; i < 256; i++) + map[i] = 0; + + char_count = mkmap(state); + + prtable("int", "map", map, 256); + printf("\n"); + + /* make the accept state table */ + accepttbl = (const char **) malloc(sizeof(const char *) * state_count); + for (i = 0; i < state_count; i++) + accepttbl[i] = NULL; + + mkaccept(state, defvalue); + + /* print the accept state table */ + printf(" static int accepttbl[%d] =\n", state_count); + printf(" {\n"); + + for (i = 0; i < state_count; i++) + printf(" %s,\n", accepttbl[i]); + + printf(" };\n\n"); + + /* make the prefix table */ + if (useprefix) { + prefixtbl = (char **) malloc(sizeof(char *) * state_count); + for (i = 0; i < state_count; i++) + prefixtbl[i] = NULL; + + mkprefix(state, prefix, 0); + + /* print the prefix table */ + printf(" static const char *prefixtbl[%d] =\n", state_count); + printf(" {\n"); + + for (i = 0; i < state_count; i++) + printf(" \"%s\",\n", prefixtbl[i]); + + printf(" };\n\n"); + } + + /* make the state transition tables */ + + basetbl = (int *) malloc(sizeof(int) * state_count); + nexttbl = (int *) malloc(sizeof(int) * (state_count + char_count)); + checktbl = (int *) malloc(sizeof(int) * (state_count + char_count)); + + for (i = 0; i < state_count; i++) { + basetbl[i] = -1; + } + + for (i = 0; i < (state_count + char_count); i++) { + nexttbl[i] = 0; + checktbl[i] = -1; + } + + mktranstables(state); + + prtable("int", "basetbl", basetbl, state_count); + printf("\n"); + prtable("int", "nexttbl", nexttbl, state_count + char_count); + printf("\n"); + prtable("int", "checktbl", checktbl, state_count + char_count); +} + +const char * +rundfa(const char *buf, int length) +{ + const char *end; + int state; + int ch, tmp; + + state = 0; + end = buf + length; + + while (buf != end) { + ch = map[(int) *buf++]; + + tmp = basetbl[state] + ch; + if (checktbl[tmp] != state) + return NULL; + state = nexttbl[tmp]; + } + + return accepttbl[state]; +} + +void +mkdfa(info_t * infos, int ninfos, int useprefix, int debug) +{ + /* + static const char *names[] = + { + "foo", + "bar", + "foobar", + "argh", + "filep", + }; + static int nnames = SIZEOF (names); + const char *accept; + */ + + int i; + + start = mkstate(); + + for (i = 0; i < (ninfos - 1); i++) + infos[i].namelen = strlen(infos[i].name); + + for (i = 0; i < (ninfos - 1); i++) + add_states(start, &infos[i], 0); + + mktables(start, infos[ninfos - 1].value, useprefix); + + if (debug) { + printf("\n/*\n"); + prstate(start); + printf("*/\n"); + + /* + for (i = 0; i < ninfos; i++) + { + accept = rundfa (infos[i].name, infos[i].namelen); + if (accept) + printf ("%s\n", accept); + else + printf ("%s not accepted\n", infos[i].name); + } + + for (i = 0; i < nnames; i++) + { + accept = rundfa (names[i], strlen (names[i])); + if (accept) + printf ("%s\n", accept); + else + printf ("%s not accepted\n", names[i]); + } + */ + } +} + +int +main(int argc, char *argv[]) +{ + if (argc < 2) + return 1; + + if (strcmp(argv[1], "fields") == 0) + mkdfa(fields, SIZEOF(fields), 1, (argc == 3)); + else if (strcmp(argv[1], "methods") == 0) + mkdfa(methods, SIZEOF(methods), 0, (argc == 3)); + else if (strcmp(argv[1], "statuses") == 0) + mkdfa(statuses, SIZEOF(statuses), 0, (argc == 3)); + else if (strcmp(argv[1], "schemes") == 0) + mkdfa(schemes, SIZEOF(schemes), 0, (argc == 3)); + else if (strcmp(argv[1], "days") == 0) + mkdfa(days, SIZEOF(days), 0, (argc == 3)); + else if (strcmp(argv[1], "months") == 0) + mkdfa(months, SIZEOF(months), 0, (argc == 3)); + else if (strcmp(argv[1], "connections") == 0) + mkdfa(connections, SIZEOF(connections), 0, (argc == 3)); + else if (strcmp(argv[1], "cache-controls") == 0) + mkdfa(cache_controls, SIZEOF(cache_controls), 0, (argc == 3)); + + return 0; +} diff --git a/lib/ts/test_List.cc b/lib/ts/test_List.cc new file mode 100644 index 00000000..1bc03acc --- /dev/null +++ b/lib/ts/test_List.cc @@ -0,0 +1,59 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "List.h" + +class Foo { public: + int x; + + virtual void foo() {} + + SLINK(Foo, slink); + LINK(Foo, dlink); + + Foo(int i = 0): x(i) {} +}; + +int main() { + SList(Foo,slink) s; + DList(Foo,dlink) d; + Que(Foo,dlink) q; + Foo *f = new Foo; + f->x = 7; + s.push(f); + d.push(s.pop()); + q.enqueue(d.pop()); + for (int i = 0; i < 100; i++) + q.enqueue(new Foo(i)); + int tot = 0; + for (int i = 0; i < 101; i++) + tot += q.dequeue()->x; + if (tot != 4957) { + printf("test_List FAILED\n"); + exit(1); + } else { + printf("test_List PASSED\n"); + exit(0); + } +} diff --git a/lib/ts/test_Map.cc b/lib/ts/test_Map.cc new file mode 100644 index 00000000..27d48c2c --- /dev/null +++ b/lib/ts/test_Map.cc @@ -0,0 +1,112 @@ +/** @file + + Test code for the Map templates. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#include +#include "Map.h" + +typedef const char cchar; + +int main(int argc, char **argv) { + typedef Map SSMap; + typedef MapElem SSMapElem; +#define form_SSMap(_p, _v) form_Map(SSMapElem, _p, _v) + SSMap ssm; + ssm.put("a", "A"); + ssm.put("b", "B"); + ssm.put("c", "C"); + ssm.put("d", "D"); + form_SSMap(x, ssm) ; + + StringChainHash<> h; + cchar *hi = "hi", *ho = "ho", *hum = "hum", *hhi = "hhi"; + hhi++; + h.put(hi); + h.put(ho); + ink_assert(h.put(hum) == hum); + ink_assert(h.put(hhi) == hi); + ink_assert(h.get(hhi) == hi && h.get(hi) == hi && h.get(ho) == ho); + ink_assert(h.get("he") == 0 && h.get("hee") == 0); + h.del(ho); + ink_assert(h.get(ho) == 0); + + StringBlockHash hh; + hh.put(hi); + hh.put(ho); + ink_assert(hh.put(hum) == 0); + ink_assert(hh.put(hhi) == hi); + ink_assert(hh.get(hhi) == hi && hh.get(hi) == hi && hh.get(ho) == ho); + ink_assert(hh.get("he") == 0 && hh.get("hee") == 0); + hh.del(hi); + ink_assert(hh.get(hhi) == 0); + ink_assert(hh.get(hi) == 0); + + HashMap sh; + sh.put(hi, 1); + sh.put(ho, 2); + sh.put(hum, 3); + sh.put(hhi, 4); + ink_assert(sh.get(hi) == 4); + ink_assert(sh.get(ho) == 2); + ink_assert(sh.get(hum) == 3); + sh.put("aa", 5); + sh.put("ab", 6); + sh.put("ac", 7); + sh.put("ad", 8); + sh.put("ae", 9); + sh.put("af", 10); + ink_assert(sh.get(hi) == 4); + ink_assert(sh.get(ho) == 2); + ink_assert(sh.get(hum) == 3); + ink_assert(sh.get("af") == 10); + ink_assert(sh.get("ac") == 7); + + ChainHashMap ssh; + ssh.put(hi, 1); + ssh.put(ho, 2); + ssh.put(hum, 3); + ssh.put(hhi, 4); + ink_assert(ssh.get(hi) == 4); + ink_assert(ssh.get(ho) == 2); + ink_assert(ssh.get(hum) == 3); + ssh.put("aa", 5); + ssh.put("ab", 6); + ssh.put("ac", 7); + ssh.put("ad", 8); + ssh.put("ae", 9); + ssh.put("af", 10); + ink_assert(ssh.get(hi) == 4); + ink_assert(ssh.get(ho) == 2); + ink_assert(ssh.get(hum) == 3); + ink_assert(ssh.get("af") == 10); + ink_assert(ssh.get("ac") == 7); + ssh.del(ho); + ink_assert(ssh.get(ho) == 0); + + Vec ints; + ssh.get_values(ints); + ink_assert(ints.n == 8); + Vec chars; + ssh.get_keys(chars); + ink_assert(chars.n == 8); + printf("test_Map PASSED\n"); +} + diff --git a/lib/ts/test_Vec.cc b/lib/ts/test_Vec.cc new file mode 100644 index 00000000..0b54643c --- /dev/null +++ b/lib/ts/test_Vec.cc @@ -0,0 +1,97 @@ +/* -*-Mode: c++;-*- + Various vector related code. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* UnionFind after Tarjan */ + +#include +#include +#include +#include "Vec.h" + +int main(int argc, char **argv) { + Vec v, vv, vvv; + int tt = 99 * 50, t = 0; + + for (int i = 0; i < 100; i++) + v.add((void*)(intptr_t)i); + for (int i = 0; i < 100; i++) + t += (int)(intptr_t)v.v[i]; + ink_assert(t == tt); + + t = 0; + for (int i = 1; i < 100; i++) + vv.set_add((void*)(intptr_t)i); + for (int i = 1; i < 100; i++) + vvv.set_add((void*)(intptr_t)i); + for (int i = 1; i < 100; i++) + vvv.set_add((void*)(intptr_t)(i * 1000)); + vv.set_union(vvv); + for (int i = 0; i < vv.n; i++) + if (vv.v[i]) + t += (int)(intptr_t)vv.v[i]; + ink_assert(t == tt + 1000 * tt); + + v.clear(); + v.reserve(1000); + t = 0; + for (int i = 0; i < 1000; i++) + v.add((void*)(intptr_t)i); + for (int i = 0; i < 1000; i++) + t += (int)(intptr_t)v.v[i]; + ink_assert(t == 999 * 500); + printf("%d %d\n", v.n, v.i); + + Intervals in; + in.insert(1); + ink_assert(in.n == 2); + in.insert(2); + ink_assert(in.n == 2); + in.insert(6); + ink_assert(in.n == 4); + in.insert(7); + ink_assert(in.n == 4); + in.insert(9); + ink_assert(in.n == 6); + in.insert(4); + ink_assert(in.n == 8); + in.insert(5); + ink_assert(in.n == 6); + in.insert(3); + ink_assert(in.n == 4); + in.insert(8); + ink_assert(in.n == 2); + + UnionFind uf; + uf.size(4); + uf.unify(0,1); + uf.unify(2,3); + ink_assert(uf.find(2) == uf.find(3)); + ink_assert(uf.find(0) == uf.find(1)); + ink_assert(uf.find(0) != uf.find(3)); + ink_assert(uf.find(1) != uf.find(3)); + ink_assert(uf.find(1) != uf.find(2)); + ink_assert(uf.find(0) != uf.find(2)); + uf.unify(1,2); + ink_assert(uf.find(0) == uf.find(3)); + ink_assert(uf.find(1) == uf.find(3)); + printf("test_Vec PASSED\n"); +} diff --git a/lib/ts/test_arena.cc b/lib/ts/test_arena.cc new file mode 100644 index 00000000..e0d83b2c --- /dev/null +++ b/lib/ts/test_arena.cc @@ -0,0 +1,126 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ArenaTest.cc + + Description: + + A short test program intended to be used with Purify to detect problems + with the arnea code + + + ****************************************************************************/ + +#include "Arena.h" +#include + +void +fill_test_data(char *ptr, int size, int seed) +{ + char a = 'a' + (seed % 52); + + for (int i = 0; i < size; i++) { + ptr[i] = a; + a = (a + 1) % 52; + } +} + +int +check_test_data(char *ptr, int size, int seed) +{ + int fail = 0; + char a = 'a' + (seed % 52); + + for (int i = 0; i < size; i++) { + if (ptr[i] != a) { + fail++; + } + a = (a + 1) % 52; + } + + return fail; +} + +int +test_block_boundries() +{ + const int sizes_to_test = 12; + const int regions_to_test = 1024 * 2; + char **test_regions = new char *[regions_to_test]; + int failures = 0; + Arena *a = new Arena(); + + + for (int i = 0; i < sizes_to_test; i++) { + int test_size = 1 << i; + + // Clear out the regions array + int j = 0; + for (j = 0; j < regions_to_test; j++) { + test_regions[j] = NULL; + } + + // Allocate and fill the array + for (j = 0; j < regions_to_test; j++) { + test_regions[j] = (char *) a->alloc(test_size); + fill_test_data(test_regions[j], test_size, j); + } + + // Now check to make sure the data is correct + for (j = 0; j < regions_to_test; j++) { + int f = check_test_data(test_regions[j], test_size, j); + + if (f != 0) { + fprintf(stderr, "block_boundries test failed. size %d region %d\n", test_size, j); + failures++; + } + } + + // Now free the regions + for (j = 0; j < regions_to_test; j++) { + a->free(test_regions[j], test_size); + } + + a->reset(); + } + + delete[]test_regions; + delete a; + return failures; +} + +int +main() +{ + int failures = 0; + + failures += test_block_boundries(); + + if (failures) { + return 1; + } else { + return 0; + } +} diff --git a/lib/ts/test_atomic.cc b/lib/ts/test_atomic.cc new file mode 100644 index 00000000..10aca260 --- /dev/null +++ b/lib/ts/test_atomic.cc @@ -0,0 +1,237 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +//////////////////////////////////////////////////////////////////////////// +// NT Build Notes: +// 1) Enable the following #include. +// Visual C++ does not allow this under #ifdef +// #include "stdafx.h" +// +// 2) Create a new project within the existing TS project +// which is a "WIN32 Console Application" +// with the "Simple Application" option. +// 3) Replace C/C++ Preprocessor definitions with traffic_server +// definitions. +// 4) Replace C/C++ Additional includes with traffic server +// definitions. Prepend "..\proxy" to directories in proxy. +// Add "..\proxy". +// 5) Replace C/C++ project option "/MLd" with "/MTd" +// 6) Add libts as dependency. +//////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "ink_atomic.h" +#include "ink_queue.h" +#include "ink_thread.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + + +#ifndef LONG_ATOMICLIST_TEST + +#define MAX_ALIST_TEST 10 +#define MAX_ALIST_ARRAY 100000 +InkAtomicList al[MAX_ALIST_TEST]; +void *al_test[MAX_ALIST_TEST][MAX_ALIST_ARRAY]; +volatile int al_done = 0; + +void * +testalist(void *ame) +{ + int me = (int) (uintptr_t) ame; + int j, k; + for (k = 0; k < MAX_ALIST_ARRAY; k++) + ink_atomiclist_push(&al[k % MAX_ALIST_TEST], &al_test[me][k]); + void *x; + for (j = 0; j < 1000000; j++) + if ((x = ink_atomiclist_pop(&al[me]))) + ink_atomiclist_push(&al[rand() % MAX_ALIST_TEST], x); + ink_atomic_increment((int *) &al_done, 1); + return NULL; +} +#endif // !LONG_ATOMICLIST_TEST + +#ifdef LONG_ATOMICLIST_TEST +/************************************************************************/ +#define MAX_ATOMIC_LISTS (4 * 1024) +#define MAX_ITEMS_PER_LIST (1 * 1024) +#define MAX_TEST_THREADS 64 +static InkAtomicList alists[MAX_ATOMIC_LISTS]; +struct listItem *items[MAX_ATOMIC_LISTS * MAX_ITEMS_PER_LIST]; + +struct listItem +{ + int data1; + int data2; + void *link; + int data3; + int data4; + int check; +}; + +void +init_data() +{ + int j; + int ali; + struct listItem l; + struct listItem *plistItem; + + for (ali = 0; ali < MAX_ATOMIC_LISTS; ali++) + ink_atomiclist_init(&alists[ali], "alist", ((char *) &l.link - (char *) &l)); + + for (ali = 0; ali < MAX_ATOMIC_LISTS; ali++) { + for (j = 0; j < MAX_ITEMS_PER_LIST; j++) { + plistItem = (struct listItem *) malloc(sizeof(struct listItem)); + items[ali + j] = plistItem; + plistItem->data1 = ali + j; + plistItem->data2 = ali + rand(); + plistItem->link = 0; + plistItem->data3 = j + rand(); + plistItem->data4 = ali + j + rand(); + plistItem->check = (plistItem->data1 ^ plistItem->data2 ^ plistItem->data3 ^ plistItem->data4); + ink_atomiclist_push(&alists[ali], plistItem); + } + } +} + +void +cycle_data(void *d) +{ + InkAtomicList *l; + struct listItem *pli; + struct listItem *pli_next; + int iterations; + int me; + + me = (int) d; + iterations = 0; + + while (1) { + l = &alists[(me + rand()) % MAX_ATOMIC_LISTS]; + + pli = (struct listItem *) ink_atomiclist_popall(l); + if (!pli) + continue; + + // Place listItems into random queues + while (pli) { + ink_assert((pli->data1 ^ pli->data2 ^ pli->data3 ^ pli->data4) == pli->check); + pli_next = (struct listItem *) pli->link; + pli->link = 0; + ink_atomiclist_push(&alists[(me + rand()) % MAX_ATOMIC_LISTS], (void *) pli); + pli = pli_next; + } + iterations++; + poll(0, 0, 10); // 10 msec delay + if ((iterations % 100) == 0) + printf("%d ", me); + } +} + +/************************************************************************/ +#endif // LONG_ATOMICLIST_TEST + +int +main(int argc, const char *argv[]) +{ +#ifndef LONG_ATOMICLIST_TEST + int32_t m = 1, n = 100; + //int64 lm = 1LL, ln = 100LL; + const char* m2 = "hello"; + char* n2; + + printf("sizeof(int32_t)==%d sizeof(void *)==%d\n", (int)sizeof(int32_t), (int)sizeof(void *)); + + + printf("CAS: %d == 1 then 2\n", m); + n = ink_atomic_cas(&m, 1, 2); + printf("changed to: %d, result=%s\n", m, n ? "true" : "false"); + + printf("CAS: %d == 1 then 3\n", m); + n = ink_atomic_cas(&m, 1, 3); + printf("changed to: %d, result=%s\n", m, n ? "true" : "false"); + + printf("CAS pointer: '%s' == 'hello' then 'new'\n", m2); + n = ink_atomic_cas_ptr((pvvoidp) &m2, (char *) "hello", (char *) "new"); + printf("changed to: %s, result=%s\n", m2, n ? (char *) "true" : (char *) "false"); + + printf("CAS pointer: '%s' == 'hello' then 'new2'\n", m2); + n = ink_atomic_cas_ptr((pvvoidp)&m2, (char*)m2, (char *) "new2"); + printf("changed to: %s, result=%s\n", m2, n ? "true" : "false"); + + n = 100; + printf("Atomic Inc of %d\n", n); + m = ink_atomic_increment((int *) &n, 1); + printf("changed to: %d, result=%d\n", n, m); + + + printf("Atomic Fetch-and-Add 2 to pointer to '%s'\n", m2); + n2 = (char *)ink_atomic_increment_ptr((pvvoidp)&m2, 2); + printf("changed to: %s, result=%s\n", m2, n2); + + printf("Testing atomic lists\n"); + { + int ali; + srand(time(NULL)); + printf("sizeof(al_test) = %d\n", (int)sizeof(al_test)); + memset(&al_test[0][0], 0, sizeof(al_test)); + for (ali = 0; ali < MAX_ALIST_TEST; ali++) + ink_atomiclist_init(&al[ali], "foo", 0); + for (ali = 0; ali < MAX_ALIST_TEST; ali++) { + ink_thread tid; + pthread_attr_t attr; + + pthread_attr_init(&attr); +#if !defined(freebsd) + pthread_attr_setstacksize(&attr, 1024 * 1024); +#endif + ink_assert(pthread_create(&tid, &attr, testalist, (void *)((intptr_t)ali)) == 0); + } + while (al_done != MAX_ALIST_TEST) + sleep(1); + } +#endif // !LONG_ATOMICLIST_TEST + +#ifdef LONG_ATOMICLIST_TEST + printf("Testing atomic lists (long version)\n"); + { + int id; + + init_data(); + for (id = 0; id < MAX_TEST_THREADS; id++) { + ink_assert(thr_create(NULL, 0, cycle_data, (void *) id, THR_NEW_LWP, NULL) == 0); + } + } + while (1) { + poll(0, 0, 10); // 10 msec delay + } +#endif // LONG_ATOMICLIST_TEST + + return 0; +} diff --git a/lib/ts/test_freelist.cc b/lib/ts/test_freelist.cc new file mode 100644 index 00000000..eb37dac3 --- /dev/null +++ b/lib/ts/test_freelist.cc @@ -0,0 +1,90 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include "ink_thread.h" +#include "ink_queue.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + + +#define NTHREADS 64 + + +InkFreeList *flist = NULL; + + +void * +test(void *d) +{ + int id; + void *m1, *m2, *m3; + + id = *((int *) &d); + + time_t start = time(NULL); + int count = 0; + for (;;) { + m1 = ink_freelist_new(flist); + m2 = ink_freelist_new(flist); + m3 = ink_freelist_new(flist); + + if ((m1 == m2) || (m1 == m3) || (m2 == m3)) { + printf("0x%08" PRIx64 " 0x%08" PRIx64 " 0x%08" PRIx64 "\n", + (uint64_t)(uintptr_t)m1, (uint64_t)(uintptr_t)m2, (uint64_t)(uintptr_t)m3); + exit(1); + } + + memset(m1, id, 64); + memset(m2, id, 64); + memset(m3, id, 64); + + ink_freelist_free(flist, m1); + ink_freelist_free(flist, m2); + ink_freelist_free(flist, m3); + + // break out of the test if we have run more then 60 seconds + if (++count % 1000 == 0 && (start + 60) < time(NULL)) { + return NULL; + } + } + +} + + +int +main(int argc, char *argv[]) +{ + int i; + + flist = ink_freelist_create("woof", 64, 256, 0, 8); + + for (i = 0; i < NTHREADS; i++) { + fprintf(stderr, "Create thread %d\n", i); + ink_thread_create(test, (void *)((intptr_t)i)); + } + + test((void *) NTHREADS); + + return 0; +} diff --git a/lib/ts/test_memchr.cc b/lib/ts/test_memchr.cc new file mode 100644 index 00000000..6f990fd8 --- /dev/null +++ b/lib/ts/test_memchr.cc @@ -0,0 +1,171 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include + +// +// fast memchr +// +void * +ink_memchr(const void *as, int ac, size_t an) +{ + unsigned char c = (unsigned char) ac; + unsigned char *s = (unsigned char *) as; + + // initial segment + + int i_len = (int)(((uintptr_t) 8 - (uintptr_t) as) & 7); + + // too short to concern us + + if ((int) an < i_len) { + for (int i = 0; i < (int) an; i++) + if (s[i] == c) + return &s[i]; + return 0; + } + // bytes 0-3 + + switch (i_len & 3) { + case 3: + if (*s++ == c) + return s - 1; + case 2: + if (*s++ == c) + return s - 1; + case 1: + if (*s++ == c) + return s - 1; + case 0: + break; + } + + // bytes 4-8 + + unsigned int ib = c; + ib |= (ib << 8); + ib |= (ib << 16); + unsigned int im = 0x7efefeff; + if (i_len & 4) { + unsigned int ibp = *(unsigned int *) s; + unsigned int ibb = ibp ^ ib; + ibb = ((ibb + im) ^ ~ibb) & ~im; + if (ibb) { + if (s[0] == c) + return &s[0]; + if (s[1] == c) + return &s[1]; + if (s[2] == c) + return &s[2]; + if (s[3] == c) + return &s[3]; + } + s += 4; + } + // next 8x bytes + uint64_t m = 0x7efefefefefefeffLL; + uint64_t b = ((uint64_t) ib); + b |= (b << 32); + uint64_t *p = (uint64_t *) s; + unsigned int n = (((unsigned int) an) - (s - (unsigned char *) as)) >> 3; + uint64_t *end = p + n; + while (p < end) { + uint64_t bp = *p; + uint64_t bb = bp ^ b; + bb = ((bb + m) ^ ~bb) & ~m; + if (bb) { + s = (unsigned char *) p; + if (s[0] == c) + return &s[0]; + if (s[1] == c) + return &s[1]; + if (s[2] == c) + return &s[2]; + if (s[3] == c) + return &s[3]; + if (s[4] == c) + return &s[4]; + if (s[5] == c) + return &s[5]; + if (s[6] == c) + return &s[6]; + if (s[7] == c) + return &s[7]; + } + p++; + } + + // terminal segement + + i_len = an - (((unsigned char *) p) - ((unsigned char *) as)); + s = (unsigned char *) p; + + // n-(4..8)..n bytes + + if (i_len & 4) { + unsigned int ibp = *(unsigned int *) s; + unsigned int ibb = ibp ^ ib; + ibb = ((ibb + im) ^ ~ibb) & ~im; + if (ibb) { + if (s[0] == c) + return &s[0]; + if (s[1] == c) + return &s[1]; + if (s[2] == c) + return &s[2]; + if (s[3] == c) + return &s[3]; + } + s += 4; + } + // n-(0..3)..n bytes + + switch (i_len & 3) { + case 3: + if (*s++ == c) + return s - 1; + case 2: + if (*s++ == c) + return s - 1; + case 1: + if (*s++ == c) + return s - 1; + case 0: + break; + } + return 0; +} + + +#define MEMCHR(_s,_c) ink_memchr(_s,_c,strlen(_s))?:"" +main() +{ + int i = 0; + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalkdufla asdfj3i", ' ')); + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalkdufla asdfj3i", '3')); + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalkdufla asdfj3i", '\n')); + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalk$uflaE$$dfj3i", '$')); + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalkd#####asdfj3i", '#')); + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalkdufla a^^sdfj3i", '^')); + printf("%d %s\n", i++, MEMCHR("a;ldkfjoiwenalkdufla asd*************fj3i", '*')); +} diff --git a/lib/ts/test_strings.cc b/lib/ts/test_strings.cc new file mode 100644 index 00000000..9c312a15 --- /dev/null +++ b/lib/ts/test_strings.cc @@ -0,0 +1,378 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* This program tests the speeds of several of the string functions, both + * from the inktomi library and from the standard library. + */ + +#include +#include +#include +#include + +char *small = "12345"; +char *small2 = "12345"; +int small_len = 5; +#define SMALL_LEN 5 + +char *medium = "1234512345123451234512345"; +char *medium2 = "1234512345123451234512345"; +int med_len = 25; +#define MED_LEN 25 + +char *large = "111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"; +char *large2 = "111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"; +int large_len = 90; +#define LARGE_LEN 90 + +int i, iresult, cycles; +char *sresult; +char cresult; +clock_t start, stop; + +void *ink_memchr(const void *as, int ac, size_t an); + +#define STRLEN_TEST(_func_,_size_) \ +{ \ + start = clock(); \ + for (i = 0; i < cycles; i++) { \ + iresult = _func_ (_size_); \ + } \ + stop = clock(); \ + printf ("%20s\t%10s\t%1.03g usec/op\n", \ + #_func_, #_size_, ((double)stop-start)/((double)cycles)); \ +} + +#define STRCHR_TEST(_func_,_size_,_chr_) \ +{ \ + start = clock(); \ + for (i = 0; i < cycles; i++) { \ + sresult = _func_ (_size_,_chr_); \ + } \ + stop = clock(); \ + printf ("%20s\t%10s\t%1.03g usec/op\t%s\n", \ + #_func_, #_size_, ((double)stop-start)/((double)cycles), \ + (sresult)? "found" : "not found"); \ +} + +#define JP_MEMCHR_TEST(_func_,_size_,_chr_,_len_) \ +{ \ + start = clock(); \ + for (i = 0; i < cycles; i++) { \ + sresult = (char*) ink_memchr (_size_,_chr_,_len_); \ + } \ + stop = clock(); \ + printf ("%20s\t%10s\t%1.03g usec/op\t%s\n", \ + "jp_memchr", #_size_, ((double)stop-start)/((double)cycles), \ + (sresult)? "found" : "not found"); \ +} + +#define STRCMP_TEST(_func_,_size_,_str_) \ +{ \ + start = clock(); \ + for (i = 0; i < cycles; i++) { \ + iresult = _func_ (_size_,_str_); \ + } \ + stop = clock(); \ + printf ("%20s\t%10s\t%1.03g usec/op\t%s\n", \ + #_func_, #_size_, ((double)stop-start)/((double)cycles), \ + (sresult)? "not matching" : "matching"); \ +} + +#define STRCPY_TEST(_func_,_size_) \ +{ \ + char buf[1024]; \ + start = clock(); \ + for (i = 0; i < cycles; i++) { \ + sresult = _func_ (buf,_size_); \ + } \ + stop = clock(); \ + printf ("%20s\t%10s\t%1.03g usec/op\n", \ + #_func_, #_size_, ((double)stop-start)/((double)cycles)); \ +} + +#define MEMCPY_TEST(_func_,_size_,_len_) \ +{ \ + char buf[1024]; \ + start = clock(); \ + for (i = 0; i < cycles; i++) { \ + sresult = (char*) _func_ (buf,_size_,_len_); \ + } \ + stop = clock(); \ + printf ("%20s\t%10s\t%10s\t%1.03g usec/op\n", \ + #_func_, #_size_, #_len_, ((double)stop-start)/((double)cycles)); \ +} + +/* version from ink_string.h */ +inline char * +ink_strchr(char *s, char c) +{ + while (*s) { + if (*s == c) + return (s); + else + ++s; + } + return (0); +} + +inline char * +ink_memcpy(char *d, char *s, int len) +{ + for (int i = 0; i < len; i++) + d[i] = s[i]; + return d; +} + +/* version using ink_memchr */ +inline char * +jp_strchr(char *s, char c) +{ + return (char *) ink_memchr(s, c, strlen(s)); +} + +void +strlen_tests() +{ + printf("strlen:\n"); + STRLEN_TEST(strlen, small); + STRLEN_TEST(strlen, medium); + STRLEN_TEST(strlen, large); + printf("\n"); +} + +void +strchr_tests() +{ + printf("strchr:\n"); + /* expect to find */ + STRCHR_TEST(strchr, small, '5'); + STRCHR_TEST(ink_strchr, small, '5'); + JP_MEMCHR_TEST(jp_memchr, small, '5', small_len); + STRCHR_TEST(strchr, medium, '5'); + STRCHR_TEST(ink_strchr, medium, '5'); + JP_MEMCHR_TEST(jp_memchr, medium, '5', med_len); + STRCHR_TEST(strchr, large, '5'); + STRCHR_TEST(ink_strchr, large, '5'); + JP_MEMCHR_TEST(jp_memchr, large, '5', large_len); + /* expect NOT to find */ + STRCHR_TEST(strchr, small, 'x'); + STRCHR_TEST(ink_strchr, small, 'x'); + JP_MEMCHR_TEST(jp_memchr, small, 'x', small_len); + STRCHR_TEST(strchr, medium, 'x'); + STRCHR_TEST(ink_strchr, medium, 'x'); + JP_MEMCHR_TEST(jp_memchr, medium, 'x', med_len); + STRCHR_TEST(strchr, large, 'x'); + STRCHR_TEST(ink_strchr, large, 'x'); + JP_MEMCHR_TEST(jp_memchr, large, 'x', large_len); + printf("\n"); +} + +void +strcmp_tests() +{ + printf("\nstrcmp:\n"); + /* expect to match */ + STRCMP_TEST(strcmp, small, small2); + STRCMP_TEST(strcmp, medium, medium2); + STRCMP_TEST(strcmp, large, large2); + /* expect NOT to match */ + STRCMP_TEST(strcmp, small, "1xx"); + STRCMP_TEST(strcmp, medium, "1xx"); + STRCMP_TEST(strcmp, large, "1xx"); + printf("\n"); +} + +void +strcpy_tests() +{ + printf("\nstrcpy:\n"); + STRCPY_TEST(strcpy, small); + STRCPY_TEST(strcpy, medium); + STRCPY_TEST(strcpy, large); + printf("\nmemcpy:\n"); + MEMCPY_TEST(memcpy, small, small_len); + MEMCPY_TEST(memcpy, medium, med_len); + MEMCPY_TEST(memcpy, large, large_len); + MEMCPY_TEST(memcpy, small, SMALL_LEN); + MEMCPY_TEST(memcpy, medium, MED_LEN); + MEMCPY_TEST(memcpy, large, LARGE_LEN); + + MEMCPY_TEST(ink_memcpy, small, small_len); + MEMCPY_TEST(ink_memcpy, medium, med_len); + MEMCPY_TEST(ink_memcpy, large, large_len); + MEMCPY_TEST(ink_memcpy, small, SMALL_LEN); + MEMCPY_TEST(ink_memcpy, medium, MED_LEN); + MEMCPY_TEST(ink_memcpy, large, LARGE_LEN); + printf("\n"); +} + +int +main(int argc, char *argv[]) +{ + if (argc < 2) { + printf("usage: %s [cycles]\n", argv[0]); + exit(0); + } + cycles = atoi(argv[1]); + printf("%20s\t%10s\tspeed\n", "function", "str size"); + printf("--------------------\t----------\t------------------\n"); + + strlen_tests(); + strchr_tests(); + strcmp_tests(); + strcpy_tests(); +} + +// +// fast memchr +// +void * +ink_memchr(const void *as, int ac, size_t an) +{ + unsigned char c = (unsigned char) ac; + unsigned char *s = (unsigned char *) as; + + // initial segment + + int i_len = (int)(((uintptr_t) 8 - (uintptr_t) as) & 7); + + // too short to concern us + + if ((int) an < i_len) { + for (int i = 0; i < (int) an; i++) + if (s[i] == c) + return &s[i]; + return 0; + } + // bytes 0-3 + + switch (i_len & 3) { + case 3: + if (*s++ == c) + return s - 1; + case 2: + if (*s++ == c) + return s - 1; + case 1: + if (*s++ == c) + return s - 1; + case 0: + break; + } + + // bytes 4-8 + + unsigned int ib = c; + ib |= (ib << 8); + ib |= (ib << 16); + unsigned int im = 0x7efefeff; + if (i_len & 4) { + unsigned int ibp = *(unsigned int *) s; + unsigned int ibb = ibp ^ ib; + ibb = ((ibb + im) ^ ~ibb) & ~im; + if (ibb) { + if (s[0] == c) + return &s[0]; + if (s[1] == c) + return &s[1]; + if (s[2] == c) + return &s[2]; + if (s[3] == c) + return &s[3]; + } + s += 4; + } + // next 8x bytes + uint64_t m = 0x7efefefefefefeffLL; + uint64_t b = ((uint64_t) ib); + b |= (b << 32); + uint64_t *p = (uint64_t *) s; + unsigned int n = (((unsigned int) an) - (s - (unsigned char *) as)) >> 3; + uint64_t *end = p + n; + while (p < end) { + uint64_t bp = *p; + uint64_t bb = bp ^ b; + bb = ((bb + m) ^ ~bb) & ~m; + if (bb) { + s = (unsigned char *) p; + if (s[0] == c) + return &s[0]; + if (s[1] == c) + return &s[1]; + if (s[2] == c) + return &s[2]; + if (s[3] == c) + return &s[3]; + if (s[4] == c) + return &s[4]; + if (s[5] == c) + return &s[5]; + if (s[6] == c) + return &s[6]; + if (s[7] == c) + return &s[7]; + } + p++; + } + + // terminal segement + + i_len = an - (((unsigned char *) p) - ((unsigned char *) as)); + s = (unsigned char *) p; + + // n-(4..8)..n bytes + + if (i_len & 4) { + unsigned int ibp = *(unsigned int *) s; + unsigned int ibb = ibp ^ ib; + ibb = ((ibb + im) ^ ~ibb) & ~im; + if (ibb) { + if (s[0] == c) + return &s[0]; + if (s[1] == c) + return &s[1]; + if (s[2] == c) + return &s[2]; + if (s[3] == c) + return &s[3]; + } + s += 4; + } + // n-(0..3)..n bytes + + switch (i_len & 3) { + case 3: + if (*s++ == c) + return s - 1; + case 2: + if (*s++ == c) + return s - 1; + case 1: + if (*s++ == c) + return s - 1; + case 0: + break; + } + return 0; +} diff --git a/lib/tsconfig/BisonHeaderToC++.sed b/lib/tsconfig/BisonHeaderToC++.sed new file mode 100644 index 00000000..768c6ee8 --- /dev/null +++ b/lib/tsconfig/BisonHeaderToC++.sed @@ -0,0 +1,6 @@ +1anamespace ts { namespace config {\ + enum TokenType { +1,/^ *enum/d +/^ *};/a\ +}} // namespace ts::config +/^#endif/,$d diff --git a/lib/tsconfig/Errata.cc b/lib/tsconfig/Errata.cc new file mode 100644 index 00000000..a3035f3a --- /dev/null +++ b/lib/tsconfig/Errata.cc @@ -0,0 +1,297 @@ +/** @file + Errata implementation. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "Errata.h" +# include +# include +# include +# include +# include + +namespace ts { + +/** List of sinks for abandoned erratum. + */ +namespace { + std::deque Sink_List; +} + +std::string const Errata::DEFAULT_GLUE("\n"); +Errata::Message const Errata::NIL_MESSAGE; +Errata::Code Errata::Message::Default_Code = 0; +Errata::Message::SuccessTest const Errata::Message::DEFAULT_SUCCESS_TEST = + &Errata::Message::isCodeZero; +Errata::Message::SuccessTest Errata::Message::Success_Test = + Errata::Message::DEFAULT_SUCCESS_TEST; + +bool +Errata::Message::isCodeZero(Message const& msg) { + return msg.m_code == 0; +} + +void +Errata::Data::push(Message const& msg) { + m_items.push_back(msg); +} + +Errata::Message const& +Errata::Data::top() const { + return m_items.size() ? m_items.back() : NIL_MESSAGE ; +} + +inline Errata::Errata(ImpPtr const& ptr) + : m_data(ptr) { +} + +Errata::Data::~Data() { + if (m_log_on_delete) { + Errata tmp(this); // because client API requires a wrapper. + std::deque::iterator spot, limit; + for ( spot = Sink_List.begin(), limit = Sink_List.end(); + spot != limit; + ++spot + ) { + (**spot)(tmp); + } + tmp.m_data.release(); // don't delete this again. + } +} + +Errata::Errata() { +} + +Errata::Errata(self const& that) + : m_data(that.m_data) { +} + +Errata::Errata(std::string const& text) { + this->push(text); +} + +Errata::Errata(Id id, std::string const& text) { + this->push(id, text); +} + +Errata::~Errata() { +} + +/* This forces the errata to have a data object that only it references. + If we're sharing the data, clone. If there's no data, allocate. + This is used just before a write operation to have copy on write semantics. + */ +Errata::Data* +Errata::pre_write() { + if (m_data) { + if (m_data.useCount() > 1) { + m_data = new Data(*m_data); // clone current data + } + } else { // create new data + m_data = new Data; + } + return m_data.get(); +} + +// Just create an instance if needed. +Errata::Data* +Errata::instance() { + if (!m_data) m_data = new Data; + return m_data.get(); +} + +Errata& +Errata::push(Message const& msg) { + this->pre_write()->push(msg); + return *this; +} + +Errata& +Errata::operator=(self const& that) { + m_data = that.m_data; + return *this; +} + +Errata& +Errata::operator = (Message const& msg) { + // Avoid copy on write in the case where we discard. + if (!m_data || m_data.useCount() > 1) { + this->clear(); + this->push(msg); + } else { + m_data->m_items.clear(); + m_data->push(msg); + } + return *this; +} + +Errata& +Errata::pull(self& that) { + if (that.m_data) { + this->pre_write(); + m_data->m_items.insert( + m_data->m_items.end(), + that.m_data->m_items.begin(), + that.m_data->m_items.end() + ); + that.m_data->m_items.clear(); + } + return *this; +} + +void +Errata::pop() { + if (m_data && m_data->size()) { + this->pre_write()->m_items.pop_front(); + } + return; +} + +void +Errata::clear() { + m_data.reset(0); +} + +/* We want to allow iteration on empty / nil containers because that's very + convenient for clients. We need only return the same value for begin() + and end() and everything works as expected. + + However we need to be a bit more clever for VC 8. It checks for + iterator compatibility, i.e. that the iterators are not + invalidated and that they are for the same container. It appears + that default iterators are not compatible with anything. So we + use static container for the nil data case. + */ +static Errata::Container NIL_CONTAINER; + +Errata::iterator +Errata::begin() { + return m_data ? m_data->m_items.rbegin() : NIL_CONTAINER.rbegin(); +} + +Errata::const_iterator +Errata::begin() const { + return m_data ? static_cast(*m_data).m_items.rbegin() + : static_cast(NIL_CONTAINER).rbegin(); +} + +Errata::iterator +Errata::end() { + return m_data ? m_data->m_items.rend() : NIL_CONTAINER.rend(); +} + +Errata::const_iterator +Errata::end() const { + return m_data ? static_cast(*m_data).m_items.rend() + : static_cast(NIL_CONTAINER).rend(); +} + +void +Errata::registerSink(Sink::Handle const& s) { + Sink_List.push_back(s); +} + +std::ostream& +Errata::write( + std::ostream& out, + int offset, + int indent, + int shift, + char const* lead +) const { + for ( const_iterator spot = this->begin(), limit = this->end(); + spot != limit; + ++spot + ) { + if ((offset + indent) > 0) + out << std::setw(indent + offset) << std::setfill(' ') + << ((indent > 0 && lead) ? lead : " "); + + out << spot->m_id << " [" << spot->m_code << "]: " << spot->m_text + << std::endl + ; + if (spot->getErrata().size()) + spot->getErrata().write(out, offset, indent+shift, shift, lead); + + } + return out; +} + +size_t +Errata::write( + char *buff, + size_t n, + int offset, + int indent, + int shift, + char const* lead +) const { + std::ostringstream out; + std::string text; + this->write(out, offset, indent, shift, lead); + text = out.str(); + memcpy(buff, text.data(), std::min(n, text.size())); + return text.size(); +} + +std::ostream& operator<< (std::ostream& os, Errata const& err) { + return err.write(os, 0, 0, 2, "> "); +} + +# if USING_BOOST + +std::ostream& +errata::format(std::ostream& s, std::string const& fmt, std::string const& glue) const { + return this->format(s, boost::format(fmt), glue); +} + +std::ostream& +errata::format(std::ostream& s, boost::format const& fmt, std::string const& glue) const { + if (_data) { + bool inside = false; + boost::format f(fmt); + f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); + const_iterator spot(this->begin()), limit(this->end()); + while (spot != limit) { + if (inside) s << glue; + s << ( f % spot->_id % spot->_text ); + inside = true; + ++spot; + } + } + return s; +} + +std::string +errata::format(std::string const& fmt, std::string const& glue) const { + return this->format(boost::format(fmt), glue); +} + +std::string +errata::format(boost::format const& fmt, std::string const& glue) const { + std::ostringstream s; + this->format(s, fmt, glue); + return s.str(); +} + +# endif + +} // namespace ts + diff --git a/lib/tsconfig/Errata.h b/lib/tsconfig/Errata.h new file mode 100644 index 00000000..5c1d1443 --- /dev/null +++ b/lib/tsconfig/Errata.h @@ -0,0 +1,945 @@ +# if !defined TS_ERRATA_HEADER +# define TS_ERRATA_HEADER + +/** @file + Stacking error message handling. + + The problem addressed by this library is the ability to pass back + detailed error messages from failures. It is hard to get good + diagnostics because the specific failures and general context are + located in very different stack frames. This library allows local + functions to pass back local messages which can be easily + augmented as the error travels up the stack frame. + + This could be done with exceptions but + - That is more effort to implemention + - Generally more expensive. + + Each message on a stack contains text and a numeric identifier. + The identifier value zero is reserved for messages that are not + errors so that information can be passed back even in the success + case. + + The implementation takes the position that success is fast and + failure is expensive. Therefore it is optimized for the success + path, imposing very little overhead. On the other hand, if an + error occurs and is handled, that is generally so expensive that + optimizations are pointless (although, of course, one should not + be gratuitiously expensive). + + The library also provides the @c Rv ("return value") template to + make returning values and status easier. This template allows a + function to return a value and status pair with minimal changes. + The pair acts like the value type in most situations, while + providing access to the status. + + Each instance of an erratum is a wrapper class that emulates value + semantics (copy on write). This means passing even large message + stacks is inexpensive, involving only a pointer copy and reference + counter increment and decrement. A success value is represented by + an internal @c NULL so it is even cheaper to copy. + + To further ease use, the library has the ability to define @a + sinks. A sink is a function that acts on an erratum when it + becomes unreferenced. The indended use is to send the messages to + an output log. This makes reporting errors to a log from even + deeply nested functions easy while preserving the ability of the + top level logic to control such logging. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include +# include +# include +# include +# include "NumericType.h" +# include "IntrusivePtr.h" + +# if USING_BOOST +# include +# include +# endif + +namespace ts { + +/** Class to hold a stack of error messages (the "errata"). + This is a smart handle class, which wraps the actual data + and can therefore be treated a value type with cheap copy + semantics. Default construction is very cheap. + */ +class Errata { +protected: + /// Implementation class. + struct Data; + /// Handle for implementation class instance. + typedef IntrusivePtr ImpPtr; +public: + typedef Errata self; /// Self reference type. + + /// Message ID. + typedef NumericType Id; + + /* Tag / level / code severity. + This is intended for clients to use to provide additional + classification of a message. A severity code, as for syslog, + is a common use. + + */ + typedef NumericType Code; + struct Message; + + typedef std::deque Container; ///< Storage type for messages. + // We iterate backwards to look like a stack. +// typedef Container::reverse_iterator iterator; ///< Message iteration. + /// Message const iteration. +// typedef Container::const_reverse_iterator const_iterator; + /// Reverse message iteration. +// typedef Container::iterator reverse_iterator; + /// Reverse constant message iteration. +// typedef Container::const_iterator const_reverse_iterator; + + /// Default constructor - empty errata, very fast. + Errata(); + /// Copy constructor, very fast. + Errata ( + self const& that ///< Object to copy + ); + /// Construct from string. + /// Message Id and Code are default. + explicit Errata( + std::string const& text ///< Finalized message text. + ); + /// Construct with @a id and @a text. + /// Code is default. + Errata( + Id id, ///< Message id. + std::string const& text ///< Message text. + ); + /// Construct with @a id, @a code, and @a text. + Errata( + Id id, ///< Message text. + Code code, ///< Message code. + std::string const& text ///< Message text. + ); + /** Construct from a message instance. + This is equivalent to default constructing an @c errata and then + invoking @c push with an argument of @a msg. + */ + Errata( + Message const& msg ///< Message to push + ); + + /// destructor + ~Errata(); + + /// Self assignment. + /// @return A reference to this object. + self& operator = ( + const self& that ///< Source instance. + ); + + /** Assign message. + All other messages are discarded. + @return A reference to this object. + */ + self& operator = ( + Message const& msg ///< Source message. + ); + + /** Push @a text as a message. + The message is constructed from just the @a text. + It becomes the top message. + @return A reference to this object. + */ + self& push(std::string const& text); + /** Push @a text as a message with message @a id. + The message is constructed from @a text and @a id. + It becomes the top message. + @return A reference to this object. + */ + self& push(Id id, std::string const& text); + /** Push @a text as a message with message @a id and @a code. + The message is constructed from @a text and @a id. + It becomes the top message. + @return A reference to this object. + */ + self& push(Id id, Code code, std::string const& text); + /** Push a message. + @a msg becomes the top message. + @return A reference to this object. + */ + self& push(Message const& msg); + + /** Push a nested status. + @a err becomes the top item. + @return A reference to this object. + */ + self& push(self const& err); + + /** Access top message. + @return If the errata is empty, a default constructed message + otherwise the most recent message. + */ + Message const& top() const; + + /** Move messages from @a that to @c this errata. + Messages from @a that are put on the top of the + stack in @c this and removed from @a that. + */ + self& pull(self& that); + + /// Remove last message. + void pop(); + + /// Remove all messages. + void clear(); + + /** Inhibit logging. + @note This only affects @c this as a top level @c errata. + It has no effect on this @c this being logged as a nested + @c errata. + */ + self& doNotLog(); + + friend std::ostream& operator<< (std::ostream&, self const&); + + /// Default glue value (a newline) for text rendering. + static std::string const DEFAULT_GLUE; + + /** Test status. + + Equivalent to @c success but more convenient for use in + control statements. + + @return @c true if no messages or last message has a zero + message ID, @c false otherwise. + */ + operator bool() const; + + /** Test errata for no failure condition. + + Equivalent to @c operator @c bool but easier to invoke. + + @return @c true if no messages or last message has a zero + message ID, @c false otherwise. + */ + bool isOK() const; + + /// Number of messages in the errata. + size_t size() const; + + /* Forward declares. + We have to make our own iterators as the least bad option. The problem + is that we have recursive structures so declaration order is difficult. + We can't use the container iterators here because the element type is + not yet defined. If we define the element type here, it can't contain + an Errata and we have to do funky things to get around that. So we + have our own iterators, which are just shadowing sublclasses of the + container iterators. + */ + class iterator; + class const_iterator; + + /// Reference to top item on the stack. + iterator begin(); + /// Reference to top item on the stack. + const_iterator begin() const; + //! Reference one past bottom item on the stack. + iterator end(); + //! Reference one past bottom item on the stack. + const_iterator end() const; + + // Logging support. + + /** Base class for erratum sink. + When an errata is abandoned, this will be called on it to perform + any client specific logging. It is passed around by handle so that + it doesn't have to support copy semantics (and is not destructed + until application shutdown). Clients can subclass this class in order + to preserve arbitrary data for the sink or retain a handle to the + sink for runtime modifications. + */ + class Sink : public IntrusivePtrCounter { + public: + typedef Sink self; ///< Self reference type. + typedef IntrusivePtr Handle; ///< Handle type. + + /// Handle an abandoned errata. + virtual void operator() (Errata const&) const = 0; + /// Force virtual destructor. + virtual ~Sink() {} + }; + + //! Register a sink for discarded erratum. + static void registerSink(Sink::Handle const& s); + + /// Register a function as a sink. + typedef void (*SinkHandlerFunction)(Errata const&); + + // Wrapper class to support registering functions as sinks. + struct SinkFunctionWrapper : public Sink { + /// Constructor. + SinkFunctionWrapper(SinkHandlerFunction f) : m_f(f) { } + /// Operator to invoke the function. + virtual void operator() (Errata const& e) const { m_f(e); } + SinkHandlerFunction m_f; ///< Client supplied handler. + }; + + /// Register a sink function for abandonded erratum. + static void registerSink(SinkHandlerFunction f) { + registerSink(Sink::Handle(new SinkFunctionWrapper(f))); + } + + /** Simple formatted output. + + Each message is written to a line. All lines are indented with + whitespace @a offset characters. Lines are indented an + additional @a indent. This value is increased by @a shift for + each level of nesting of an @c Errata. if @a lead is not @c + NULL the indentation is overwritten by @a lead if @a indent is + non-zero. It acts as a "continuation" marker for nested + @c Errata. + + */ + std::ostream& write( + std::ostream& out, ///< Output stream. + int offset, ///< Lead white space for every line. + int indent, ///< Additional indention per line for messages. + int shift, ///< Additional @a indent for nested @c Errata. + char const* lead ///< Leading text for nested @c Errata. + ) const; + /// Simple formatted output to fixed sized buffer. + /// @return Number of characters written to @a buffer. + size_t write( + char* buffer, ///< Output buffer. + size_t n, ///< Buffer size. + int offset, ///< Lead white space for every line. + int indent, ///< Additional indention per line for messages. + int shift, ///< Additional @a indent for nested @c Errata. + char const* lead ///< Leading text for nested @c Errata. + ) const; + +# if USING_BOOST + /// Functor type for sink. + typedef boost::function SinkFunctor; + + // Wrapper class to support registering functions as sinks. + struct SinkFunctorWrapper : public Sink { + /// Constructor. + SinkFunctionWrapper(SinkHandlerFunctor f) : m_f(f) { } + /// Operator to invoke the function. + virtual void operator() (Errata const& e) const { m_f(e); } + SinkHandlerFunctor m_f; ///< Client supplied handler. + }; + + /// Register a sink function for abandonded erratum. + static void registerSink(SinkFunctor const& f) { + registerSink(Sink::Handle(new SinkFunctorWrapper(f))); + } + + /// Generate formatted output. + /// For each message in the stack, invoke @c boost::format passing + /// @a fmt as the format string and the message ID and message text as + /// two values. It is not an error to elide either or both. @a glue is + /// sent to the stream @a s between every pair of messages. + /// @return The stream @a s. + std::ostream& format( + std::ostream& s, ///< Output stream + boost::format const& fmt, ///< Format string + std::string const& glue = DEFAULT_GLUE ///< Glue + ) const; + + /// Generate formatted output. + /// A convenience overload so clients do not have to include the Boost.Format headers. + /// @return The formatted output. + /// @see std::ostream& format ( std::ostream& s, boost::format const& fmt, std::string const& glue ). + std::ostream& format( + std::ostream& s, ///< Output stream + std::string const& fmt, ///< Format string + std::string const& glue = DEFAULT_GLUE ///< Glue + ) const; + + /// Generate formatted output. + /// For each message in the stack, invoke @c boost::format passing + /// @a fmt as the format string and the message ID and message text as + /// two values. It is not an error to elide either or both. @a glue is + /// added between every pair of messages. + /// @note This is identical to the stream variant except the output + /// is put in a string instead of a stream. + /// @return The formatted output. + /// @see std::ostream& format ( std::ostream& s, boost::format const& fmt, std::string const& glue ). + std::string format( + boost::format const& fmt, ///< Format string + std::string const& glue = DEFAULT_GLUE ///< Glue + ) const; + + /// Generate formatted output. + /// A convenience overload so clients do not have to include the Boost.Format headers. + /// @return The formatted output. + /// @see std::string format ( boost::format const& fmt, std::string const& glue ). + std::string format( + std::string const& fmt, ///< Format string + std::string const& glue = DEFAULT_GLUE ///< Glue + ) const; +# endif // USING_BOOST + +protected: + /// Construct from implementation pointer. + /// Used internally by nested classes. + Errata(ImpPtr const& ptr); + /// Implementation instance. + ImpPtr m_data; + + /// Return the implementation instance, allocating and unsharing as needed. + Data* pre_write(); + /// Force and return an implementation instance. + /// Does not follow copy on write. + Data* instance(); + + /// Used for returns when no data is present. + static Message const NIL_MESSAGE; + + friend struct Data; + friend class Item; + +}; + +extern std::ostream& operator<< (std::ostream& os, Errata const& stat); + +/// Storage for a single message. +struct Errata::Message { + typedef Message self; ///< Self reference type. + + /// Default constructor. + /// The message has Id = 0, default code, and empty text. + Message(); + + /// Construct from text. + /// Id is zero and Code is default. + Message( + std::string const& text ///< Finalized message text. + ); + + /// Construct with @a id and @a text. + /// Code is default. + Message( + Id id, ///< ID of message in table. + std::string const& text ///< Final text for message. + ); + + /// Construct with @a id, @a code, and @a text. + Message( + Id id, ///< Message Id. + Code code, ///< Message Code. + std::string const& text ///< Final text for message. + ); + + /// Reset to the message to default state. + self& clear(); + + /// Set the message Id. + self& set( + Id id ///< New message Id. + ); + + /// Set the code. + self& set( + Code code ///< New code for message. + ); + + /// Set the text. + self& set( + std::string const& text ///< New message text. + ); + + /// Set the text. + self& set( + char const* text ///< New message text. + ); + + /// Set the errata. + self& set( + Errata const& err ///< Errata to store. + ); + + /// Get the text of the message. + std::string const& text() const; + + /// Get the code. + Code getCode() const; + /// Get the nested status. + /// @return A status object, which is not @c NULL if there is a + /// nested status stored in this item. + Errata getErrata() const; + + /** The default message code. + + This value is used as the Code value for constructing and + clearing messages. It can be changed to control the value + used for empty messages. + */ + static Code Default_Code; + + /// Type for overriding success message test. + typedef bool (*SuccessTest)(Message const& m); + + /** Success message test. + + When a message is tested for being "successful", this + function is called. It may be overridden by a client. + The initial value is @c DEFAULT_SUCCESS_TEST. + + @note This is only called when there are Messages in the + Errata. An empty Errata (@c NULL or empty stack) is always + a success. Only the @c top Message is checked. + + @return @c true if the message indicates success, + @c false otherwise. + */ + static SuccessTest Success_Test; + + /// Indicate success if the message code is zero. + /// @note Used as the default success test. + static bool isCodeZero(Message const& m); + + static SuccessTest const DEFAULT_SUCCESS_TEST; + + Id m_id; ///< Message ID. + Code m_code; ///< Message code. + std::string m_text; ///< Final text. + Errata m_errata; ///< Nested errata. +}; + +/** This is the implementation class for Errata. + + It holds the actual messages and is treated as a passive data + object with nice constructors. + + We implement reference counting semantics by hand for two + reasons. One is that we need to do some specialized things, but + mainly because the client can't see this class so we can't +*/ +struct Errata::Data : public IntrusivePtrCounter { + typedef Data self; ///< Self reference type. + + //! Default constructor. + Data(); + + /// Destructor, to do logging. + ~Data(); + + //! Number of messages. + size_t size() const; + + /// Get the top message on the stack. + Message const& top() const; + + /// Put a message on top of the stack. + void push(Message const& msg); + + /// Log this when it is deleted. + bool m_log_on_delete; + + //! The message stack. + Container m_items; +}; + +/// Forward iterator for @c Messages in an @c Errata. +class Errata::iterator : public Errata::Container::reverse_iterator { +public: + typedef iterator self; ///< Self reference type. + typedef Errata::Container::reverse_iterator super; ///< Parent type. + iterator(); ///< Default constructor. + /// Copy constructor. + iterator( + self const& that ///< Source instance. + ); + /// Construct from super class. + iterator( + super const& that ///< Source instance. + ); + /// Assignment. + self& operator = (self const& that); + /// Assignment from super class. + self& operator = (super const& that); + /// Prefix increment. + self& operator ++ (); + /// Prefix decrement. + self& operator -- (); +}; + +/// Forward constant iterator for @c Messages in an @c Errata. +class Errata::const_iterator : public Errata::Container::const_reverse_iterator { +public: + typedef const_iterator self; ///< Self reference type. + typedef Errata::Container::const_reverse_iterator super; ///< Parent type. + const_iterator(); ///< Default constructor. + /// Copy constructor. + const_iterator( + self const& that ///< Source instance. + ); + const_iterator( + super const& that ///< Source instance. + ); + /// Assignment. + self& operator = (self const& that); + /// Assignment from super class. + self& operator = (super const& that); + /// Prefix increment. + self& operator ++ (); + /// Prefix decrement. + self& operator -- (); +}; + +/** Helper class for @c Rv. + This class enables us to move the implementation of non-templated methods + and members out of the header file for a cleaner API. + */ +struct RvBase { + Errata _errata; ///< The status from the function. + + /** Default constructor. */ + RvBase(); + + /** Construct with specific status. + */ + RvBase ( + Errata const& s ///< Status to copy + ); + + //! Test the return value for success. + bool isOK() const; + + /** Clear any stacked errors. + This is useful during shutdown, to silence irrelevant errors caused + by the shutdown process. + */ + void clear(); + + /// Inhibit logging of the errata. + void doNotLog(); +}; + +/** Return type for returning a value and status (errata). In + general, a method wants to return both a result and a status so + that errors are logged properly. This structure is used to do that + in way that is more usable than just @c std::pair. - Simpler and + shorter typography - Force use of @c errata rather than having to + remember it (and the order) each time - Enable assignment directly + to @a R for ease of use and compatibility so clients can upgrade + asynchronously. + */ +template < typename R > +struct Rv : public RvBase { + typedef Rv self; ///< Standard self reference type. + typedef RvBase super; ///< Standard super class reference type. + typedef R Result; ///< Type of result value. + + Result _result; ///< The actual result of the function. + + /** Default constructor. + The default constructor for @a R is used. + The status is initialized to SUCCESS. + */ + Rv(); + + /** Standard (success) constructor. + + This copies the result and sets the status to SUCCESS. + + @note Not @c explicit so that clients can return just a result + and have it be marked as SUCCESS. + */ + Rv( + Result const& r ///< The function result + ); + + /** Construct from a result and a pre-existing status object. + + @internal No constructor from just an Errata to avoid + potential ambiguity with constructing from result type. + */ + Rv( + Result const& r, ///< The function result + Errata const& s ///< A pre-existing status object + ); + + /** User conversion to the result type. + + This makes it easy to use the function normally or to pass the + result only to other functions without having to extract it by + hand. + */ + operator Result const& () const; + + /** Assignment from result type. + + This allows the result to be assigned to a pre-declared return + value structure. The return value is a reference to the + internal result so that this operator can be chained in other + assignments to instances of result type. This is most commonly + used when the result is computed in to a local variable to be + both returned and stored in a member. + + @code + Rv zret; + int value; + // ... complex computations, result in value + this->m_value = zret = value; + // ... + return zret; + @endcode + + @return A reference to the copy of @a r stored in this object. + */ + Result& operator = ( + Result const& r ///< Result to assign + ) { + _result = r; + return _result; + } + + /** Add the status from another instance to this one. + @return A reference to @c this object. + */ + template < typename U > + self& push( + Rv const& that ///< Source of status messages + ); + + /** Set the result. + + This differs from assignment of the function result in that the + return value is a reference to the @c Rv, not the internal + result. This makes it useful for assigning a result local + variable and then returning. + + @code + Rv zret; + int value; + // ... complex computation, result in value + return zret.set(value); + @endcode + */ + self& set( + Result const& r ///< Result to store + ); + + /** Return the result. + @return A reference to the result value in this object. + */ + Result& result(); + + /** Return the result. + @return A reference to the result value in this object. + */ + Result const& result() const; + + /** Return the status. + @return A reference to the @c errata in this object. + */ + Errata& errata(); + + /** Return the status. + @return A reference to the @c errata in this object. + */ + Errata const& errata() const; + + /// Directly set the errata + self& operator = ( + Errata const& status ///< Errata to assign. + ); + + /// Push a message on to the status. + self& push( + Errata::Message const& msg + ); +}; + +/** Combine a function result and status in to an @c Rv. + This is useful for clients that want to declare the status object + and result independently. + */ +template < typename R > Rv +MakeRv( + R const& r, ///< The function result + Errata const& s ///< The pre-existing status object +) { + return Rv(r, s); +} +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +// Inline methods. +inline Errata::Message::Message() + : m_id(0), m_code(Default_Code) { +} +inline Errata::Message::Message(std::string const& text) + : m_id(0), m_code(Default_Code), m_text(text) { +} +inline Errata::Message::Message(Id id, std::string const& text) + : m_id(id), m_code(Default_Code), m_text(text) { +} +inline Errata::Message::Message(Id id, Code code, std::string const& text) + : m_id(id), m_code(code), m_text(text) { +} +inline Errata::Message& Errata::Message::clear() { + m_id = 0; + m_code = Default_Code; + m_text.erase(); + m_errata.clear(); + return *this; +} + +inline std::string const& Errata::Message::text() const { return m_text; } +inline Errata::Code Errata::Message::getCode() const { return m_code; } +inline Errata Errata::Message::getErrata() const { return m_errata; } + +inline Errata::Message& Errata::Message::set(Id id) { + m_id = id; + return *this; +} +inline Errata::Message& Errata::Message::set(Code code) { + m_code = code; + return *this; +} +inline Errata::Message& Errata::Message::set(std::string const& text) { + m_text = text; + return *this; +} +inline Errata::Message& Errata::Message::set(char const* text) { + m_text = text; + return *this; +} +inline Errata::Message& Errata::Message::set(Errata const& err) { + m_errata = err; + m_errata.doNotLog(); + return *this; +} + +inline Errata::Errata(Id id, Code code, std::string const& text) { + this->push(Message(id, code, text)); +} +inline Errata::Errata(Message const& msg) { + this->push(msg); +} + +inline Errata::operator bool() const { return this->isOK(); } + +inline size_t Errata::size() const { + return m_data ? m_data->m_items.size() : 0; +} + +inline bool Errata::isOK() const { + return 0 == m_data + || 0 == m_data->size() + || Message::Success_Test(this->top()) + ; +} + +inline Errata& +Errata::push(std::string const& text) { + this->push(Message(text)); + return *this; +} + +inline Errata& +Errata::push(Id id, std::string const& text) { + this->push(Message(id, text)); + return *this; +} + +inline Errata& +Errata::push(Id id, Code code, std::string const& text) { + this->push(Message(id, code, text)); + return *this; +} + +inline Errata::Message const& +Errata::top() const { + return m_data ? m_data->top() : NIL_MESSAGE; +} +inline Errata& Errata::doNotLog() { + this->instance()->m_log_on_delete = false; + return *this; +} + +inline Errata::Data::Data() : m_log_on_delete(true) {} +inline size_t Errata::Data::size() const { return m_items.size(); } + +inline Errata::iterator::iterator() { } +inline Errata::iterator::iterator(self const& that) : super(that) { } +inline Errata::iterator::iterator(super const& that) : super(that) { } +inline Errata::iterator& Errata::iterator::operator = (self const& that) { this->super::operator = (that); return *this; } +inline Errata::iterator& Errata::iterator::operator = (super const& that) { this->super::operator = (that); return *this; } +inline Errata::iterator& Errata::iterator::operator ++ () { this->super::operator ++ (); return *this; } +inline Errata::iterator& Errata::iterator::operator -- () { this->super::operator -- (); return *this; } + +inline Errata::const_iterator::const_iterator() { } +inline Errata::const_iterator::const_iterator(self const& that) : super(that) { } +inline Errata::const_iterator::const_iterator(super const& that) : super(that) { } +inline Errata::const_iterator& Errata::const_iterator::operator = (self const& that) { super::operator = (that); return *this; } +inline Errata::const_iterator& Errata::const_iterator::operator = (super const& that) { super::operator = (that); return *this; } +inline Errata::const_iterator& Errata::const_iterator::operator ++ () { this->super::operator ++ (); return *this; } +inline Errata::const_iterator& Errata::const_iterator::operator -- () { this->super::operator -- (); return *this; } + +inline RvBase::RvBase() { } +inline RvBase::RvBase(Errata const& errata) : _errata(errata) { } +inline bool RvBase::isOK() const { return _errata; } +inline void RvBase::clear() { _errata.clear(); } +inline void RvBase::doNotLog() { _errata.doNotLog(); } + +template < typename T > Rv::Rv() { } +template < typename T > Rv::Rv(Result const& r) : _result(r) { } +template < typename T > Rv::Rv(Result const& r, Errata const& errata) + : super(errata) + , _result(r) { +} +template < typename T > Rv::operator Result const&() const { + return _result; +} +template < typename T > T const& Rv::result() const { return _result; } +template < typename T > T& Rv::result() { return _result; } +template < typename T > Errata const& Rv::errata() const { return _errata; } +template < typename T > Errata& Rv::errata() { return _errata; } +template < typename T > Rv& +Rv::set(Result const& r) { + _result = r; + return *this; +} +template < typename T > Rv& +Rv::operator = (Errata const& errata) { + _errata = errata; + return *this; +} +template < typename T > Rv& +Rv::push(Errata::Message const& msg) { + _errata.push(msg); + return *this; +} +template < typename T > template < typename U > Rv& +Rv::push(Rv const& that) { + _errata.push(that.errata()); + return *this; +} +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +} // namespace ts + +# endif // TS_ERRATA_HEADER diff --git a/lib/tsconfig/IntrusivePtr.h b/lib/tsconfig/IntrusivePtr.h new file mode 100644 index 00000000..937fc1d9 --- /dev/null +++ b/lib/tsconfig/IntrusivePtr.h @@ -0,0 +1,609 @@ +# if !defined(TS_INTRUSIVE_PTR_HEADER) +# define TS_INTRUSIVE_PTR_HEADER + +/** @file + + This is a simple shared pointer class for restricted use. It is not a + completely general class. The most significant missing feature is the + lack of thread safety. For its intended use, this is acceptable and + provides a performance improvement. However, it does restrict how the + class may be used. + + This style of shared pointer also requires explicit support from the + target class, which must provide an internal reference counter. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include +# include +# include + +namespace ts { + +class IntrusivePtrCounter; + +/** This class exists solely to be declared a friend of @c IntrusivePtrCounter. + + @internal This is done because we can't declare the template a + friend, so rather than burden the client with the declaration we + do it here. It provides a single method that allows the smart pointer + to get access to the protected reference count. + + */ +class IntrusivePtrBase { +public: + /// Type used for reference counter. + typedef long Counter; +protected: + Counter* getCounter( + IntrusivePtrCounter* c ///< Cast object with reference counter. + ) const; +}; +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +/** Reference counter mixin. + + To add support for @c IntrusivePtr to class @a T, it + should inherit from @c IntrusivePtrCounter in order to + + - provide a reference count member + - force the reference count to initialize to zero + - define the add and release global functions required by @c IntrusivePtr + + In general this class should be inherited publicly. This will + provide methods which mimic the @c Boost.shared_ptr interface ( @c + unique() , @c use_count() ). + + If this class is not inherited publically or the destructor is + non-public then the host class (@a T) must declare this class ( @c + reference_counter ) as a friend. + + @internal Due to changes in the C++ standard and design decisions + in gcc, it is no longer possible to declare a template parameter + as a friend class. (Basically, you can't use a typedef in a + friend declaration and gcc treats template parameters as + typedefs). + + @note You can use this with insulated (by name only) classes. The + important thing is to make sure that any such class that uses @c + IntrusivePtr has all of its constructors and destructors declared + in the header and defined in the implementation translation + unit. If the compiler generates any of those, it will not compile + due to missing functions or methods + + */ +class IntrusivePtrCounter { + friend class IntrusivePtrBase; +public: + /** Copy constructor. + + @internal We have to define this to explicitly _not_ copy the + reference count. Otherwise any client that uses a default copy + constructor will _copy the ref count into the new object_. That + way lies madness. + */ + + IntrusivePtrCounter( + IntrusivePtrCounter const& ///< Source object. + ); + + /** Assignment operator. + + @internal We need this for the same reason as the copy + constructor. The reference counter must not participate in + assignment. + */ + IntrusivePtrCounter& operator = ( + IntrusivePtrCounter const& + ); + +protected: + IntrusivePtrBase::Counter m_intrusive_pointer_reference_count; + /// Default constructor (0 init counter). + /// @internal Only subclasses can access this. + IntrusivePtrCounter(); +}; +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +/** Shared pointer. + + This is a reference counted smart pointer. A single object is jointly + ownded by a set of pointers. When the last of the pointers is destructed + the target object is also destructed. + + The smart pointer actions can be changed through class specific policy + by specializing the @c IntrusivePtrPolicy template class. +*/ +template < typename T > +class IntrusivePtr : private IntrusivePtrBase { +private: /* don't pollute client with these typedefs */ + typedef IntrusivePtrBase super; ///< Parent type. + typedef IntrusivePtr self; ///< Self reference type. + +public: + /// Promote type for reference counter. + typedef super::Counter Counter; + + /// Default constructor (0 initialized). + IntrusivePtr(); + /// Construct from instance. + /// The instance becomes referenced and owned by the pointer. + IntrusivePtr(T* obj); + /// Destructor. + ~IntrusivePtr(); + + /// Copy constructor. + IntrusivePtr(const self& src); + /// Self assignement. + self& operator = (const self& src); + /** Assign from instance. + The instance becomes referenced and owned by the pointer. + The reference to the current object is dropped. + */ + self& operator = ( + T* obj ///< Target instance. + ); + + /** Assign from instance. + The instance becomes referenced and owned by the pointer. + The reference to the current object is dropped. + @note A synonym for @c operator= for compatibility. + */ + self& assign ( + T* obj ///< Target instance. + ); + + /** Assign from instance. + The instance becomes referenced and owned by the pointer. + The reference to the current object is dropped. + */ + void reset(T* obj); + /** Clear reference without cleanup. + + This unsets this smart pointer and decrements the reference + count, but does @b not perform any finalization on the + target object. This can easily lead to memory leaks and + in some sense vitiates the point of this class, but it is + occasionally the right thing to do. Use with caution. + + @return @c true if there are no references upon return, + @c false if the reference count is not zero. + */ + bool release(); + + /// Test if the pointer is zero (@c NULL). + bool isNull() const; + + /// Member dereference. + T* operator -> () const; + /// Dereference. + T& operator * () const; + /// Access raw pointer. + T* get() const; + + /** User conversion to raw pointer. + + @internal allow implicit conversion to the underlying + pointer. This allows for the form "if (handle)" and is not + particularly dangerous (as it would be for a scope_ptr or + shared_ptr) because the counter is carried with the object and + so can't get lost or duplicated. + + */ + operator T* () const; + + /** Cross type construction. + This succeeds if an @a X* can be implicitly converted to a @a T*. + */ + template < + typename X ///< Foreign pointer type. + > IntrusivePtr( + IntrusivePtr const& that ///< Foreign pointer. + ); + + /** Cross type assignment. + This succeeds if an @a X* can be implicitily converted to a @a T*. + */ + template < + typename X ///< Foreign pointer type. + > self& operator = ( + IntrusivePtr const& that ///< Foreign pointer. + ); + + /// Check for multiple references. + /// @return @c true if more than one smart pointer references the object, + /// @c false otherwise. + bool isShared() const; + /// Check for a single reference (@c shared_ptr compatibility) + /// @return @c true if this object is not shared. + bool unique() const; + /// Reference count. + /// @return Number of references. + Counter useCount() const; +private: + T* m_obj; ///< Pointer to object. + + /// Reference @a obj. + void set( + T* obj ///< Target object. + ); + /// Drop the current reference. + void unset(); + + /// Get a pointer to the reference counter of the target object. + Counter* getCounter() const; +}; + +/** Pointer dynamic cast. + This allows a smart pointer to be cast from one type to another. + It must be used when the types do not implicitly convert (generally + a downcast). + + @code + class A { ... }; + class B : public A { ... }; + IntrusivePtr really_b(new B); + InstruivePtr the_b; + the_b = dynamic_ptr_cast(really_b); + @endcode +*/ +template < + typename T, ///< Target type. + typename X ///< Source type. +> IntrusivePtr dynamic_ptr_cast( + IntrusivePtr const& src ///< Source pointer. +) { + return IntrusivePtr(dynamic_cast(src.get())); +} + +/** Pointer cast. + This allows a smart pointer to be cast from one type to another. + It must be used when the types do not implicitly convert (generally + a downcast). This uses @c static_cast and so performs only compile + time checks. + + @code + class A { ... }; + class B : public A { ... }; + IntrusivePtr really_b(new B); + IntrusivePtr the_b; + the_b = ptr_cast(really_b); + @endcode +*/ +template < + typename T, ///< Target type. + typename X ///< Source type. +> IntrusivePtr ptr_cast( + IntrusivePtr const& src ///< Source pointer. +) { + return IntrusivePtr(static_cast(src.get())); +} +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +/** Default policy class for intrusive pointers. + + This allows per type policy, although not per target instance. + Clients can override policy by specializing this class for the + target type. + + @code + template <> IntrusivePtrPolicy + : IntrusivePtrDefaultPolicy { + ... Redefinition of methods and nested types ... + }; + @endcode + + The inherited class will provide the default definitions so you can + override only what is different. Although this can be omitted if you + override everything, it is more robust for maintenance to inherit + anyway. +*/ + +template +class IntrusivePtrPolicy { +public: + /// Called when the pointer is dereferenced. + /// Default is empty (no action). + static void dereferenceCheck( + T* ///< Target object. + ); + + /** Perform clean up on a target object that is no longer referenced. + + Default is calling @c delete. Any specialization that overrides this + @b must clean up the object. The primary use of this is to perform + a clean up other than @c delete. + + @note When this is called, the target object reference count + is zero. If it is necessary to pass a smart pointer to the + target object, it will be necessary to call + @c IntrusivePtr::release to drop the reference without + another finalization. Further care must be taken that none of + the called logic keeps a copy of the smart pointer. Use with + caution. + */ + static void finalize( + T* t ///< Target object. + ); + /// Strict weak order for STL containers. + class Order + : public std::binary_function< IntrusivePtr, IntrusivePtr, bool> { + public: + /// Default constructor. + Order() { + } + /// Compare by raw pointer. + bool operator() ( + IntrusivePtr const& lhs, ///< Left hand operand. + IntrusivePtr const& rhs ///< Right hand operand. + ) const; + }; +}; + +struct IntrusivePtrDefaultPolicyTag {}; +typedef IntrusivePtrPolicy IntrusivePtrDefaultPolicy; +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +/* Inline Methods */ +inline IntrusivePtrCounter::IntrusivePtrCounter() + : m_intrusive_pointer_reference_count(0) { +} + +inline IntrusivePtrCounter::IntrusivePtrCounter(IntrusivePtrCounter const&) + : m_intrusive_pointer_reference_count(0) { +} + +inline IntrusivePtrCounter& +IntrusivePtrCounter::operator = (IntrusivePtrCounter const&) { + return *this; +} + +inline IntrusivePtrBase::Counter* +IntrusivePtrBase::getCounter(IntrusivePtrCounter* c) const { + return &(c->m_intrusive_pointer_reference_count); +} +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +template < typename T > void +IntrusivePtrPolicy::dereferenceCheck(T*) { +} + +template < typename T > void +IntrusivePtrPolicy::finalize(T* obj) { + delete obj; +} + +template < typename T > bool +IntrusivePtrPolicy::Order::operator()( + IntrusivePtr const& lhs, + IntrusivePtr const& rhs +) const { + return lhs.get() < rhs.get(); +} +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +template < typename T > +IntrusivePtr::IntrusivePtr() + : m_obj(0) { +} + +template < typename T > +IntrusivePtr::IntrusivePtr(T* obj) { + this->set(obj); +} + +template < typename T > +IntrusivePtr::~IntrusivePtr() { + this->unset(); +} + +template < typename T > +IntrusivePtr::IntrusivePtr(const self& that) { + this->set(that.m_obj); +} + +template < typename T > +template < typename X > +IntrusivePtr::IntrusivePtr( + IntrusivePtr const& that ///< Foreign pointer. +) : super(that.get()) { +} + +template < typename T > IntrusivePtr& +IntrusivePtr::operator = (const self& that) { + this->reset(that.m_obj); + return *this; +} + +template < typename T > +template < typename X > +IntrusivePtr& +IntrusivePtr::operator = ( + IntrusivePtr const& that ///< Foreign pointer. +) { + this->reset(that.get()); + return *this; +} + +template < typename T > IntrusivePtr& +IntrusivePtr::operator = (T* obj) { + this->reset(obj); + return *this; +} + +template < typename T > IntrusivePtr& +IntrusivePtr::assign (T* obj) { + return *this = obj; +} + +template < typename T > T* +IntrusivePtr::operator -> () const { + IntrusivePtrPolicy::dereferenceCheck(m_obj); + return m_obj; +} + +template < typename T > T& +IntrusivePtr::operator * () const { + IntrusivePtrPolicy::dereferenceCheck(m_obj); + return *m_obj; +} + +template < typename T > T* +IntrusivePtr::get() const { + IntrusivePtrPolicy::dereferenceCheck(m_obj); + return m_obj; +} + +template < typename T > typename IntrusivePtr::Counter* +IntrusivePtr::getCounter() const { + return super::getCounter(static_cast(m_obj)); +} + +/* The Set/Unset methods are the basic implementation of our + * reference counting. The Reset method is the standard way + * of invoking the pair, although splitting them allows some + * additional efficiency in certain situations. + */ + +/* set and unset are two half operations that don't do checks. + It is the callers responsibility to do that. +*/ + +template < typename T > void +IntrusivePtr::unset() { + if (0 != m_obj) { + /* magic: our target is required to inherit from IntrusivePtrCounter, + * which provides a protected counter variable and access via our + * super class. We call the super class method to get a raw pointer + * to the counter variable. + */ + Counter* cp = this->getCounter(); + + /* If you hit this assert you've got a cycle of objects that + reference each other. A delete in the cycle will eventually + result in one of the objects getting deleted twice, which is + what this assert indicates. + */ + assert(*cp); + + if (0 == --*cp) { + IntrusivePtrPolicy::finalize(m_obj); + } + m_obj = 0; + } +} + +template < typename T > void +IntrusivePtr::set(T* obj) { + m_obj = obj; /* update to new object */ + if (0 != m_obj) /* if a real object, bump the ref count */ + ++(*(this->getCounter())); +} + +template < typename T > void +IntrusivePtr::reset(T* obj) { + if (obj != m_obj) { + this->unset(); + this->set(obj); + } +} + +template < typename T > bool +IntrusivePtr::release() { + bool zret = true; + if (m_obj) { + Counter* cp = this->getCounter(); + zret = *cp <= 1; + // If the client is using this method, they're doing something funky + // so be extra careful with the reference count. + if (*cp > 0) --*cp; + m_obj = 0; + } + return zret; +} + +/* Simple method to check for invalid pointer */ +template < typename T > bool +IntrusivePtr::isNull() const { + return 0 == m_obj; +} + +/* Pointer comparison */ +template < typename T > bool +operator == (IntrusivePtr const& lhs, IntrusivePtr const& rhs) { + return lhs.get() == rhs.get(); +} + +template < typename T > bool +operator != (IntrusivePtr const& lhs, IntrusivePtr const& rhs) { + return lhs.get() != rhs.get(); +} + +template < typename T > bool +operator < (IntrusivePtr const& lhs, IntrusivePtr const& rhs) { + return lhs.get() < rhs.get(); +} + +template < typename T > bool +operator == (IntrusivePtr const& lhs, int rhs) { + assert(0 == rhs); + return lhs.get() == 0; +} + +template < typename T > bool +operator == (int lhs, IntrusivePtr const& rhs) { + assert(0 == lhs); + return rhs.get() == 0; +} + +template < typename T > bool +operator != (int lhs, IntrusivePtr const& rhs) { + return !(lhs == rhs); +} + +template < typename T > bool +operator != (IntrusivePtr const& lhs, int rhs) { + return !(lhs == rhs); +} + +template < typename T > +IntrusivePtr::operator T* () const { + return m_obj; +} + +template < typename T> bool +IntrusivePtr::isShared() const { + return m_obj && *(this->getCounter()) > 1; +} + +template < typename T> bool +IntrusivePtr::unique() const { + return 0 == m_obj || *(this->getCounter()) <= 1; +} + +template < typename T> typename IntrusivePtr::Counter +IntrusivePtr::useCount() const { + return m_obj ? *(this->getCounter()) : 0; +} +/* ----------------------------------------------------------------------- */ +/* ----------------------------------------------------------------------- */ +} // namespace ats +/* ----------------------------------------------------------------------- */ +# endif // TS_INTRUSIVE_PTR_HEADER diff --git a/lib/tsconfig/Makefile.am b/lib/tsconfig/Makefile.am new file mode 100644 index 00000000..0bb814ae --- /dev/null +++ b/lib/tsconfig/Makefile.am @@ -0,0 +1,55 @@ +# Makefile.am for TS Config module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +lib_LTLIBRARIES = libtsconfig.la +noinst_PROGRAMS = test-tsconfig + +AM_YFLAGS = -d -p tsconfig + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib + + +BUILT_SOURCES = \ + TsConfigGrammar.c TsConfigGrammar.h TsConfigGrammar.hpp \ + TsConfigSyntax.c + +CLEANFILES = $(BUILT_SOURCES) + +libtsconfig_la_SOURCES = \ + TsConfigGrammar.y \ + TsConfigSyntax.l \ + Errata.cc \ + Errata.h \ + TsErrataUtil.cc \ + TsBuffer.h \ + NumericType.h \ + IntrusivePtr.h \ + TsBuilder.cc \ + TsBuilder.h \ + TsValue.cc \ + TsValue.h + +test_tsconfig_SOURCES = test-tsconfig.cc + +test_tsconfig_LDADD = libtsconfig.la + +# Strip to just the enum in the ts::config namespace so we can use +# it more easily in C++. +TsConfigGrammar.hpp: TsConfigGrammar.h + $(SED) -f BisonHeaderToC++.sed $< > $@ \ No newline at end of file diff --git a/lib/tsconfig/Makefile.in b/lib/tsconfig/Makefile.in new file mode 100644 index 00000000..dc4cd202 --- /dev/null +++ b/lib/tsconfig/Makefile.in @@ -0,0 +1,843 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for TS Config module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = test-tsconfig$(EXEEXT) +subdir = lib/tsconfig +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + TsConfigGrammar.c TsConfigGrammar.h TsConfigSyntax.c +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libtsconfig_la_LIBADD = +am_libtsconfig_la_OBJECTS = TsConfigGrammar.lo TsConfigSyntax.lo \ + Errata.lo TsErrataUtil.lo TsBuilder.lo TsValue.lo +libtsconfig_la_OBJECTS = $(am_libtsconfig_la_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am_test_tsconfig_OBJECTS = test-tsconfig.$(OBJEXT) +test_tsconfig_OBJECTS = $(am_test_tsconfig_OBJECTS) +test_tsconfig_DEPENDENCIES = libtsconfig.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) +LTLEXCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(LEX) $(LFLAGS) $(AM_LFLAGS) +YLWRAP = $(top_srcdir)/build/aux/ylwrap +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +LTYACCCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(YACC) $(YFLAGS) $(AM_YFLAGS) +SOURCES = $(libtsconfig_la_SOURCES) $(test_tsconfig_SOURCES) +DIST_SOURCES = $(libtsconfig_la_SOURCES) $(test_tsconfig_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +lib_LTLIBRARIES = libtsconfig.la +AM_YFLAGS = -d -p tsconfig +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib + +BUILT_SOURCES = \ + TsConfigGrammar.c TsConfigGrammar.h TsConfigGrammar.hpp \ + TsConfigSyntax.c + +CLEANFILES = $(BUILT_SOURCES) +libtsconfig_la_SOURCES = \ + TsConfigGrammar.y \ + TsConfigSyntax.l \ + Errata.cc \ + Errata.h \ + TsErrataUtil.cc \ + TsBuffer.h \ + NumericType.h \ + IntrusivePtr.h \ + TsBuilder.cc \ + TsBuilder.h \ + TsValue.cc \ + TsValue.h + +test_tsconfig_SOURCES = test-tsconfig.cc +test_tsconfig_LDADD = libtsconfig.la +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .cc .l .lo .o .obj .y +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/tsconfig/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/tsconfig/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +TsConfigGrammar.h: TsConfigGrammar.c + @if test ! -f $@; then \ + rm -f TsConfigGrammar.c; \ + $(MAKE) $(AM_MAKEFLAGS) TsConfigGrammar.c; \ + else :; fi +libtsconfig.la: $(libtsconfig_la_OBJECTS) $(libtsconfig_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libtsconfig_la_OBJECTS) $(libtsconfig_la_LIBADD) $(LIBS) + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test-tsconfig$(EXEEXT): $(test_tsconfig_OBJECTS) $(test_tsconfig_DEPENDENCIES) + @rm -f test-tsconfig$(EXEEXT) + $(CXXLINK) $(test_tsconfig_OBJECTS) $(test_tsconfig_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Errata.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TsBuilder.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TsConfigGrammar.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TsConfigSyntax.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TsErrataUtil.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TsValue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-tsconfig.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +.l.c: + $(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) + +.y.c: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f TsConfigGrammar.c + -rm -f TsConfigGrammar.h + -rm -f TsConfigSyntax.c + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: all check install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Strip to just the enum in the ts::config namespace so we can use +# it more easily in C++. +TsConfigGrammar.hpp: TsConfigGrammar.h + $(SED) -f BisonHeaderToC++.sed $< > $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/tsconfig/NumericType.h b/lib/tsconfig/NumericType.h new file mode 100644 index 00000000..6216187f --- /dev/null +++ b/lib/tsconfig/NumericType.h @@ -0,0 +1,182 @@ +# if !defined(TS_NUMERIC_TYPE_HEADER) +# define TS_NUMERIC_TYPE_HEADER + +/** @file + + Create a distinct type from a builtin numeric type. + + This template class converts a basic type into a class, so that + instances of the class act like the basic type in normal use but + as a distinct type when evaluating overloads. This is very handy + when one has several distinct value types that map to the same + basic type. That means we can have overloads based on the type + even though the underlying basic type is the same. The second + template argument, X, is used only for distinguishing + instantiations of the template with the same base type. It doesn't + have to exist. One can declare an instantiation like + + @code + typedef NumericType some_random_type; + @endcode + + It is not necessary to ever mention some_random_tag_name + again. All we need is the entry in the symbol table. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include + +namespace ts { + +// Forward declare. +template < typename T, typename X > class NumericType; + +/// @cond NOT_DOCUMENTED +/** Support template for resolving operator ambiguity. + + Not for client use. + + @internal This resolves a problem when @a T is not @c int. In + that case, because raw numbers are @c int the overloading rule + changes creates an ambiguity - gcc won't distinguish between class + methods and builtins because @c NumericType has a user conversion + to @a T. So signature (NumericType, T) and (T, + int) are considered equivalent. This defines the @c int + operators explicitly. We inherit it so if @a T is @c int, these + are silently overridden. + + @internal Note that we don't have to provide an actual implementation + for these operators. Funky, isn't it? +*/ +template < + typename T, ///< Base numeric type. + typename X ///< Distinguishing tag type. +> class NumericTypeIntOperators { +public: + NumericType& operator += ( int t ); + NumericType& operator -= ( int t ); + + // Must have const and non-const versions. + NumericType operator + ( int t ); + NumericType operator - ( int t ); + NumericType operator + ( int t ) const; + NumericType operator - ( int t ) const; +}; + +template < typename T, typename X > NumericType +operator + ( int t, NumericTypeIntOperators const& ); + +template < typename T, typename X > NumericType +operator - ( int t, NumericTypeIntOperators const& ); + +/// @endcond + +/** Numeric type template. + + @internal One issue is that this is not a POD and so doesn't work + with @c printf. I will need to investigate what that would take. + */ +template < + typename T, ///< Base numeric type. + typename X ///< Distinguishing tag type. +> class NumericType : public NumericTypeIntOperators { +public: + typedef T raw_type; //!< Base builtin type. + typedef NumericType self; //!< Self reference type. + + /// @cond NOT_DOCUMENTED + // Need to import these to avoid compiler problems. + using NumericTypeIntOperators::operator +=; + using NumericTypeIntOperators::operator -=; + using NumericTypeIntOperators::operator +; + using NumericTypeIntOperators::operator -; + /// @endcond + + /// Default constructor, uninitialized. + NumericType(); + //! Construct from implementation type. + NumericType( + raw_type const t ///< Initialized value. + ); + //! Assignment from implementation type. + NumericType & operator = (raw_type const t); + //! Self assignment. + NumericType & operator = (self const& that); + + /// User conversion to implementation type. + /// @internal If we have just a single const method conversion to a copy + /// of the @c raw_type then the stream operators don't work. Only a CR + /// conversion operator satisifies the argument matching. + operator raw_type const& () const { return _t; } + /// User conversion to implementation type. + operator raw_type& () { return _t; } + /// Explicit conversion to host type + raw_type raw() const { return _t; } + + // User conversions to raw type provide the standard comparison operators. + self& operator += ( self const& that ); + self& operator -= ( self const& that ); + + self& operator += ( raw_type t ); + self& operator -= ( raw_type t ); + + self operator + ( self const& that ); + self operator - ( self const& that ); + + self operator + ( raw_type t ); + self operator - ( raw_type t ); + + self& operator ++(); + self operator ++(int); + self& operator --(); + self operator --(int); + +private: + raw_type _t; +}; + +// Method definitions. +template < typename T, typename X > NumericType::NumericType() { } +template < typename T, typename X > NumericType::NumericType(raw_type const t) : _t(t) { } +template < typename T, typename X > NumericType& NumericType::operator = (raw_type const t) { _t = t; return *this; } +template < typename T, typename X > NumericType& NumericType::operator = (self const& that) { _t = that._t; return *this; } + +template < typename T, typename X > NumericType& NumericType::operator += ( self const& that ) { _t += that._t; return *this; } +template < typename T, typename X > NumericType& NumericType::operator -= ( self const& that ) { _t -= that._t; return *this; } +template < typename T, typename X > NumericType NumericType::operator + ( self const& that ) { return self(_t + that._t); } +template < typename T, typename X > NumericType NumericType::operator - ( self const& that ) { return self(_t - that._t); } + +template < typename T, typename X > NumericType& NumericType::operator += ( raw_type t ) { _t += t; return *this; } +template < typename T, typename X > NumericType& NumericType::operator -= ( raw_type t ) { _t -= t; return *this; } +template < typename T, typename X > NumericType NumericType::operator + ( raw_type t ) { return self(_t + t); } +template < typename T, typename X > NumericType NumericType::operator - ( raw_type t ) { return self(_t - t); } + +template < typename T, typename X > NumericType& NumericType::operator ++() { ++_t; return *this; } +template < typename T, typename X > NumericType& NumericType::operator --() { --_t; return *this; } +template < typename T, typename X > NumericType NumericType::operator ++(int) { self tmp(*this); ++_t; return tmp; } +template < typename T, typename X > NumericType NumericType::operator --(int) { self tmp(*this); --_t; return tmp; } + +template < typename T, typename X > NumericType operator + ( T const& lhs, NumericType const& rhs ) { return rhs + lhs; } +template < typename T, typename X > NumericType operator - ( T const& lhs, NumericType const& rhs ) { return NumericType(lhs - rhs.raw()); } + +/* ----------------------------------------------------------------------- */ +} /* end namespace ts */ +/* ----------------------------------------------------------------------- */ +# endif // TS_NUMERIC_TYPE_HEADER diff --git a/lib/tsconfig/TsBuffer.h b/lib/tsconfig/TsBuffer.h new file mode 100644 index 00000000..f3e39aa1 --- /dev/null +++ b/lib/tsconfig/TsBuffer.h @@ -0,0 +1,200 @@ +# if ! defined TS_BUFFER_HEADER +# define TS_BUFFER_HEADER + +/** @file + Definitions for a buffer type, to carry a reference to a chunk of memory. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# if defined _MSC_VER +# include +# else +# include +# endif + +// For memcmp() +# include + +/// Apache Traffic Server commons. +namespace ts { + struct ConstBuffer; + /** A chunk of writable memory. + A convenience class because we pass this kind of pair frequently. + */ + struct Buffer { + typedef Buffer self; ///< Self reference type. + + char * _ptr; ///< Pointer to base of memory chunk. + size_t _size; ///< Size of memory chunk. + + /// Default constructor. + /// Elements are in uninitialized state. + Buffer(); + + /// Construct from pointer and size. + Buffer( + char* ptr, ///< Pointer to buffer. + size_t n ///< Size of buffer. + ); + + /** Equality. + @return @c true if the @c Buffer instances are identical, + @c false otherwise. + */ + bool operator == (self const& that) const; + /** Inequality. + @return @c true if the @c Buffer instances are different, + @c false otherwise. + */ + bool operator != (self const& that) const; + /** Equality for a constant buffer. + @return @c true if @a that contains identical contents. + @c false otherwise. + */ + bool operator == (ConstBuffer const& that) const; + /** Inequality. + @return @c true if the instances have different content, + @c false if they are identical. + */ + bool operator != (ConstBuffer const& that) const; + + /// @name Accessors. + //@{ + /// Get the data in the buffer. + char* data() const; + /// Get the size of the buffer. + size_t size() const; + //@} + + /// Set the chunk. + /// Any previous values are discarded. + /// @return @c this object. + self& set( + char* ptr, ///< Buffer address. + size_t n ///< Buffer size. + ); + /// Reset to empty. + self& reset(); + }; + + /** A chunk of read only memory. + A convenience class because we pass this kind of pair frequently. + */ + struct ConstBuffer { + typedef ConstBuffer self; ///< Self reference type. + + char const * _ptr; ///< Pointer to base of memory chunk. + size_t _size; ///< Size of memory chunk. + + /// Default constructor. + /// Elements are in uninitialized state. + ConstBuffer(); + + /// Construct from pointer and size. + ConstBuffer( + char const * ptr, ///< Pointer to buffer. + size_t n ///< Size of buffer. + ); + /// Construct from writable buffer. + ConstBuffer( + Buffer const& buffer ///< Buffer to copy. + ); + + /** Equality. + @return @c true if the @c Buffer instances are identical, + @c false otherwise. + */ + bool operator == (self const& that) const; + /** Equality. + @return @c true if the @c Buffer instances are identical, + @c false otherwise. + */ + bool operator == (Buffer const& that) const; + /** Inequality. + @return @c true if the @c Buffer instances are different, + @c false otherwise. + */ + bool operator != (self const& that) const; + /** Inequality. + @return @c true if the @c Buffer instances are different, + @c false otherwise. + */ + bool operator != (Buffer const& that) const; + /// Assign from non-const Buffer. + self& operator = ( + Buffer const& that ///< Source buffer. + ); + + /// @name Accessors. + //@{ + /// Get the data in the buffer. + char const * data() const; + /// Get the size of the buffer. + size_t size() const; + //@} + + /// Set the chunk. + /// Any previous values are discarded. + /// @return @c this object. + self& set( + char const * ptr, ///< Buffer address. + size_t n ///< Buffer size. + ); + /// Reset to empty. + self& reset(); + }; + + // ---------------------------------------------------------- + // Inline implementations. + + inline Buffer::Buffer() { } + inline Buffer::Buffer(char* ptr, size_t n) : _ptr(ptr), _size(n) { } + inline Buffer& Buffer::set(char* ptr, size_t n) { _ptr = ptr; _size = n; return *this; } + inline Buffer& Buffer::reset() { _ptr = 0; _size = 0 ; return *this; } + inline bool Buffer::operator != (self const& that) const { return ! (*this == that); } + inline bool Buffer::operator != (ConstBuffer const& that) const { return ! (*this == that); } + inline bool Buffer::operator == (self const& that) const { + return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size); + } + inline bool Buffer::operator == (ConstBuffer const& that) const { + return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size); + } + inline char * Buffer::data() const { return _ptr; } + inline size_t Buffer::size() const { return _size; } + + inline ConstBuffer::ConstBuffer() { } + inline ConstBuffer::ConstBuffer(char const* ptr, size_t n) : _ptr(ptr), _size(n) { } + inline ConstBuffer::ConstBuffer(Buffer const& that) : _ptr(that._ptr), _size(that._size) { } + inline ConstBuffer& ConstBuffer::set(char const* ptr, size_t n) { _ptr = ptr; _size = n; return *this; } + inline ConstBuffer& ConstBuffer::reset() { _ptr = 0; _size = 0 ; return *this; } + inline bool ConstBuffer::operator != (self const& that) const { return ! (*this == that); } + inline bool ConstBuffer::operator != (Buffer const& that) const { return ! (*this == that); } + inline bool ConstBuffer::operator == (self const& that) const { + return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size); + } + inline ConstBuffer& ConstBuffer::operator = (Buffer const& that) { _ptr = that._ptr ; _size = that._size; return *this; } + inline bool ConstBuffer::operator == (Buffer const& that) const { + return _size == that._size && 0 == memcmp(_ptr, that._ptr, _size); + } + inline char const * ConstBuffer::data() const { return _ptr; } + inline size_t ConstBuffer::size() const { return _size; } +} + +# endif // TS_BUFFER_HEADER diff --git a/lib/tsconfig/TsBuilder.cc b/lib/tsconfig/TsBuilder.cc new file mode 100644 index 00000000..efba4bb8 --- /dev/null +++ b/lib/tsconfig/TsBuilder.cc @@ -0,0 +1,214 @@ +/** @file + + Implementation of the handler for parsing events. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "TsBuilder.h" +# include "TsErrataUtil.h" +# include "TsConfigLexer.h" +# include "TsConfigGrammar.hpp" +# include + +// Prefix for text of our messages. +# define PRE "Configuration Parser: " + +namespace { +/** Compress a string by removing escape characters. + @return The new length of the string. +*/ +size_t unescape_string(char* text, size_t len) { + size_t zret = len; + // quick check - if no escape char, do nothing. + char* dst = static_cast(memchr(text, '\\', len)); + if (dst) { + char* limit = text + len; + char* src = dst + 1; // skip escape char + for ( *dst++ = *src++ ; src < limit ; ++src ) + if ('\\' != *src) *dst++ = *src; + else if (++src < limit) *dst++ = *src; + else *dst++ = '\\'; // trailing backslash. + zret = dst - text; + } + return zret; +} +} // anon namespace + +namespace ts { namespace config { + +Builder& +Builder::init() { + // Fill in each element to dispatch through the static + // method. Callback data is a pointer to an entry in @c dispatch + // which contains pointer to this object and a pointer to the + // appropriate dispatch method. + + // Zero everything first, just to be safe. + memset(_dispatch, 0, sizeof(_dispatch)); + + for ( size_t i = 0 ; i < TS_CONFIG_N_EVENT_TYPES ; ++i) { + _dispatch[i]._ptr = this; + _handlers.handler[i]._f = &self::dispatch; + _handlers.handler[i]._data = &(_dispatch[i]); + } + + _dispatch[TsConfigEventGroupOpen]._method = &self::groupOpen; + _dispatch[TsConfigEventGroupName]._method = &self::groupName; + _dispatch[TsConfigEventGroupClose]._method = &self::groupClose; + _dispatch[TsConfigEventListOpen]._method = &self::listOpen; + _dispatch[TsConfigEventListClose]._method = &self::listClose; + _dispatch[TsConfigEventPathOpen]._method = &self::pathOpen; + _dispatch[TsConfigEventPathTag]._method = &self::pathTag; + _dispatch[TsConfigEventPathIndex]._method = &self::pathIndex; + _dispatch[TsConfigEventPathClose]._method = &self::pathClose; + _dispatch[TsConfigEventLiteralValue]._method = &self::literalValue; + _dispatch[TsConfigEventInvalidToken]._method = &self::invalidToken; + + _handlers.error._data = this; + _handlers.error._f = &self::syntaxErrorDispatch; + + return *this; +} + +// Error messages here have to just be logged, as they effectively report that +// the dispatcher can't find the builder object. +void +Builder::dispatch(void* data, Token* token) { + if (data) { + Handler* handler = reinterpret_cast(data); + if (handler->_ptr) { + if (handler->_method) { + ((handler->_ptr)->*(handler->_method))(*token); + } else { + msg::logf(msg::WARN, PRE "Unable to dispatch event - no method."); + } + } else { + msg::logf(msg::WARN, PRE "Unable to dispatch event - no builder."); + } + } else { + msg::logf(msg::WARN, PRE "Unable to dispatch event - no handler."); + } +} + +int +Builder::syntaxErrorDispatch(void* data, char const* text) { + return reinterpret_cast(data)->syntaxError(text); +} + +int +Builder::syntaxError(char const* text) { + msg::logf(_errata, msg::WARN, + "Syntax error '%s' near line %d, column %d.", + text, tsconfiglex_current_line(), tsconfiglex_current_col() + ); + return 0; +} + +Rv +Builder::build(Buffer const& buffer) { + _v = _config.getRoot(); // seed current value. + _errata.clear(); // no errors yet. + tsconfig_parse_buffer(&_handlers, buffer._ptr, buffer._size); + return MakeRv(_config, _errata); +} + +void +Builder::groupOpen(Token const& token) { + _v = _v.makeGroup(_name); + _v.setSource(token._loc._line, token._loc._col); +} +void Builder::groupClose(Token const&) { + _v = _v.getParent(); +} +void Builder::groupName(Token const& token) { + _name.set(token._s, token._n); +} +void Builder::listOpen(Token const& token) { + _v = _v.makeList(_name); + _v.setSource(token._loc._line, token._loc._col); +} +void Builder::listClose(Token const&) { + _v = _v.getParent(); +} + +void Builder::pathOpen(Token const&) { + _path.reset(); + _extent.reset(); +} +void Builder::pathTag(Token const& token) { + _path.append(Buffer(token._s, token._n)); + if (_extent._ptr) { + _extent._size = token._s - _extent._ptr + token._n; + } else { + _extent.set(token._s, token._n); + _loc = token._loc; + } +} +void Builder::pathIndex(Token const& token){ + // We take advantage of the lexer - token will always be a valid + // digit string that is followed by a non-digit or the FLEX + // required double null at the end of the input buffer. + _path.append(Buffer(0, static_cast(atol(token._s)))); + if (_extent._ptr) _extent._size = token._s - _extent._ptr + token._n; + else _extent.set(token._s, token._n); +} + +void Builder::pathClose(Token const&) { + Rv cv = _v.makePath(_path, _name); + if (cv.isOK()) { + cv.result().setText(_extent).setSource(_loc._line, _loc._col); + // Terminate path. This will overwrite trailing whitespace or + // the closing angle bracket, both of which are expendable. + _extent._ptr[_extent._size] = 0; + } + _name.reset(); + _extent.reset(); +} + +void Builder::literalValue(Token const& token) { + Rv cv; + Buffer text(token._s, token._n); + + // It's just too painful to use these strings with standard + // libraries without nul terminating. For strings we convert the + // trailing quote. For integers we abuse the fact that the parser + // can't reduce using this token before the lexer has read at + // least one char ahead. + + // Note the nul is *not* included in the reported length. + + if (INTEGER == token._type) { + cv = _v.makeInteger(text, _name); + token._s[token._n] = 0; + } else if (STRING == token._type) { + ++text._ptr, text._size -= 2; // Don't include the quotes. + text._size = unescape_string(text._ptr, text._size); + text._ptr[text._size] = 0; // OK because we have the trailing quote. + cv = _v.makeString(text, _name); + } else { + msg::logf(_errata, msg::WARN, PRE "Unexpected literal type %d.", token._type); + } + if (!cv.isOK()) _errata.pull(cv.errata()); + if (cv.result()) cv.result().setSource(token._loc._line, token._loc._col); + _name.set(0,0); // used, so clear it. +} +void Builder::invalidToken(Token const&) { } + +}} // namespace ts::config diff --git a/lib/tsconfig/TsBuilder.h b/lib/tsconfig/TsBuilder.h new file mode 100644 index 00000000..815e195d --- /dev/null +++ b/lib/tsconfig/TsBuilder.h @@ -0,0 +1,101 @@ +# if ! defined(TS_CONFIG_BUILDER_HEADER) +# define TS_CONFIG_BUILDER_HEADER + +/** @file + + Header for handler for parsing events. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "TsValue.h" +# include "TsConfigTypes.h" +# include "TsConfigParseEvents.h" + +namespace ts { namespace config { + +/** Class to build the configuration table from parser events. + */ +class Builder { +public: + typedef Builder self; + struct Handler { + self* _ptr; ///< Pointer to Builder instance. + /// Pointer to method to invoke for this event. + void (self::*_method)(Token const& token); + + /// Default constructor. + Handler(); + }; + + /// Default constructor. + Builder(); + /// Destructor. + virtual ~Builder() {} + /// Construct with existing configuration. + Builder(Configuration const& config); + /// Build the table. + /// @return The configuration or error status. + Rv build( + Buffer const& buffer ///< Input text. + ); +protected: + /// Dispatch table for parse events. + Handler _dispatch[TS_CONFIG_N_EVENT_TYPES]; + /// Event handler table for the parser. + TsConfigHandlers _handlers; + /// Dispatch methods + virtual void groupOpen(Token const& token); + virtual void groupClose(Token const& token); + virtual void groupName(Token const& token); + virtual void listOpen(Token const& token); + virtual void listClose(Token const& token); + virtual void pathOpen(Token const& token); + virtual void pathTag(Token const& token); + virtual void pathIndex(Token const& token); + virtual void pathClose(Token const& token); + virtual void literalValue(Token const& token); + virtual void invalidToken(Token const& token); + /// Syntax error handler + virtual int syntaxError(char const* text); + /// Static method to handle parser event callbacks. + static void dispatch(void* data, Token* token); + /// Static method for syntax errors. + static int syntaxErrorDispatch(void* data, char const* text); + + // Building state. + Configuration _config; ///< Configuration to update. + Errata _errata; ///< Error accumulator. + Value _v; ///< Current value. + Buffer _name; ///< Pending group name, if any. + Buffer _extent; ///< Accumulator for multi-token text. + Location _loc; ///< Cache for multi-token text. + Path _path; ///< Path accumulator + + /// Initialization, called from constructors. + self& init(); +}; + +inline Builder::Handler::Handler() : _ptr(0), _method(0) { } +inline Builder::Builder() { this->init(); } +inline Builder::Builder(Configuration const& config) : _config(config) { this->init(); } + +}} // namespace ts::config + +# endif // TS_CONFIG_BUILDER_HEADER diff --git a/lib/tsconfig/TsConfigGrammar.y b/lib/tsconfig/TsConfigGrammar.y new file mode 100644 index 00000000..57871408 --- /dev/null +++ b/lib/tsconfig/TsConfigGrammar.y @@ -0,0 +1,118 @@ +%code top { +/** @file + + TS Configuration grammar. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "TsConfigTypes.h" +# include + +// Inhibit Bison definitions. +# define YYMALLOC malloc +# define YYFREE free + +# include "TsConfigParseEvents.h" + +// Types we need for the lexer. +typedef void* yyscan_t; +extern int tsconfiglex(YYSTYPE* yylval, yyscan_t lexer); + +} + +%code { + +# define HANDLE_EVENT(x,y) \ + if (handlers) { \ + struct TsConfigEventHandler* h = &(handlers->handler[TsConfigEvent##x]); \ + if (h->_f) h->_f(h->_data, &(y)); \ + } + +int tsconfigerror( + yyscan_t lexer, + struct TsConfigHandlers* handlers, + char const* text +) { + return (handlers && handlers->error._f) + ? handlers->error._f(handlers->error._data, text) + : 0 + ; +} + +} + +%token STRING +%token IDENT +%token INTEGER +%token LIST_OPEN +%token LIST_CLOSE +%token GROUP_OPEN +%token GROUP_CLOSE +%token PATH_OPEN +%token PATH_CLOSE +%token PATH_SEPARATOR +%token SEPARATOR +%token ASSIGN + +%error-verbose +%define api.pure +%parse-param { yyscan_t lexer } +%parse-param { struct TsConfigHandlers* handlers } +%lex-param { yyscan_t lexer } + +%% + +config: group_items; + +group: group_open group_items group_close ; + +group_open: GROUP_OPEN { HANDLE_EVENT(GroupOpen, $1); } ; + +group_close: GROUP_CLOSE { HANDLE_EVENT(GroupClose, $1); } ; + +group_items: /* empty */ | group_items assign separator | group_items error separator ; + +assign: IDENT ASSIGN { HANDLE_EVENT(GroupName, $1); } value ; + +list: list_open list_items list_close ; + +list_open: LIST_OPEN { HANDLE_EVENT(ListOpen, $1); } ; + +list_close: LIST_CLOSE { HANDLE_EVENT(ListClose, $1); } ; + +list_items: /* empty */ | list_items value separator | list_items error separator; + +value: literal { HANDLE_EVENT(LiteralValue, $1); } | list | group | path; + +literal: STRING | IDENT | INTEGER ; + +separator: /* empty */ | SEPARATOR ; + +path: path_open path_item path_close; + +path_open: PATH_OPEN { HANDLE_EVENT(PathOpen, $1); } + +path_close: PATH_CLOSE { HANDLE_EVENT(PathClose, $1); } + +path_item: path_tag | path_item PATH_SEPARATOR path_tag ; + +path_tag: IDENT { HANDLE_EVENT(PathTag, $1); } | INTEGER { HANDLE_EVENT(PathIndex, $1); }; + +%% diff --git a/lib/tsconfig/TsConfigLexer.h b/lib/tsconfig/TsConfigLexer.h new file mode 100644 index 00000000..40262ed6 --- /dev/null +++ b/lib/tsconfig/TsConfigLexer.h @@ -0,0 +1,61 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +# if ! defined(TS_CONFIG_LEXER_HEADER) +# define TS_CONFIG_LEXER_HEADER + +struct TsConfigHandlers; // forward declare. + +# if defined(__cplusplus) + extern "C" { +# endif + +/// Get the current line in the buffer during parsing. +/// @return 1 based line number. +extern int tsconfiglex_current_line(void); +/// Get the current column in the buffer during parsing. +/// @return 0 base column number. +extern int tsconfiglex_current_col(void); + +/** Parse @a buffer. + + The @a buffer is parsed and the events dispatched via @a handlers. + + @note The contents of @a buffer are in general modified to handle + null termination and processing escape codes in strings. Tokens + passed to the handlers are simply offsets in to @a buffer and + therefore have the same lifetime as @a buffer. + + @return Not sure. + */ +extern int tsconfig_parse_buffer( + struct TsConfigHandlers* handlers, ///< Syntax handlers. + char* buffer, ///< Input buffer. + size_t buffer_len ///< Length of input buffer. +); + +# if defined(__cplusplus) +} +# endif + +# endif // TS_CONFIG_LEXER_HEADER diff --git a/lib/tsconfig/TsConfigParseEvents.h b/lib/tsconfig/TsConfigParseEvents.h new file mode 100644 index 00000000..237514b3 --- /dev/null +++ b/lib/tsconfig/TsConfigParseEvents.h @@ -0,0 +1,67 @@ +# if ! defined(TS_CONFIG_PARSE_EVENTS_HEADER) +# define TS_CONFIG_PARSE_EVENTS_HEADER + +/** @file + + Definition of parsing events and handlers. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "TsConfigTypes.h" + +typedef void (*TsConfigEventFunction)(void* data, YYSTYPE* token); +struct TsConfigEventHandler { + TsConfigEventFunction _f; ///< Callback function. + void* _data; ///< Callback context data. +}; +typedef int (*TsConfigErrorFunction)(void* data, char const* text); +struct TsConfigErrorHandler { + TsConfigErrorFunction _f; ///< Callback function. + void* _data; ///< Callback context data. +}; + +enum TsConfigEventType { + TsConfigEventGroupOpen, + TsConfigEventGroupName, + TsConfigEventGroupClose, + TsConfigEventListOpen, + TsConfigEventListClose, + TsConfigEventPathOpen, + TsConfigEventPathTag, + TsConfigEventPathIndex, + TsConfigEventPathClose, + TsConfigEventLiteralValue, + TsConfigEventInvalidToken +}; + +# if defined(__cplusplus) +static const size_t TS_CONFIG_N_EVENT_TYPES = TsConfigEventInvalidToken + 1; +# else +# define TS_CONFIG_N_EVENT_TYPES (TsConfigEventInvalidToken + 1) +# endif + +struct TsConfigHandlers { + struct TsConfigErrorHandler error; ///< Syntax error. + /// Parsing event handlers. + /// Indexed by @c TsConfigEventType. + struct TsConfigEventHandler handler[TS_CONFIG_N_EVENT_TYPES]; +}; + +# endif // TS_CONFIG_PARSE_EVENTS_HEADER diff --git a/lib/tsconfig/TsConfigSyntax.l b/lib/tsconfig/TsConfigSyntax.l new file mode 100644 index 00000000..6a07463b --- /dev/null +++ b/lib/tsconfig/TsConfigSyntax.l @@ -0,0 +1,124 @@ +%{ + +/** @file + + Syntactic analyzer for TS Configuration. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "TsConfigParseEvents.h" +# include "TsConfigGrammar.h" + +extern int tsconfigparse(yyscan_t lexer, struct TsConfigHandlers* handlers); + +struct Location TsConfig_Lex_Location = { 0, 1 }; + +# define YY_USER_ACTION TsConfig_Lex_Location._col += yyleng; + +# define FILL \ + yylval->_s = yytext; \ + yylval->_n = yyleng; \ + yylval->_loc = TsConfig_Lex_Location; \ + yylval->_loc._col -= yyleng; + +# define ZRET(t) FILL; yylval->_type = t; return t; + +# define HANDLE_EVENT(x) \ + if (yyextra) { \ + struct TsConfigEventHandler* h = &(yyextra->handler[TsConfigEvent##x]); \ + if (h->_f) h->_f(h->_data, yylval); \ + } + +%} + +%option outfile="lex.yy.c" +%option never-interactive reentrant bison-bridge noyywrap +%option prefix="tsconfig" +%option nounput noinput +%option extra-type="struct TsConfigHandlers*" + +DSTRING \"(?:[^\"\\]|\\.)*\" +SSTRING '(?:[^'\\]|\\.)*' +QSTRING {DSTRING}|{SSTRING} +IDENT [[:alpha:]_](?:-*[[:alnum:]_])* + +%x bad + +%% + +\n { + ++(TsConfig_Lex_Location._line); + TsConfig_Lex_Location._col = 0; + } + +{QSTRING} ZRET(STRING); /* Quote string overrides comments */ + +(?:[[:space:]]{-}[\n])+ /* Ignore all white space. */ +^[[:space:]]*#.*$ /* Leading '#' is a comment. */ +\/\/.*$ /* Trailing '//' is a comment. */ + +{IDENT} ZRET(IDENT); +[[:digit:]]+ ZRET(INTEGER); +\{ ZRET(GROUP_OPEN); +\} ZRET(GROUP_CLOSE); +\( ZRET(LIST_OPEN); +\) ZRET(LIST_CLOSE); +\< ZRET(PATH_OPEN); +\> ZRET(PATH_CLOSE); +\. ZRET(PATH_SEPARATOR); += ZRET(ASSIGN); +[,;]+ ZRET(SEPARATOR); + +. BEGIN(bad); FILL; +\n { + BEGIN(0); // Terminate bad token mode. + ++(TsConfig_Lex_Location._line); // Must bump line count. + HANDLE_EVENT(InvalidToken); + } +[[:space:]] BEGIN(0); HANDLE_EVENT(InvalidToken); +. ++(yylval->_n); +%% + +int tsconfiglex_current_line(void) { return TsConfig_Lex_Location._line; } +int tsconfiglex_current_col(void) { return TsConfig_Lex_Location._col; } + +// This is in here because it's easier than trying to convince automake +// to let me have a generated header from flex. The header is only needed +// to define the various macros used here outside of the .l file so if +// this is here, we don't need the header anymore. This also means we +// don't have to deal with C/C++ issues in that regard either. +int tsconfig_parse_buffer( + struct TsConfigHandlers* handlers, + char* buffer, + size_t buffer_len +) { + int zret; + yyscan_t lexer; + YY_BUFFER_STATE lexer_buffer_state; + + tsconfiglex_init(&lexer); + tsconfigset_extra(handlers, lexer); + lexer_buffer_state = tsconfig_scan_buffer(buffer, buffer_len, lexer); + zret = tsconfigparse(lexer, handlers); + tsconfig_delete_buffer(lexer_buffer_state, lexer); + tsconfiglex_destroy(lexer); + + return zret; +} diff --git a/lib/tsconfig/TsConfigTypes.h b/lib/tsconfig/TsConfigTypes.h new file mode 100644 index 00000000..b4399d0d --- /dev/null +++ b/lib/tsconfig/TsConfigTypes.h @@ -0,0 +1,66 @@ +# if ! defined(TS_CONFIG_TYPES_HEADER) +# define TS_CONFIG_TYPES_HEADER + +/** @file + + Basic types for configuration parsing. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# if defined(_MSC_VER) +# include +# else +# include +# endif + +# if defined(__cplusplus) +namespace ts { namespace config { +# endif + +/** A location in the source stream. + @internal At some point we may need to add stream information, + e.g. file name, once includes are supported. Or should that + be the caller's responsibility? + */ +struct Location { + int _col; ///< Column. + int _line; ///< Line. +}; + +/** A token from the source stream. + @internal We should use ts::Buffer here, but because this + has to work in C as well, it's less painful to do it by hand. + */ +struct Token { + char* _s; ///< Text of token. + size_t _n; ///< Text length. + int _type; ///< Type of token. + struct Location _loc; ///< Location of token. +}; + +# if defined(__cplusplus) +}} // namespace ts::config +# define YYSTYPE ts::config::Token +# else +# define YYSTYPE struct Token +#endif + + +# endif // TS_CONFIG_TYPES_HEADER diff --git a/lib/tsconfig/TsErrataUtil.cc b/lib/tsconfig/TsErrataUtil.cc new file mode 100644 index 00000000..8f766aa3 --- /dev/null +++ b/lib/tsconfig/TsErrataUtil.cc @@ -0,0 +1,170 @@ +/** @file + + TS Configuration utilities for Errata and logging. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# if !defined(_MSC_VER) +# include +# include +# endif +# include +# include +# include + +namespace ts { namespace msg { + +Errata::Code FATAL = 3; ///< Fatal, cannot continue. +Errata::Code WARN = 2; ///< Significant, should be fixed. +Errata::Code INFO = 1; /// Interesting, not necessarily a problem. +Errata::Code DEBUG = 0; /// Debugging information. + +# if defined(_MSC_VER) +char* strerror_r(int err, char* s, size_t n) { + strncpy(s, strerror(err), n-1); + s[n-1] = 0; // guarantee null termination. + return s; +} + +# define snprintf _snprintf +# endif + +Errata& +log(Errata& err, Errata::Id id, Errata::Code code, char const* text) { + err.push(id, code, text); + return err; +} + +Errata& +log(Errata& err, Errata::Code code, char const* text) { + err.push(0, code, text); + return err; +} + +Errata& +log(RvBase& rv, Errata::Code code, char const* text) { + rv._errata.push(0, code, text); + return rv._errata; +} + +Errata +log(Errata::Code code, char const* text) { + Errata err; + err.push(0, code, text); + return err; +} + +Errata& +vlogf( + Errata& err, + Errata::Id id, + Errata::Code code, + char const* format, + va_list& rest +) { + static size_t const SIZE = 8192; + char buffer[SIZE]; + + vsnprintf(buffer, SIZE, format, rest); + err.push(id, code, buffer); + return err; +} + +Errata& +logf( + Errata& err, + Errata::Id id, + Errata::Code code, + char const* format, + ... +) { + va_list rest; + va_start(rest, format); + return vlogf(err, id, code, format, rest); +} + +Errata +logf(Errata::Code code, char const* format, ...) { + Errata err; + va_list rest; + va_start(rest, format); + return vlogf(err, Errata::Id(0), code, format, rest); +} + +Errata& +logf(Errata& err, Errata::Code code, char const* format, ...) { + va_list rest; + va_start(rest, format); + return vlogf(err, Errata::Id(0), code, format, rest); +} + +Errata& +logf(RvBase& base, Errata::Code code, char const* format, ...) { + va_list rest; + va_start(rest, format); + return vlogf(base._errata, Errata::Id(0), code, format, rest); +} + +Errata +log_errno(Errata::Code code, char const* text) { + static size_t const SIZE = 1024; + char buffer[SIZE]; + return logf(code, "%s [%d] %s", text, errno, strerror_r(errno, buffer, SIZE)); +} + +Errata +vlogf_errno(Errata& errata, Errata::Id id, Errata::Code code, char const* format, va_list& rest) { + int e = errno; // Preserve value before making system calls. + int n; + static int const E_SIZE = 256; + char e_buffer[E_SIZE]; + static int const T_SIZE = 8192; + char t_buffer[T_SIZE]; + + n = vsnprintf(t_buffer, T_SIZE, format, rest); + if (0 <= n && n < T_SIZE) // still have room. + n += snprintf(t_buffer + n, T_SIZE - n, "[%d] %s", e, strerror_r(e, e_buffer, E_SIZE)); + errata.push(id, code, t_buffer); + return errata; +} + +Errata +logf_errno(Errata::Code code, char const* format, ...) { + Errata zret; + va_list rest; + va_start(rest, format); + return vlogf_errno(zret, 0, code, format, rest); +} + +Errata +logf_errno(Errata& errata, Errata::Code code, char const* format, ...) { + va_list rest; + va_start(rest, format); + return vlogf_errno(errata, 0, code, format, rest); +} + +Errata +logf_errno(RvBase& rv, Errata::Code code, char const* format, ...) { + va_list rest; + va_start(rest, format); + return vlogf_errno(rv._errata, 0, code, format, rest); +} +// ------------------------------------------------------ +}} // namespace ts::msg diff --git a/lib/tsconfig/TsErrataUtil.h b/lib/tsconfig/TsErrataUtil.h new file mode 100644 index 00000000..f9df89db --- /dev/null +++ b/lib/tsconfig/TsErrataUtil.h @@ -0,0 +1,169 @@ +/** @file + + TS Configuration utilities for Errata and logging. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# if !defined(TS_ERRATA_UTIL_HEADER) +# define TS_ERRATA_UTIL_HEADER + +// TBD: Need to do something better than this to get around using +// 'DEBUG' as the name of a constant. +# if defined DEBUG +# undef DEBUG +# define DEBUG DEBUG +# endif + +# include + +namespace ts { namespace msg { + +/// @name Message severity levels. +//@{ +extern Errata::Code FATAL; ///< Fatal, cannot continue. +extern Errata::Code WARN; ///< Significant, function degraded. +extern Errata::Code INFO; ///< Interesting, not necessarily a problem. +extern Errata::Code DEBUG; ///< Debugging information. +//@} + +/** Logging / reporting support. + We build on top of @c Errata but we want to be able to prevent + message generation / allocation for messages with severity levels + less than a run time controllable value. + + @internal Far from complete but serving as a prototype / experiment + to learn what's actually useful. +*/ +//@{ +/// Report literal string to an Errata. +/// @return @a err. +Errata& log( + Errata& err,///< Target errata. + Errata::Id id, ///< Message ID. + Errata::Code code, ///< Severity level. + char const* text ///< Message text. +); +/// Report literal string to an Errata. +/// Use message ID 0. +/// @return @a err. +Errata& log( + Errata& err,///< Target errata. + Errata::Code code, ///< Severity level. + char const* text ///< Message text. +); +/// Report literal string to a return value. +/// Use message ID 0. +/// @return The @c Errata in @a rv. +Errata& log( + RvBase& rv,///< Return value. + Errata::Code code, ///< Severity level. + char const* text ///< Message text. +); +/// printf style log to Errata. +/// @return @a err. +Errata& logf( + Errata& err,///< Target errata. + Errata::Id id, ///< Message ID. + Errata::Code code, ///< Severity level. + char const* format, ///< Format string. + ... ///< Format string parameters. +); +/// printf style log to Errata. +/// The message id is set to zero. +/// @return @a err. +Errata& logf( + Errata& err,///< Target errata. + Errata::Code code, ///< Severity level. + char const* format, ///< Format string. + ... ///< Format string parameters. +); +/// Return an Errata in a return value populated with a printf style formatted string. +/// Use message ID 0. +/// @return The @c Errata in @a rv. +Errata& logf( + RvBase& rv, ///< Rv value. + Errata::Code code, ///< Severity level. + char const* format, ///< Message text. + ... +); +/// Return an Errata populated with a literal string. +/// Use message ID 0. +/// @return @a err. +Errata log( + Errata::Code code, ///< Severity level. + char const* text ///< Message text. +); +/// Return an Errata populated with a printf style formatted string. +/// Use message ID 0. +/// @return @a err. +Errata logf( + Errata::Code code, ///< Severity level. + char const* format, ///< Message text. + ... +); +/** Return an Errata based on @c errno. + The literal string is combined with the system text for the current + value of @c errno. This is modeled on @c perror. Message ID 0 is used. + @return The new @c Errata. + */ +Errata log_errno( + Errata::Code code, ///< Severity level. + char const* text ///< Message text. +); +/** Return an @c Errata based on @c errno. + @c errno and the corresponding system error string are appended to + the results from the @a format and following arguments. + @return The new @c Errata. + */ +Errata +logf_errno( + Errata::Code code, ///< Severity code. + char const* format, ///< Format string. + ... ///< Arguments for @a format. +); +/** Add a message to an @a errata based on @c errno. + @c errno and the corresponding system error string are appended to + the results from the @a format and following arguments. + @return @a errata. + */ +Errata +logf_errno( + Errata& errata, ///< Errata to use. + Errata::Code code, ///< Severity code. + char const* format, ///< Format string. + ... ///< Arguments for @a format. +); +/** Add a message to a return value based on @c errno. + @c errno and the corresponding system error string are appended to + the results from the @a format and following arguments. + @return The errata in @a rv. + */ +Errata +logf_errno( + RvBase& rv, ///< Return value. + Errata::Code code, ///< Severity code. + char const* format, ///< Format string. + ... ///< Arguments for @a format. +); +//@} + +}} // namespace ts::msg + +# endif // define TS_ERRATA_UTIL_HEADER diff --git a/lib/tsconfig/TsValue.cc b/lib/tsconfig/TsValue.cc new file mode 100644 index 00000000..c4ff2b3d --- /dev/null +++ b/lib/tsconfig/TsValue.cc @@ -0,0 +1,364 @@ +/** @file + + TS Configuration API implementation. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "TsValue.h" +# include "TsBuilder.h" + +# include +# include +# include + +# if !defined(_MSC_VER) +# define _fileno fileno +# define __STDC_FORMAT_MACROS 1 +# include +# endif + +// --------------------------------------------------------------------------- +namespace ts { namespace config { +// --------------------------------------------------------------------------- +Buffer const detail::NULL_BUFFER(0,0); +ConstBuffer const detail::NULL_CONST_BUFFER(0,0); +detail::ValueItem detail::ValueTableImpl::NULL_ITEM(VoidValue); +detail::PseudoBool::Type const detail::PseudoBool::FALSE = 0; +detail::PseudoBool::Type const detail::PseudoBool::TRUE = &detail::PseudoBool::operator !; +// This should not be called, it is used only as a pointer value. +bool detail::PseudoBool::operator ! () const { return false; } +// --------------------------------------------------------------------------- +unsigned int const detail::Type_Property[N_VALUE_TYPES] = { + 0, // Void + detail::IS_VALID | detail::IS_CONTAINER, // List + detail::IS_VALID | detail::IS_CONTAINER, // Group + detail::IS_VALID | detail::IS_LITERAL, // String + detail::IS_VALID | detail::IS_LITERAL, // Integer +}; +// --------------------------------------------------------------------------- +detail::ValueTableImpl::ValueTableImpl() : _generation(0) { } +detail::ValueTableImpl::~ValueTableImpl() { + for ( BufferGroup::iterator spot(_buffers.begin()), limit(_buffers.end()) ; spot != limit ; ++spot) + free(spot->_ptr); +} +// --------------------------------------------------------------------------- +detail::ValueTable::ImplType* +detail::ValueTable::instance() { + if (! _ptr) _ptr.reset(new ImplType); + return _ptr.get(); +} + +detail::ValueTable& +detail::ValueTable::forceRootItem() { + ImplType* imp = this->instance(); + if (0 == imp->_values.size()) + imp->_values.push_back(ValueItem(GroupValue)); + return *this; +} + +Rv +detail::ValueTable::make(ValueIndex pidx, ValueType type, ConstBuffer const& name) { + Rv zret = NULL_VALUE_INDEX; + if (_ptr) { + size_t n = _ptr->_values.size(); + // Check the parent + if (pidx < n) { + ValueItem* parent = &(_ptr->_values[pidx]); + if (IS_CONTAINER & Type_Property[parent->_type]) { + ValueItem* item; + + _ptr->_values.push_back(ValueItem(type)); + parent = &(_ptr->_values[pidx]); // possibly stale, refresh. + item = &(_ptr->_values[n]); + item->_parent = pidx; + parent->_children.push_back(n); + item->_local_index = parent->_children.size() - 1; + // Only use the name if the parent is a group. + if (GroupValue == parent->_type) item->_name = name; + zret = n; // mark for return to caller. + } else { + msg::log(zret.errata(), msg::WARN, "Add child failed because parent is not a container."); + } + } else { + msg::logf(zret.errata(), msg::WARN, "Add child failed because parent index (%ul) is out of range (%ul).", pidx.raw(), n); + } + } else { + msg::log(zret.errata(), msg::WARN, "Add child failed because the configuration is null."); + } + return zret; +} + +detail::ValueItem& +detail::ValueTable::operator [] ( ValueIndex idx ) { + assert(_ptr && idx < _ptr->_values.size()); + return _ptr->_values[idx]; +} +Buffer +detail::ValueTable::alloc(size_t n) { + ImplType* imp = this->instance(); + Buffer zret(static_cast(malloc(n)), n); + if (zret._ptr) imp->_buffers.push_back(zret); + return zret; +} + +// --------------------------------------------------------------------------- +Value +Value::operator [] (size_t idx) const { + Value zret; + detail::ValueItem const* item = this->item(); + if (item && idx < item->_children.size()) { + zret = Value(_config, item->_children[idx]); + if (PathValue == zret.getType()) zret = _config.getRoot().find(_config._table[zret._vidx]._path); + } + return zret; +} + +Value +Value::operator [] (ConstBuffer const& name) const { + Value zret; + detail::ValueItem const* item = this->item(); + if (item) { + for ( detail::ValueItem::ChildGroup::const_iterator spot = item->_children.begin(), limit = item->_children.end(); spot != limit; ++spot ) { + if (_config._table[*spot]._name == name) { + zret = Value(_config, *spot); + if (PathValue == zret.getType()) zret = _config.getRoot().find(_config._table[zret._vidx]._path); + break; + } + } + } + return zret; +} + +Value +Value::find( ConstBuffer const& path ) { + Value zret = *this; + Path::Parser parser(path); + Rv x; + ConstBuffer elt; + for ( x = parser.parse(&elt) ; zret && Path::Parser::EOP != x && Path::Parser::ERROR != x ; x = parser.parse(&elt) ) { + if (Path::Parser::TAG == x) zret = zret[elt]; + else if (Path::Parser::INDEX == x) zret = zret[elt._size]; + else zret.reset(); + } + if (Path::Parser::EOP != x) zret.reset(); + return zret; +} + +Value +Value::find(Path const& path ) { + Value zret = *this; + for ( size_t i = 0, n = path.count() ; i < n && zret ; ++i ) { + ConstBuffer const& elt = path[i]; + if (elt._ptr) zret = zret[elt]; + else zret = zret[elt._size]; + } + return zret; +} + +Rv +Value::makeChild(ValueType type, ConstBuffer const& name) { + Rv zret; + Rv vr = _config._table.make(this->_vidx, type, name); + if (vr.isOK()) zret = Value(_config, vr.result()); + else zret.errata() = vr.errata(); + return zret; +} + +Rv +Value::makeGroup(ConstBuffer const& name) { + return this->makeChild(GroupValue, name); +} + +Rv +Value::makeList(ConstBuffer const& name) { + return this->makeChild(ListValue, name); +} + +Rv +Value::makeString(ConstBuffer const& text, ConstBuffer const& name) { + Rv zret = this->makeChild(StringValue, name); + if (zret.isOK()) zret.result().setText(text); + return zret; +} + +Rv +Value::makeInteger(ConstBuffer const& text, ConstBuffer const& name) { + Rv zret = this->makeChild(IntegerValue, name); + if (zret.isOK()) zret.result().setText(text); + return zret; +} + +Rv +Value::makePath(Path const& path, ConstBuffer const& name) { + Rv zret = this->makeChild(PathValue, name); + if (zret.isOK()) _config._table[zret.result()._vidx]._path = path; + return zret; +} +// --------------------------------------------------------------------------- +Path& Path::reset() { + if (_ptr) { + // If we're sharing the instance, make a new one for us. + if (_ptr.isShared()) _ptr = new ImplType; + else { // clear out the existing instance. + _ptr->_elements.clear(); + } + } + return *this; +} +// --------------------------------------------------------------------------- +Rv +Path::Parser::parse(ConstBuffer *cbuff) { + Rv zret = EOP; + enum State { + S_INIT, // initial state + S_INDEX, // reading index. + S_TAG, // reading tag. + S_DASH, // reading dashes in tag. + } state = S_INIT; + + // Character bucket + enum Bucket { + C_INVALID, // Invalid input. + C_DIGIT, // digit. + C_IDENT, // Identifier character. + C_DASH, // A dash + C_DOT, // A dot (period). + }; + + if (cbuff) cbuff->reset(); + char const* start = _c; // save starting character location. + size_t idx = 0; // accumulator for index value. + + bool final = false; + while (! final && this->hasInput()) { + Bucket cb; + if (isdigit(*_c)) cb = C_DIGIT; + else if ('_' == *_c || isalpha(*_c)) cb = C_IDENT; + else if ('-' == *_c) cb = C_DASH; + else if ('.' == *_c) cb = C_DOT; + else cb = C_INVALID; + + if (C_INVALID == cb) { + msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in path.", *_c, *_c); + } else switch (state) { + case S_INIT: + switch (cb) { + case C_DIGIT: state = S_INDEX; idx = *_c - '0'; break; + case C_IDENT: state = S_TAG; break; + case C_DASH: msg::logf(zret, msg::WARN, "Dash not allowed as leading character for tag."); final = true; break; + case C_DOT: msg::logf(zret, msg::WARN, "Separator without preceding element."); final = true; break; + default: msg::logf(zret, msg::WARN, "Internal error: unexpected character %u in INIT state.", *_c); final = true; break; + } + break; + case S_INDEX: // reading an index. + if (C_DIGIT == cb) idx = 10 * idx + *_c - '0'; + else if (C_DOT == cb) { final = true; } + else { + msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in index element.", *_c, *_c); + final = true; + } + break; + case S_TAG: // reading a tag. + if (C_IDENT == cb || C_DIGIT == cb) ; // continue + else if (C_DASH == cb) state = S_DASH; + else if (C_DOT == cb) { final = true; } + else { // should never happen, but be safe. + msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in index element.", *_c, *_c); + final = true; + } + break; + case S_DASH: // dashes inside tag. + if (C_IDENT == cb || C_DIGIT == cb) state = S_TAG; + else if (C_DOT == cb) { + msg::log(zret, msg::WARN, "Trailing dash not allowed in tag element."); + final = true; + } else if (C_DASH != cb) { // should never happen, but be safe. + msg::logf(zret, msg::WARN, "Invalid character '%c' [%u] in index element.", *_c, *_c); + final = true; + } + break; + } + ++_c; + } + if (!zret.isOK()) { + zret = ERROR; + if (cbuff) cbuff->set(_c - 1, 1); + _c = 0; + _input.reset(); + } else if (S_INIT == state) { + zret = EOP; + } else if (S_TAG == state) { + zret = TAG; + if (cbuff) { + cbuff->set(start, _c - start); + // if @a final is set, then we parsed a dot separator. + // don't include it in the returned tag. + if (final) cbuff->_size -= 1; + } + } else if (S_INDEX == state) { + zret = INDEX; + if (cbuff) cbuff->_size = idx; + } else if (S_DASH == state) { + zret = ERROR; + msg::log(zret, msg::WARN, "Trailing dash not allowed in tag element."); + if (cbuff) cbuff->set(start, _c - start); + } + return zret; +} +// --------------------------------------------------------------------------- +Value +Configuration::getRoot() const { + const_cast(this)->_table.forceRootItem(); + return Value(*this, 0); +} + +Rv +Configuration::loadFromPath(char const* path) { + Rv zret; + Buffer buffer(0,0); + FILE* in = fopen(path, "r"); + + if (in) { + struct stat info; + if (0 == fstat(_fileno(in), &info)) { + // Must reserve 2 bytes at the end for FLEX terminator. + buffer = zret.result().alloc(info.st_size + 2); + if (buffer._ptr) { + size_t n; + if (0 < (n = fread(buffer._ptr, sizeof(char), info.st_size, in))) { + buffer._size = n+2; + memset(buffer._ptr + n, 0, 2); // required by FLEX + zret = Builder(zret.result()).build(buffer); + } else { + msg::logf_errno(zret, msg::WARN, "failed to read %" PRIu64 " bytes from configuration file '%s'", info.st_size, path); + } + } else { + msg::logf_errno(zret, msg::WARN, "failed to allocate buffer for configuration file '%s' - needed %" PRIu64 " bytes.", path, info.st_size); + } + } else { + msg::logf_errno(zret, msg::WARN, "failed to determine file information on '%s'", path); + } + } else { + msg::logf_errno(zret, msg::WARN, "failed to open configuration file '%s'", path); + } + return zret; +} + +}} // namespace ts::config diff --git a/lib/tsconfig/TsValue.h b/lib/tsconfig/TsValue.h new file mode 100644 index 00000000..b3d947b8 --- /dev/null +++ b/lib/tsconfig/TsValue.h @@ -0,0 +1,739 @@ +# if ! defined(TS_CONFIG_VALUE_HEADER) +# define TS_CONFIG_VALUE_HEADER + +/** @file + + TS Configuration API definition. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include +# include +# include +# include +# include + +namespace ts { namespace config { + +// Forward declares. +class Value; +class Path; + +namespace detail { + /** Class to provide a "pseudo bool" value. + This is used as the return type for the positive logical operator + (the converse of @c operator! ). This makes a class directly + usable in logical expressions. It is like a pointer but @b not + convertible to anything else, and so avoiding any undesirable + automatic conversions and the resulting ambiguities. + */ + struct PseudoBool { + typedef bool (PseudoBool::*Type)() const; ///< The type itself. + bool operator ! () const; ///< A method to use for the @c true value. + static Type const TRUE; ///< The @c true equivalent. + static Type const FALSE; ///< The @c false equivalent. + }; +} + +/// Type of value. +enum ValueType { + VoidValue, ///< No value, invalid. + ListValue, ///< List of values. + GroupValue, ///< Group of values. + StringValue, ///< Text string. + IntegerValue, ///< Integer. + PathValue, ///< Path. + // Update N_VALUE_TYPES if you change the last enum value !! +}; +/// Number of value types. +static size_t const N_VALUE_TYPES = PathValue + 1; + +/** A path to a value in a configuration. + */ +class Path { + friend class Value; +protected: + class ImplType : public IntrusivePtrCounter { + friend class Path; + public: + ImplType(); ///< Constructor. + protected: + /** Container for path elements. + We are subtle with our elements, which can be either a string + or a numeric index. By convention, if the pointer in the buffer is + @c NULL, then the size is a numeric index. Otherwise it's a name. + */ + typedef std::vector Elements; + Elements _elements; ///< Path elements. + }; +public: + typedef Path self; ///< Self reference type. + + Path(); ///< Default constructor. + + /// Append a string tag to the path. + self& append( + ConstBuffer const& tag ///< Text of tag. + ); + /// Append a numeric index to the path. + self& append( + size_t idx ///< Index. + ); + /// Reset to default constructed state. + self& reset(); + + /// Get the number of elements in this path. + size_t count() const; + + /// Access an element by @a index. + ConstBuffer const& operator [] ( + size_t index ///< Element index. + ) const; + + /** Parser for path text. + This is restartable so a path can be parsed in pieces. + @internal Sadly, FLEX is just too much overhead to be useful here. + */ + class Parser { + public: + typedef Parser self; ///< Self reference type. + + Parser(); ///< Default constructor. + /** Construct with input. + + This default constructs the Parser then calls @c setInput with + @a text. It is provided as a convenience as that will be the + common use case. + + @see setInput. + */ + Parser( + ConstBuffer const& text ///< Input text. + ); + + /** Set the input @a text. + Parsing state is reset and the next parsing call will + start at the beginning of @a text. + */ + self& setInput( + ConstBuffer const& text ///< Input buffer. + ); + + /// Parsing result. + enum Result { + ERROR, ///< Bad input. + TAG, ///< Path tag. + INDEX, ///< Path index. + EOP, ///< End Of Path. + }; + + /** Parse the next element in the path. + + @a cbuff may be @c NULL in which case no data about elements + is available. In general this should be called until @c EOP + or @c ERROR is returned, each call returning the next element. + + @return A parse @c Result. + - TAG: A tag was found. The start and length are stored in @a cbuff. + - INDEX: An index was found. The value is in @a cbuff._size. + - EOP: No more path elements were found. Do not continue parsing. + - ERROR: A syntax error was encountered. See the errata for detail. Do not continue parsing. + */ + Rv parse( + ConstBuffer* cbuff = 0 ///< [out] Parsed path element. + ); + + /// Check if input is available. + bool hasInput() const; + + protected: + ConstBuffer _input; ///< Current input buffer. + char const* _c; ///< Next input character. + }; +protected: + typedef IntrusivePtr ImplPtr; ///< Smart pointer to implementation. + ImplPtr _ptr; ///< Our instance. + /// Force an implementation instance and return a pointer to it. + ImplType* instance(); +}; + +namespace detail { + /// Null buffer, handy in several places. + extern Buffer const NULL_BUFFER; + /// Null buffer, handy in several places. + extern ConstBuffer const NULL_CONST_BUFFER; + /// Index type for value items in the global table. + typedef NumericType ValueIndex; + /// Index value that presents NULL (invalid value). + static ValueIndex const NULL_VALUE_INDEX = static_cast(-1); + /// Numeric type for configuration generation. + typedef NumericType Generation; + + /** Value type properties. + These are used as bit masks on elements of an array. + */ + static unsigned int const IS_VALID = 1; + static unsigned int const IS_LITERAL = 1<<1; + static unsigned int const IS_CONTAINER = 1<<2; + + /// Value type property table. + extern unsigned int const Type_Property[N_VALUE_TYPES]; + + /** A value in the configuration. + This is used in a global table so it handles all types of Values. + Members that are not used for scalars are designed to be @c NULL + pointers in that case. + */ + class ValueItem { + // Apparently the C++ standard, 7.3.1.2, states that unqualified + // friend classes only considers the current namespace, not any + // outer ones. So we have to fully qualify this. Blech. + friend class ts::config::Value; + friend class ValueTable; + public: + /// Default constructor. + ValueItem(); + /// Construct empty item of a specific type. + ValueItem(ValueType type); + /// Get item type. + ValueType getType() const; + protected: + ValueType _type; ///< Type of value. + ValueIndex _parent; ///< Table index of parent value. + ConstBuffer _text; ///< Text of value (if scalar). + ConstBuffer _name; ///< Local name of value, if available. + size_t _local_index; ///< Index among siblings. + int _srcLine; ///< Source line. + int _srcColumn; ///< Source column. + + /// Container for children of this item. + typedef std::vector ChildGroup; + /// Child items of this item. + ChildGroup _children; + /// Path if present. + Path _path; + + // This is for optimizing named access at some point in the future. + /// Hold a child item name in a table for fast lookup. + struct Name { + ConstBuffer _text; ///< Text of name. + ValueIndex _index; ///< Index of child. + }; + /// Container for child names. + typedef std::vector NameGroup; + /** Child names, if appropriate. + This is faulted in when needed, if this value is an aggregate with + named children. The list must be sorted on name so that it can be binary + searched for performance. + */ + NameGroup _names; + }; + + class ValueTable; + + /** Table of configuration values. + This holds all the values for a specific configuration. + */ + class ValueTableImpl : public IntrusivePtrCounter { + friend class ValueTable; + public: + typedef ValueTableImpl self; ///< Self reference type. + + ValueTableImpl(); ///< Constructor. + ~ValueTableImpl(); ///< Destructor. + protected: + /// Container for value items. + typedef std::vector ItemTable; + ItemTable _values; ///< All configuration values. + Generation _generation; ///< Generation number of configuration. + /// A group of buffers. + typedef std::vector BufferGroup; + /** Locally allocated buffers. + These are freed when this object is destroyed. + */ + BufferGroup _buffers; + + static ValueItem NULL_ITEM; ///< Null item for invalid access return. + }; + + /** Wrapper class for a table of configuration values. + @internal Really, this should be merged in to Configuration. The original + differences have evolved out of the implementation. + */ + class ValueTable { + public: + typedef ValueTable self; ///< Self reference type. + typedef ValueTableImpl ImplType; ///< Implementation type. + + /// Table size. + /// @return The number of value items in the table. + size_t size() const; + /// Generation. + /// @return The generation number. + Generation generation() const; + + /// Const access by index. + /// @return The value item at index @a idx. + ValueItem const& operator [] ( + ValueIndex idx ///< Index of item. + ) const; + /// Access by index. + /// @return The value item at index @a idx. + ValueItem& operator [] ( + ValueIndex idx ///< Index of item. + ); + + /// Force the existence of the root item in the table. + /// @return @c this object. + self& forceRootItem(); + /** Create a new item (value) with optional @a name + The table must contain @a parent. If @a name is omitted, the item + has an empty name. + @return Index of the new value item. + */ + Rv make( + ValueIndex parent, ///< Index of parent for item. + ValueType type, ///< Type of item. + ConstBuffer const& name = NULL_BUFFER ///< Name (may be empty). + ); + + /// Test for not table existence. + /// @return @c false if the implementation instance exists, @c true if not. + bool operator ! () const; + /// Test for table existence. + /// @return @c true if the implementation instance exists, @c false if not. + operator PseudoBool::Type() const; + /// Reset to default constructed state. + /// @return @c this object. + self& reset(); + + /** Allocate a local buffer. + This buffer will persist until the implementation instance + is destoyed. + @return The allocated buffer. + */ + Buffer alloc(size_t n); + protected: + typedef IntrusivePtr ImplPtr; ///< Smart pointer to implementation instance. + ImplPtr _ptr; ///< Implementation instance. + + /// Force an implementation instance and return a pointer to it. + ImplType* instance(); + }; +} // namespace detail + +/** Container for a configuration. + This is a wrapper class that holds a shared reference to a configuration. +*/ +class Configuration { + friend class Value; +public: + typedef Configuration self; ///< Self reference type. + + /** Check if configuration is (not) valid. + @return @c true if this configuration is invalid, @c false otherwise. + */ + bool operator ! () const; + /** Check if the configuration is valid. + @return The equivalent of @c true if this does @b not contain a value, + the equivalent of @c false if it does. + */ + operator detail::PseudoBool::Type () const; + /** Get the root @c Value of the configuration. + The root is always a group and has no name. + @return The root value. + */ + Value getRoot() const; + + /// Get the number of child values on the root value. + size_t childCount() const; + /** Root value child access by @a index + @return The child or a @c Void value if there is no child with @a name. + */ + Value operator [] ( + size_t idx ///< Index of child value. + ) const; + /** Root value child access by @a name. + @return The child or a @c Void value if there is no child with @a name. + */ + Value operator [] ( + ConstBuffer const& name + ) const; + /** Root value child access by @a name. + @return The child or a @c Void value if there is no child with @a name. + */ + Value operator [] ( + char const* name ///< Null terminated string. + ) const; + + /** Find a value. + @return The value if found, an void valid if not. + */ + Value find( + char const* path ///< configuration path to value. + ); + /** Load a configuration from a file. + + @note Check the returned errata for problems during configuration + load. It is probably not a good idea to use the configuration in + any error are reported. + @return A new @c Configuration and errata. + */ + static Rv loadFromPath( + char const* path ///< file system path. + ); + /** Allocate a local buffer of size @a n. + This buffer will persist until the implementation instance + is destroyed. + @return The allocated buffer. + */ + Buffer alloc( + size_t n ///< requested size of buffer. + ); +protected: + detail::ValueTable _table; ///< Table of values from the configuration. +}; + +/** This holds a value from the configuration. + + @internal It is critical that none of the type specific subclasses define any data members + so that instances can be freely converted to and from this base class. +*/ +class Value { + friend class Configuration; +public: + typedef Value self; ///< Self reference type. + /// Default constructors. + /// Creates an @c NULL instance. + Value(); + /// Destructor. + ~Value(); + + /// Get the type of value. + ValueType getType() const; + /// Test if this is a valid value. + /// @return @c true if this contains a value, @c false otherwise. + bool hasValue() const; + /** Operator form of @c hasValue. + @see hasValue + @return @c true if this does @b not contain a value, @c false if it does. + */ + bool operator ! () const; + /** Logical form of @c hasValue for use in logical expressions. + @see hasValue + @return The equivalent of @c true if this does @b not contain a value, + the equivalent of @c false if it does. + */ + operator detail::PseudoBool::Type () const; + + /** Get the value text. + @return The text in the configuration file for this item if the item + is a scalar, an empty buffer otherwise. + */ + ConstBuffer const& getText() const; + /// Set the @a text for this value. + self& setText( + ConstBuffer const& text + ); + + /** Get local name. + This gets the local name of the value. That is the name by which it + is known to its parent container. + + @internal Only works for groups now. It should be made to work + for lists. This would require allocating strings for each index, + which should be shared across values. For instance, all values + at index 1 should return the same string "1", not separately + allocated for each value. + */ + ConstBuffer const& getName() const; + /** Get local index. + This gets the local index for the value. This is the index which, + if used on the parent, would yield this value. + @return The local index. + */ + size_t getIndex() const; + + /// Test for a literal value. + /// @return @c true if the value is a literal, + /// @c false if it is a container or invalid. + bool isLiteral() const; + /// Test for value container. + /// @return @c true if the value is a container (can have child values), + /// @c false otherwise. + bool isContainer() const; + /// Get the parent value. + Value getParent() const; + /// Test if this is the root value for the configuration. + bool isRoot() const; + + /// Get the number of child values. + size_t childCount() const; + /** Child access by @a index + @return The child or a @c Void value if there is no child with @a name. + */ + Value operator [] ( + size_t idx ///< Index of child value. + ) const; + /** Child access by @a name. + @return The child or a @c Void value if there is no child with @a name. + */ + Value operator [] ( + ConstBuffer const& name + ) const; + /** Child access by @a name. + @return The child or a @c Void value if there is no child with @a name. + */ + Value operator [] ( + char const* name ///< Null terminated string. + ) const; + + /** @name Creating child values. + + These methods all take an optional @a name argument. This is + required if @c this is a @c Group and ignored if @c this is a @c + List. + + These methods will fail if + - @c this is not a container. + - @c this is a @c Group and no @a name is provided. + + @note Currently for groups, duplicate names are not + detected. The duplicates will be inaccessible by name but can + still be found by index. This is a problem but I am still + pondering the appropriate solution. + + @see isContainer + @return The new value, or an invalid value plus errata on failure. + + @internal I original had this as a single method, but changed to + separate per type. Overall less ugly because we can get the + arguments more useful. + */ + //@{ + /// Create a @c String value. + Rv makeString( + ConstBuffer const& text, ///< String content. + ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value. + ); + /// Create an @c Integer value. + Rv makeInteger( + ConstBuffer const& text, ///< Text of number. + ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value. + ); + /// Create a @c Group value. + Rv makeGroup( + ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value. + ); + /// Create a @c List value. + Rv makeList( + ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value. + ); + /// Create a @c Path value. + Rv makePath( + Path const& path, ///< Path. + ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value. + ); + /// Create a child by type. + /// Client must fill in any other required elements. + Rv makeChild( + ValueType type, ///< Type of child. + ConstBuffer const& name = detail::NULL_BUFFER///< Optional name of value. + ); + //@} + + /** Find a value. + @return The value if found, an void valid if not. + */ + Value find( + ConstBuffer const& path ///< Path relative to this value. + ); + /** Find a value. + @return The value if found, an void valid if not. + */ + Value find( + char const* path ///< Path relative to this value. + ); + /** Find a value using a precondensed path. + @return The value if found, an void valid if not. + */ + Value find( + Path const& path ///< Path relative to this value. + ); + + /** Reset to default constructed state. + @note This wrapper is reset, the value in the configuration is unchanged. + @return @c this object. + */ + self& reset(); + + /// Set source line. + /// @return @c this object. + self& setSourceLine( + int line ///< Line in source stream. + ); + /// Set source column. + /// @return @c this object. + self& setSourceColumn( + int col ///< Column in source stream. + ); + /// Set the source location. + self& setSource( + int line, ///< Line in source stream. + int col ///< Column in source stream. + ); + /// Get source line. + /// @return The line in the source stream for this value. + int getSourceLine() const; + /// Get source column. + /// @return The column in the source stream for this value. + int getSourceColumn() const; + +protected: + // Note: We store an index and not a pointer because a pointer will go stale + // if any items are added or removed from the underlying table. + // Also, by storing the configuration, we hold it in memory as long as a Value + // is in client hands. + Configuration _config; ///< The configuration for this value. + detail::ValueIndex _vidx; ///< Index of item. + + static Buffer const NULL_BUFFER; ///< Empty buffer to return on method failures. + + /// Construct from raw data. + Value( + Configuration cfg, ///< Source configuration. + detail::ValueIndex vidx ///< Index of value. + ); + + /** Get raw item pointer. + @note This pointer is unstable and must be recomputed on each method invocation. + @return The item pointer or @c NULL if this value is invalid. + */ + detail::ValueItem* item(); + /** Get constant raw item pointer. + @note This pointer is unstable and must be recomputed on each method invocation. + @return The item pointer or @c NULL if this value is invalid. + */ + detail::ValueItem const* item() const; +}; + +// Inline methods. +namespace detail { + inline bool ValueTable::operator ! () const { return ! _ptr; } + inline ValueTable::operator PseudoBool::Type () const { return _ptr ? PseudoBool::TRUE : PseudoBool::FALSE; } + inline size_t ValueTable::size() const { return _ptr ? _ptr->_values.size() : 0; } + inline Generation ValueTable::generation() const { return _ptr ? _ptr->_generation : Generation(0); } + inline ValueItem const& ValueTable::operator [] (ValueIndex idx) const { return const_cast(this)->operator [] (idx); } + inline ValueTable& ValueTable::reset() { _ptr = 0; return *this; } + + inline ValueItem::ValueItem() : _type(VoidValue), _text(0,0), _name(0,0) {} + inline ValueItem::ValueItem(ValueType type) : _type(type), _text(0,0), _name(0,0) {} + inline ValueType ValueItem::getType() const { return _type; } +} + +inline Value::~Value() { } +inline Value::Value() : _vidx(detail::NULL_VALUE_INDEX) {} +inline Value::Value(Configuration cfg, detail::ValueIndex vidx) : _config(cfg), _vidx(vidx) { } +inline bool Value::hasValue() const { return _config && _vidx != detail::NULL_VALUE_INDEX; } +inline Value::operator detail::PseudoBool::Type () const { return this->hasValue() ? detail::PseudoBool::TRUE : detail::PseudoBool::FALSE; } +inline bool Value::operator ! () const { return ! this->hasValue(); } +inline ValueType Value::getType() const { return this->hasValue() ? _config._table[_vidx]._type : VoidValue; } +inline ConstBuffer const& Value::getText() const { + return this->hasValue() ? _config._table[_vidx]._text : detail::NULL_CONST_BUFFER; +} +inline Value& Value::setText(ConstBuffer const& text) { + detail::ValueItem* item = this->item(); + if (item) item->_text = text; + return *this; +} +inline ConstBuffer const& Value::getName() const { + detail::ValueItem const* item = this->item(); + return item ? item->_name : detail::NULL_CONST_BUFFER; +} +inline size_t Value::getIndex() const { + detail::ValueItem const* item = this->item(); + return item ? item->_local_index : 0; +} + +inline bool Value::isLiteral() const { return 0 != (detail::IS_LITERAL & detail::Type_Property[this->getType()]); } +inline bool Value::isContainer() const { return 0 != (detail::IS_CONTAINER & detail::Type_Property[this->getType()]); } +inline Value Value::getParent() const { return this->hasValue() ? Value(_config, _config._table[_vidx]._parent) : Value(); } +inline bool Value::isRoot() const { return this->hasValue() && _vidx == 0; } +inline Value& Value::reset() { _config = Configuration(); _vidx = detail::NULL_VALUE_INDEX; return *this; } +inline detail::ValueItem* Value::item() { return this->hasValue() ? &(_config._table[_vidx]) : 0; } +inline detail::ValueItem const* Value::item() const { return const_cast(this)->item(); } +inline Value Value::operator [] (char const* name) const { return (*this)[ConstBuffer(name, strlen(name))]; } +inline size_t Value::childCount() const { + detail::ValueItem const* item = this->item(); + return item ? item->_children.size() : 0; +} +inline Value Value::find(char const* path) { return this->find(ConstBuffer(path, strlen(path))); } +inline int Value::getSourceLine() const { + detail::ValueItem const* item = this->item(); + return item ? item->_srcLine : 0; +} +inline int Value::getSourceColumn() const { + detail::ValueItem const* item = this->item(); + return item ? item->_srcColumn : 0; +} +inline Value& Value::setSourceLine(int line) { + detail::ValueItem* item = this->item(); + if (item) item->_srcLine = line; + return *this; +} +inline Value& Value::setSourceColumn(int col) { + detail::ValueItem* item = this->item(); + if (item) item->_srcColumn = col; + return *this; +} +inline Value& Value::setSource(int line, int col) { + detail::ValueItem* item = this->item(); + if (item) { + item->_srcLine = line; + item->_srcColumn = col; + } + return *this; +} + +inline Path::ImplType::ImplType() { } + +inline Path::Path() { } +inline Path::ImplType* Path::instance() { if (!_ptr) _ptr = new ImplType; return _ptr.get(); } +inline Path& Path::append(ConstBuffer const& tag) { this->instance()->_elements.push_back(tag); return *this; } +inline Path& Path::append(size_t index) { this->instance()->_elements.push_back(ConstBuffer(0, index)); return *this; } +inline size_t Path::count() const { return _ptr ? _ptr->_elements.size() : 0; } +inline ConstBuffer const& Path::operator [] (size_t idx) const { return _ptr ? _ptr->_elements[idx] : detail::NULL_CONST_BUFFER; } + +inline Path::Parser::Parser() : _input(0,0), _c(0) { } +inline Path::Parser::Parser( ConstBuffer const& text ) : _input(text), _c(text._ptr) { } +inline bool Path::Parser::hasInput() const { return _input._ptr && _input._ptr + _input._size > _c; } + +inline bool Configuration::operator ! () const { return ! _table; } +inline Configuration::operator detail::PseudoBool::Type() const { return _table.operator detail::PseudoBool::Type(); } +inline Value Configuration::find( char const* path ) { return this->getRoot().find(path); } +inline Buffer Configuration::alloc(size_t n) { return _table.alloc(n); } +inline size_t Configuration::childCount() const { return this->getRoot().childCount(); } +inline Value Configuration::operator [] (size_t idx) const { return (this->getRoot())[idx]; } +inline Value Configuration::operator [] ( ConstBuffer const& name ) const { return (this->getRoot())[name]; } +inline Value Configuration::operator [] ( char const* name ) const { return (this->getRoot())[name]; } + +}} // namespace ts::config + +# endif diff --git a/lib/tsconfig/test-1.tsconfig b/lib/tsconfig/test-1.tsconfig new file mode 100644 index 00000000..ee733a8e --- /dev/null +++ b/lib/tsconfig/test-1.tsconfig @@ -0,0 +1,18 @@ +thing-1 = { + name = "0\12\\\345678\9"; +} + +list = ( + { + prop1 = "Bob"; + prop2 = "Dave"; + }, + { + prop1 = "Bobby"; + prop2 = "Davy"; + }, + { + prop1 = "Robert"; + prop2 = "David"; + } +) \ No newline at end of file diff --git a/lib/tsconfig/test-tsconfig.cc b/lib/tsconfig/test-tsconfig.cc new file mode 100644 index 00000000..b07d232f --- /dev/null +++ b/lib/tsconfig/test-tsconfig.cc @@ -0,0 +1,49 @@ +/** @file + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +# include "tsconfig/TsValue.h" +# include +# include + +using ts::config::Configuration; +using ts::config::Value; + +inline std::ostream& operator << ( std::ostream& s, ts::ConstBuffer const& b ) { + if (b._ptr) s.write(b._ptr, b._size); + else s << b._size; + return s; +} + +int main(int argc, char ** argv) { + printf("Testing TsConfig\n"); + ts::Rv cv = Configuration::loadFromPath("test-1.tsconfig"); + if (cv.isOK()) { + Value v = cv.result().find("thing-1.name"); + if (v) { + std::cout << "thing-1.name = " << v.getText() << std::endl; + } else { + std::cout << "Failed to find 'name' in 'thing-1'" << std::endl; + } + } else { + std::cout << "Load failed" << std::endl + << cv.errata() + ; + } +} diff --git a/lib/wccp/Makefile.am b/lib/wccp/Makefile.am new file mode 100644 index 00000000..ccd09cb5 --- /dev/null +++ b/lib/wccp/Makefile.am @@ -0,0 +1,39 @@ +# +# Makefile.am for WCCP module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/proxy/api/ts + +#WCCP_DEFS = @WCCP_DEFS@ +#DEFS += $(WCCP_DEFS) + +noinst_LIBRARIES = libwccp.a +#noinst_PROGRAMS = test-cache + +libwccp_a_SOURCES = \ + Wccp.h \ + WccpLocal.h \ + WccpStatic.cc \ + WccpMsg.cc \ + WccpEndPoint.cc \ + WccpConfig.cc + +#test_cache_SOURCES = \ +# wccp-test-cache.cc diff --git a/lib/wccp/Makefile.in b/lib/wccp/Makefile.in new file mode 100644 index 00000000..1e650930 --- /dev/null +++ b/lib/wccp/Makefile.in @@ -0,0 +1,714 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Makefile.am for WCCP module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = lib/wccp +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libwccp_a_AR = $(AR) $(ARFLAGS) +libwccp_a_LIBADD = +am_libwccp_a_OBJECTS = WccpStatic.$(OBJEXT) WccpMsg.$(OBJEXT) \ + WccpEndPoint.$(OBJEXT) WccpConfig.$(OBJEXT) +libwccp_a_OBJECTS = $(am_libwccp_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libwccp_a_SOURCES) +DIST_SOURCES = $(libwccp_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib \ + -I$(top_srcdir)/proxy/api/ts + + +#WCCP_DEFS = @WCCP_DEFS@ +#DEFS += $(WCCP_DEFS) +noinst_LIBRARIES = libwccp.a +#noinst_PROGRAMS = test-cache +libwccp_a_SOURCES = \ + Wccp.h \ + WccpLocal.h \ + WccpStatic.cc \ + WccpMsg.cc \ + WccpEndPoint.cc \ + WccpConfig.cc + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/wccp/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign lib/wccp/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libwccp.a: $(libwccp_a_OBJECTS) $(libwccp_a_DEPENDENCIES) + -rm -f libwccp.a + $(libwccp_a_AR) libwccp.a $(libwccp_a_OBJECTS) $(libwccp_a_LIBADD) + $(RANLIB) libwccp.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WccpConfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WccpEndPoint.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WccpMsg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WccpStatic.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + + +#test_cache_SOURCES = \ +# wccp-test-cache.cc + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/wccp/Wccp.h b/lib/wccp/Wccp.h new file mode 100644 index 00000000..1ea15b98 --- /dev/null +++ b/lib/wccp/Wccp.h @@ -0,0 +1,512 @@ +# if ! defined(ATS_WCCP_API_HEADER) +# define ATS_WCCP_API_HEADER + +/** @file + WCCP (v2) support API. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include +# include +# include +# include +// Nasty, defining this with no prefix. The value is still available +// in TS_VERSION_STRING. +# undef VERSION + +// INADDR_ANY +# include + +/// WCCP Support. +namespace wccp { + +/// Forward declare implementation classes. +class Impl; +class CacheImpl; +class RouterImpl; + +/// Namespace for implementation details. +namespace detail { + /// Cache implementation details. + namespace cache { + class GroupData; + } + namespace router { + class GroupData; + } +} + +/// Basic time unit for WCCP in seconds +/// @note Sec 4.14: HERE_I_AM_T. +static time_t const TIME_UNIT = 10; +static time_t const ASSIGN_WAIT = (3 * TIME_UNIT) / 2; +static time_t const RAPID_TIME = TIME_UNIT/10; + +/// Service group related constants. +/// @internal In a struct so enum values can be imported to more than +/// one class. +struct ServiceConstants { + /// Methods for forwarding intercepted packets to cache. + /// @internal Enumerations values match protocol values. + enum PacketStyle { + NO_PACKET_STYLE = 0, ///< Undefined or invalid. + GRE = 1, ///< GRE tunnel only. [default] + L2 = 2, ///< L2 rewrite only. + GRE_OR_L2 = 3 ///< L2 rewrite or GRE tunnel. + }; + + /// Cache assignment supported methods. + /// @internal Enumerations values match protocol values. + enum CacheAssignmentStyle { + NO_CACHE_ASSIGN_STYLE = 0, ///< Undefined or invalid. + HASH_ONLY = 1, ///< Use only hash assignment. [default] + MASK_ONLY = 2, ///< Use only mask assignment. + HASH_OR_MASK = 3 ///< Use hash or mask assignment. + }; +}; + +/** Service group definition. + + Also used as serialized layout internally by ServiceGroupElt. This is kept + in serialized form because it is copied to and from message data far more + often then it is accessed directly. + */ +class ServiceGroup : public ServiceConstants { +public: + typedef ServiceGroup self; ///< Self reference type. + + /// Type of service. + enum Type { + STANDARD = 0, ///< Well known service. + DYNAMIC = 1 ///< Dynamic (locally defined) service. + }; + + /// Result codes for service definition. + enum Result { + DEFINED = 0, ///< Service group was created by the call. + EXISTS = 1, ///< Service group already existed. + CONFLICT = 2 ///< Service group existed but didn't match new definition. + }; + + /// @name Well known (standard) services. + //@{ + /// HTTP + static uint8_t const HTTP = 0; + //@} + /// Service IDs of this value or less are reserved. + static uint8_t const RESERVED = 50; + + /// Number of ports in component (defined by protocol). + static size_t const N_PORTS = 8; + + /// @name Flag mask values. + //@{ + /// Source IP address hash + static uint32_t const SRC_IP_HASH = 1<<0; + /// Destination IP address hash + static uint32_t const DST_IP_HASH = 1<<1; + /// Source port hash. + static uint32_t const SRC_PORT_HASH = 1<<2; + /// Destination port hash + static uint32_t const DST_PORT_HASH = 1<<3; + /// @a m_ports has port information. + static uint32_t const PORTS_DEFINED = 1<<4; + /// @a m_ports has source ports (otherwise destination ports). + static uint32_t const PORTS_SOURCE = 1<<5; + /// Alternate source IP address hash + static uint32_t const SRC_IP_ALT_HASH = 1<<8; + /// Alternate destination IP address hash + static uint32_t const DST_IP_ALT_HASH = 1<<9; + /// Alternate source port hash + static uint32_t const SRC_PORT_ALT_HASH = 1<<10; + /// Alternate destination port hash + static uint32_t const DST_PORT_ALT_HASH = 1<<11; + /// All hash related flags. + static uint32_t const HASH_FLAGS = + SRC_IP_HASH | DST_IP_HASH | SRC_PORT_HASH | DST_PORT_HASH + | SRC_IP_ALT_HASH | DST_IP_ALT_HASH | SRC_PORT_ALT_HASH | DST_PORT_ALT_HASH + ; + //@} + + /// Default constructor - no member initialization. + ServiceGroup(); + /// Test for equivalent. + bool operator == (self const& that) const; + /// Test for not equivalent. + bool operator != (self const& that) const; + + /// @name Accessors + //@{ + ServiceGroup::Type getSvcType() const; ///< Get service type field. + /** Set the service type. + If @a svc is @c SERVICE_STANDARD then all fields except the + component header and service id are set to zero as required + by the protocol. + */ + self& setSvcType(ServiceGroup::Type svc); + + uint8_t getSvcId() const; ///< Get service ID field. + self& setSvcId(uint8_t id); ///< Set service ID field to @a id. + + uint8_t getPriority() const; ///< Get priority field. + self& setPriority(uint8_t pri); ///< Set priority field to @a p. + + uint8_t getProtocol() const; ///< Get protocol field. + self& setProtocol(uint8_t p); ///< Set protocol field to @a p. + + uint32_t getFlags() const; ///< Get flags field. + self& setFlags(uint32_t f); ///< Set the flags flags in field to @a f. + /// Set the flags in the flag field that are set in @a f. + /// Other flags are unchanged. + self& enableFlags(uint32_t f); + /// Clear the flags in the flag field that are set in @a f. + /// Other flags are unchanged. + self& disableFlags(uint32_t f); + + /// Get a port value. + uint16_t getPort( + int idx ///< Index of target port. + ) const; + /// Set a port value. + self& setPort( + int idx, ///< Index of port. + uint16_t port ///< Value for port. + ); + /// Zero (clear) all ports. + self& clearPorts(); + //@} + +protected: + uint8_t m_svc_type; ///< @ref Type. + uint8_t m_svc_id; ///< ID for service type. + uint8_t m_priority; ///< Redirection priority ordering. + uint8_t m_protocol; ///< IP protocol for service. + uint32_t m_flags; ///< Flags. + uint16_t m_ports[N_PORTS]; ///< Service ports. +}; + +/// Security component option (sub-type) +enum SecurityOption { + SECURITY_NONE = 0, ///< No security @c WCCP2_NO_SECURITY + SECURITY_MD5 = 1 ///< MD5 security @c WCCP2_MD5_SECURITY +}; + +class EndPoint { +public: + typedef EndPoint self; ///< Self reference type. + typedef Impl ImplType; ///< Implementation type. + + /** Set the identifying IP address. + This is also used as the address for the socket. + */ + self& setAddr( + uint32_t addr ///< IP address. + ); + + /** Check if this endpoint is ready to use. + @return @c true if the address has been set and services + have been added. + */ + bool isConfigured() const; + + /** Open a socket for communications. + + If @a addr is @c INADDR_ANY then the identifying address is used. + If that is not set this method will attempt to find an arbitrary + local address and use that as the identifying address. + + Otherwise @a addr replaces any previously set address. + + @return 0 on success, -ERRNO on failure. + @see setAddr + */ + int open( + uint32_t addr = INADDR_ANY ///< Local IP address for socket. + ); + + /// Get the internal socket. + /// Useful primarily for socket options and using + /// in @c select. + int getSocket() const; + + /// Use MD5 based security with @a key. + void useMD5Security( + char const* key ///< Shared hash key. + ); + /// Use MD5 based security with @a key. + void useMD5Security( + ts::ConstBuffer const& key ///< Shared hash key. + ); + + /// Perform house keeping, including sending outbound messages. + int housekeeping(); + + /// Recieve and process a message on the socket. + /// @return 0 for success, -ERRNO on system error. + ts::Rv handleMessage(); + +protected: + /// Default constructor. + EndPoint(); + /// Copy constructor. + EndPoint(self const& that); + /// Force virtual destructor + virtual ~EndPoint(); + + ts::IntrusivePtr m_ptr; ///< Implementation instance. + + /** Get a pointer to the implementation instance, creating it if needed. + @internal This is paired with @c make so that the implementation check + can be done non-virtually inline, while still allowing the actual + implementation instantiation to be virtual so the correct type is + created. + */ + ImplType* instance(); + + virtual ImplType* make() = 0; ///< Create a new implementation instance. +}; + +class Cache : public EndPoint { +public: + typedef Cache self; ///< Self reference type. + typedef EndPoint super; ///< Parent type. + typedef CacheImpl ImplType; ///< Implementation type. + + class Service; + + /// Default constructor. + Cache(); + /// Destructor + ~Cache(); + + /// Define services from a configuration file. + ts::Errata loadServicesFromFile( + char const* path ///< Path to file. + ); + + /** Define a service group. + + Return a service reference object which references the group. + + If @a result is not @c NULL then its target is set to + - @c ServiceGroup::DEFINED if the service was created. + - @c ServiceGroup::EXISTS if the service matches the existing service. + - @c ServiceGroup::CONFLICT if the service doesn't match the existing service. + */ + Service defineServiceGroup( + ServiceGroup const& svc, ///< Service group description. + ServiceGroup::Result* result = 0 + ); + + /** Add a seed router to the service group. + + A seed router is one that is defined at start up and is where + initial messages will be sent. Other routers will be added as + discovered. The protocol cannot start successfully without at + least one seed router. + + Seed routers are removed when a reply is received from that router. + + */ + self& addSeedRouter( + uint8_t id, ///< Service group ID. + uint32_t addr ///< IP address of router. + ); + + /// Number of seconds until next housekeeping activity is due. + time_t waitTime() const; +protected: + /// Get implementation instance, creating if needed. + ImplType* instance(); + /// Get the current implementation instance cast to correct type. + ImplType* impl(); + /// Get the current implementation instance cast to correct type. + ImplType const* impl() const; + /// Create a new implementation instance. + super::ImplType* make(); +}; + +/** Hold a reference to a service group in this end point. + This is useful when multiple operations are to be done on the + same group, rather than doing a lookup by id every time. +*/ +class Cache::Service : public ServiceConstants { +public: + typedef Service self; ///< Self reference type. + + /// Default constructor (invalid reference). + Service(); + + /// Add an address for a seed router. + self& addSeedRouter( + uint32_t addr ///< Router IP address. + ); + /// Set the security key. + self& setKey( + char const* key /// Shared key. + ); + /// Set the service local security option. + self& setSecurity( + SecurityOption opt ///< Security style to use. + ); + /// Set intercepted packet forwarding style. + self& setForwarding( + PacketStyle style ///< Type of forwarding supported. + ); + /// Enable or disable packet return by layer 2 rewrite. + self& setReturn( + PacketStyle style ///< Type of return supported. + ); + + /// Set cache assignment style. + self& setCacheAssignment( + CacheAssignmentStyle style ///< Style to use. + ); + + +private: + Service(Cache const& cache, detail::cache::GroupData& group); + Cache m_cache; ///< Parent cache. + detail::cache::GroupData* m_group; ///< Service Group data. + friend class Cache; +}; + + +class Router : public EndPoint { +public: + typedef Router self; ///< Self reference type. + typedef EndPoint super; ///< Parent type. + typedef RouterImpl ImplType; ///< Implementation type. + + /// Default constructor + Router(); + /// Destructor. + ~Router(); + + /// Transmit pending messages. + int sendPendingMessages(); +protected: + /// Get implementation instance, creating if needed. + ImplType* instance(); + /// Get the current implementation instance cast to correct type. + ImplType* impl(); + /// Create a new implementation instance. + super::ImplType* make(); +}; + +// ------------------------------------------------------ +inline bool +ServiceGroup::operator != (self const& that) const { + return !(*this == that); +} + +inline ServiceGroup::Type +ServiceGroup::getSvcType() const { + return static_cast(m_svc_type); +} + +inline uint8_t +ServiceGroup::getSvcId() const { + return m_svc_id; +} + +inline ServiceGroup& +ServiceGroup::setSvcId(uint8_t id) { + m_svc_id = id; + return *this; +} + +inline uint8_t +ServiceGroup::getPriority() const { + return m_priority; +} + +inline ServiceGroup& +ServiceGroup::setPriority(uint8_t pri) { + m_priority = pri; + return *this; +} + +inline uint8_t +ServiceGroup::getProtocol() const { + return m_protocol; +} + +inline ServiceGroup& +ServiceGroup::setProtocol(uint8_t proto) { + m_protocol = proto; + return *this; +} + +inline uint32_t +ServiceGroup::getFlags() const { + return ntohl(m_flags); +} + +inline ServiceGroup& +ServiceGroup::setFlags(uint32_t flags) { + m_flags = htonl(flags); + return *this; +} + +inline ServiceGroup& +ServiceGroup::enableFlags(uint32_t flags) { + m_flags |= htonl(flags); + return *this; +} + +inline ServiceGroup& +ServiceGroup::disableFlags(uint32_t flags) { + m_flags &= ~htonl(flags); + return *this; +} + +inline uint16_t +ServiceGroup::getPort (int idx) const { + return ntohs(m_ports[idx]); +} + +inline ServiceGroup& +ServiceGroup::setPort(int idx, uint16_t port) { + m_ports[idx] = htons(port); + return *this; +} + +inline ServiceGroup& +ServiceGroup::clearPorts() { + memset(m_ports, 0, sizeof(m_ports)); + return *this; +} + +inline Cache::Service::Service() : m_group(0) { } + +inline Cache::Service::Service( + Cache const& cache, + detail::cache::GroupData& group +) : m_cache(cache), m_group(&group) { +} + +inline void EndPoint::useMD5Security(char const* key) { + this->useMD5Security(ts::ConstBuffer(key, strlen(key))); +} +// ------------------------------------------------------ + +} // namespace Wccp +# endif // include guard. diff --git a/lib/wccp/WccpConfig.cc b/lib/wccp/WccpConfig.cc new file mode 100644 index 00000000..3eb5abdc --- /dev/null +++ b/lib/wccp/WccpConfig.cc @@ -0,0 +1,792 @@ +/** @file WCCP Configuration processing. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "WccpLocal.h" +# include +# include +# include +# include +# include +# include + +using ts::config::Configuration; +using ts::config::Value; + +// Support that must go in the standard namespace. +namespace std { + +inline ostream& operator << ( ostream& s, ts::ConstBuffer const& b ) { + if (b._ptr) s.write(b._ptr, b._size); + else s << b._size; + return s; +} + +} // namespace std + +// WCCP related things that are file local. +namespace { +using namespace wccp; + +// Scratch global list of seed router addresses. +// Yeah, not thread safe, but it's just during configuration load. +// Logic somewhat changed - can we move in to the load method? +std::vector Seed_Router; + +// Names used for various elements and properties. +static char const * const SVC_NAME = "service"; + +static char const * const SVC_PROP_ID = "id"; +static char const * const SVC_PROP_TYPE = "type"; +static char const * const SVC_PROP_PRIORITY = "priority"; +static char const * const SVC_PROP_PROTOCOL = "protocol"; +static char const * const SVC_PROP_FLAGS = "flags"; +static char const * const SVC_PROP_PRIMARY_HASH = "primary-hash"; +static char const * const SVC_PROP_ALT_HASH = "alt-hash"; +static char const * const SVC_PROP_PORTS = "ports"; +static char const * const SVC_PROP_PORT_TYPE = "port-type"; +static char const * const SVC_PROP_SECURITY = "security"; +static char const * const SVC_PROP_ROUTERS = "routers"; +static char const * const SVC_PROP_FORWARD = "forward"; +static char const * const SVC_PROP_RETURN = "return"; +static char const * const SVC_PROP_ASSIGN = "assignment"; + +static char const * const SECURITY_PROP_OPTION = "option"; +static char const * const SECURITY_PROP_KEY = "key"; + +/// Helper structure for processing configuration strings. +struct CfgString { + char const* m_text; ///< Text value of the option. + bool m_found; ///< String was found. +}; +typedef std::vector CfgOpts; + +# define N_OPTS(x) (sizeof(x) / sizeof(*x)) + +CfgString FORWARD_OPTS[] = { { "gre" } , { "l2" } }; +size_t const N_FORWARD_OPTS = sizeof(FORWARD_OPTS)/sizeof(*FORWARD_OPTS); + +CfgString RETURN_OPTS[] = { { "gre" } , { "l2" } }; +size_t const N_RETURN_OPTS = sizeof(RETURN_OPTS)/sizeof(*RETURN_OPTS); + +CfgString ASSIGN_OPTS[] = { { "hash" } , { "mask" } }; + +CfgString HASH_OPTS[] = { { "src_ip" } , { "dst_ip" } , { "src_port" } , { "dst_port" } }; + +ts::Errata::Code code_max(ts::Errata const& err) { + ts::Errata::Code zret = std::numeric_limits::min(); + ts::Errata::const_iterator spot = err.begin(); + ts::Errata::const_iterator limit = err.end(); + for ( ; spot != limit ; ++spot ) + zret = std::max(zret, spot->getCode()); + return zret; +} + +struct ValueNamePrinter { + Value const& _v; + ValueNamePrinter(Value const& v) : _v(v) {} +}; + +std::ostream& operator << ( std::ostream& out, ValueNamePrinter const& v ) { + ts::ConstBuffer const& name = v._v.getName(); + if (name._ptr) out << "'" << name << "'"; + else out << v._v.getIndex(); + return out; +} + +ts::Errata::Message File_Syntax_Error(int line, char const* text) { + std::ostringstream out; + out << "Service configuration error. Line " + << line + << ": " << text + ; + return ts::Errata::Message(1, LVL_FATAL, out.str()); +} + +ts::Errata::Message File_Read_Error(char const* text) { + std::ostringstream out; + out << "Failed to parse configuration file." + << ": " << text + ; + return ts::Errata::Message(2, LVL_FATAL, out.str()); +} + +ts::Errata::Message Unable_To_Create_Service_Group(int line) { + std::ostringstream out; + out << "Unable to create service group at line " << line + << " because of configuration errors." + ; + return ts::Errata::Message(23, LVL_FATAL, out.str()); +} + +ts::Errata::Message Services_Not_Found() { + return ts::Errata::Message(3, LVL_INFO, "No services found in configuration."); +} + +ts::Errata::Message Services_Not_A_Sequence() { + return ts::Errata::Message(4, LVL_INFO, "The 'services' setting was not a list nor array."); +} + +ts::Errata::Message Service_Not_A_Group(int line) { + std::ostringstream out; + out << "'" << SVC_NAME << "' must be a group at line " + << line << "." + ; + return ts::Errata::Message(5, LVL_WARN, out.str()); +} + +ts::Errata::Message Service_Type_Defaulted(wccp::ServiceGroup::Type type, int line) { + std::ostringstream out; + out << "'type' not found in " << SVC_NAME << " at line " + << line << "' -- defaulting to " + << ( type == wccp::ServiceGroup::STANDARD ? "STANDARD" : "DYNAMIC" ) + ; + return ts::Errata::Message(6, LVL_INFO, out.str()); +} + +ts::Errata::Message Service_Type_Invalid(ts::ConstBuffer const& text, int line) { + std::ostringstream out; + out << "Service type '" << text + << "' at line " << line + << " invalid. Must be \"STANDARD\" or \"DYNAMIC\"" + ; + return ts::Errata::Message(7, LVL_WARN, out.str()); +} + +ts::Errata::Message Prop_Not_Found(char const* prop_name, char const* group_name, int line) { + std::ostringstream out; + out << "Required '" << prop_name << "' property not found in '" + << group_name << "' at line " << line << "." + ; + return ts::Errata::Message(8, LVL_WARN, out.str()); +} + +ts::Errata::Message Prop_Invalid_Type( + Value const& prop_cfg, + ts::config::ValueType expected +) { + std::ostringstream out; + out << "'" << prop_cfg.getName() << "' at line " << prop_cfg.getSourceLine() + << " is of type '" << prop_cfg.getType() + << "' instead of required type '" << expected << "'." + ; + return ts::Errata::Message(9, LVL_WARN, out.str()); +} + +ts::Errata::Message Prop_List_Invalid_Type( + Value const& elt_cfg, ///< List element. + ts::config::ValueType expected +) { + std::ostringstream out; + out << "Element " << ValueNamePrinter(elt_cfg) + << " at line " << elt_cfg.getSourceLine() + << " in the aggregate property '" << elt_cfg.getParent().getName() + << "' is of type '" << elt_cfg.getType() + << "' instead of required type '" << expected << "'." + ; + return ts::Errata::Message(9, LVL_WARN, out.str()); +} + +ts::Errata::Message Svc_Prop_Out_Of_Range( + char const* name, + Value const& elt_cfg, + int v, int min, int max +) { + std::ostringstream out; + out << "Service property '" << name + << "' at line " << elt_cfg.getSourceLine() + << " has a value " << v + << " that is not in the allowed range of " + << min << ".." << max << "." + ; + return ts::Errata::Message(10, LVL_WARN, out.str()); +} + +ts::Errata::Message Svc_Prop_Ignored(char const* name, int line) { + std::ostringstream out; + out << "Service property '" << name << "' at line " << line + << " ignored because the service is of type standard." + ; + return ts::Errata::Message(11, LVL_INFO, out.str()); +} + +ts::Errata::Message Svc_Flags_No_Hash_Set(int line) { + std::ostringstream out; + out << "Service flags have no hash set at line " << line + ; + return ts::Errata::Message(12, LVL_WARN, out.str()); +} + +ts::Errata::Message Svc_Flags_Ignored(int line) { + std::ostringstream out; + out << "Invalid service flags at line " << line + << " ignored." + ; + return ts::Errata::Message(13, LVL_INFO, out.str()); +} + +ts::Errata::Message Svc_Ports_Too_Many(int line, int n) { + std::ostringstream out; + out << "Excess ports ignored at line " << line + << ". " << n << " ports specified, only" + << wccp::ServiceGroup::N_PORTS << " supported." + ; + return ts::Errata::Message(14, LVL_INFO, out.str()); +} + +ts::Errata::Message Svc_Ports_Malformed(int line) { + std::ostringstream out; + out << "Port value ignored (not a number) at line " << line + << "." + ; + return ts::Errata::Message(15, LVL_INFO, out.str()); +} + +ts::Errata::Message Svc_Ports_None_Valid(int line) { + std::ostringstream out; + out << "A '" << SVC_PROP_PORTS << "' property was found at line " + << line << " but none of the ports were valid." + ; + return ts::Errata::Message(17, LVL_WARN, out.str()); +} + +ts::Errata::Message Svc_Ports_Not_Found(int line) { + std::ostringstream out; + out << "Ports not found in service at line " << line + << ". Ports must be defined for a dynamic service."; + return ts::Errata::Message(18, LVL_WARN, out.str()); +} + +ts::Errata::Message Svc_Prop_Ignored_In_Standard(const char* name, int line) { + std::ostringstream out; + out << "Service property '" << name << "' at line " << line + << " ignored because the service is of type STANDARD." + ; + return ts::Errata::Message(19, LVL_INFO, out.str()); +} + +ts::Errata::Message Security_Opt_Invalid(ts::ConstBuffer const& text, int line) { + std::ostringstream out; + out << "Security option '" << text + << "' at line " << line + << " is invalid. It must be 'none' or 'md5'." + ; + return ts::Errata::Message(20, LVL_WARN, out.str()); +} + +ts::Errata::Message Value_Malformed(char const* name, char const* text, int line) { + std::ostringstream out; + out << "'" << name << "' value '" << text + << "' malformed at line " << line << "." + ; + return ts::Errata::Message(21, LVL_WARN, out.str()); +} + +ts::Errata::Message No_Valid_Routers(int line) { + std::ostringstream out; + out << "No valid IP address for routers found for Service Group at line " + << line << "." + ; + return ts::Errata::Message(22, LVL_WARN, out.str()); +} + +ts::Errata::Message Ignored_Option_Value( + ts::ConstBuffer const& text, + ts::ConstBuffer const& name, + int line +) { + std::ostringstream out; + out << "Value '" << text << "' at line " << line + << " was ignored because it is not a valid option for '" + << name << "'." + ; + return ts::Errata::Message(24, LVL_INFO, out.str()); +} + +ts::Errata::Message Ignored_Opt_Errors( + char const* name, + int line +) { + std::ostringstream out; + out << "Errors in '" << name << "' at line " << line + << " were ignored." + ; + return ts::Errata::Message(28, LVL_INFO, out.str()); +} + +ts::Errata::Message List_Valid_Opts( + ts::ConstBuffer const& name, + int line, + CfgString* values, + size_t n +) { + std::ostringstream out; + out << "Valid values for the '" << name << "' property at line " << line + << " are: " + ; + out << '"' << values[0].m_text << '"'; + for ( size_t i = 1 ; i < n ; ++i ) + out << ", \"" << values[i].m_text << '"'; + out << '.'; + return ts::Errata::Message(29, LVL_INFO, out.str()); +} + +ts::Errata::Message Port_Type_Invalid(ts::ConstBuffer const& text, int line) { + std::ostringstream out; + out << "Value '" << text + << "' at line " << line + << "for property '" << SVC_PROP_PORT_TYPE + << "' is invalid. It must be 'src' or 'dst'." + ; + return ts::Errata::Message(30, LVL_WARN, out.str()); +} + +} // anon namespace + +namespace wccp { + +inline bool operator == ( ts::ConstBuffer const& b, char const* text ) { + return 0 == strncasecmp(text, b._ptr, b._size); +} + +inline bool operator == ( char const* text, ts::ConstBuffer const& b ) { + return 0 == strncasecmp(text, b._ptr, b._size); +} + +ts::Errata +load_option_set(Value const& setting, CfgString* opts, size_t count) { + ts::Errata zret; + CfgString* spot; + CfgString* limit = opts + count; + ts::ConstBuffer const& name = setting.getName(); + int src_line = setting.getSourceLine(); + + // Clear all found flags. + for ( spot = opts ; spot < limit ; ++spot ) spot->m_found = false; + + // Walk through the strings in the setting. + if (setting.isContainer()) { + int nr = setting.childCount(); + bool list_opts = false; + for ( int i = 0 ; i < nr ; ++i ) { + Value item = setting[i]; + if (ts::config::StringValue == item.getType()) { + ts::ConstBuffer text = item.getText(); + for ( spot = opts ; spot < limit ; ++spot ) { + if (spot->m_text == text) { + spot->m_found = true; + break; + } + } + if (spot >= limit) { + zret.push(Ignored_Option_Value(text, name, item.getSourceLine())); + list_opts = true; + } + } else { + zret.push(Prop_Invalid_Type(setting, ts::config::StringValue)); + } + } + if (list_opts) + zret.push(List_Valid_Opts(name, src_line, opts, count)); + } else { + zret.push(Prop_Invalid_Type(setting, ts::config::ListValue)); + } + return zret; +} + +/** On success this returns a non @c NULL pointer if the MD5 option is + set. In that case the pointer points at the MD5 key. Otherwise + the option was none and the pointer is @c NULL + */ +ts::Rv +load_security ( + Value const& setting ///< Security setting. +) { + ts::Rv zret; + int src_line; + ts::ConstBuffer text; + + zret.result().set(0,0); + + src_line = setting.getSourceLine(); + if (ts::config::GroupValue == setting.getType()) { + Value opt = setting[SECURITY_PROP_OPTION]; + if (opt) { + if (ts::config::StringValue == opt.getType()) { + text = opt.getText(); + if ("none" == text) { + } else if ("md5" == text) { + Value key = setting[SECURITY_PROP_KEY]; + if (key) { + if (ts::config::StringValue == key.getType()) { + zret = key.getText(); + } else { + zret.push(Prop_Invalid_Type(key, ts::config::StringValue)); + } + } else { + zret.push(Prop_Not_Found(SECURITY_PROP_KEY, SVC_PROP_SECURITY, src_line)); + } + } else { + zret.push(Security_Opt_Invalid(text, opt.getSourceLine())); + } + } else { + zret.push(Prop_Invalid_Type(opt, ts::config::StringValue)); + } + } else { + zret.push(Prop_Not_Found(SECURITY_PROP_OPTION, SVC_PROP_SECURITY, src_line)); + } + } else { + zret.push(Prop_Invalid_Type(setting, ts::config::GroupValue)); + } + return zret; +} + +/// Process a router address list. +ts::Errata +load_routers ( + Value const& setting, ///< Source of addresses. + std::vector& addrs ///< Output list +) { + ts::Errata zret; + char const* text; + static char const * const NAME = "IPv4 Address"; + + if (setting.isContainer()) { + int nr = setting.childCount(); + for ( int i = 0 ; i < nr ; ++i ) { + Value const& addr_cfg = setting[i]; + int addr_line = addr_cfg.getSourceLine(); + in_addr addr; + if (ts::config::StringValue == addr_cfg.getType()) { + text = addr_cfg.getText()._ptr; + if (inet_aton(text, &addr)) addrs.push_back(addr.s_addr); + else zret.push(Value_Malformed(NAME, text, addr_line)); + } else { + zret.push(Prop_List_Invalid_Type(addr_cfg, ts::config::StringValue)); + } + } + } else { + zret.push(Prop_Invalid_Type(setting, ts::config::ListValue)); + } + return zret; +} + +ts::Errata +CacheImpl::loadServicesFromFile(char const* path) { + ts::Errata zret; + int src_line = 0; // scratch for local source line caching. + std::vector routers; // scratch per service loop. + Value prop; // scratch var. + + ts::Rv cv = Configuration::loadFromPath(path); + if (!cv.isOK()) return cv.errata(); + + ts::config::Configuration cfg = cv.result(); + Value svc_list = cfg.find("services"); + // No point in going on from here. + if (!svc_list) return Services_Not_Found(); + + if (!svc_list.isContainer()) return Services_Not_A_Sequence(); + + // Check for global (default) security setting. + if ((prop = cfg[SVC_PROP_SECURITY]).hasValue()) { + ts::Rv rv = load_security(prop); + if (rv.isOK()) this->useMD5Security(rv); + else zret.pull(rv.errata()); + } + + if ((prop = cfg[SVC_PROP_ROUTERS]).hasValue()) { + zret.pull(load_routers(prop, Seed_Router).doNotLog()); + } + + int idx, nsvc; + for ( idx = 0, nsvc = svc_list.childCount() ; idx < nsvc ; ++idx ) { + int x; // scratch int. + char const* md5_key = 0; + ts::ConstBuffer text; + SecurityOption security_style = SECURITY_NONE; + bool use_group_local_security = false; + Value const& svc_cfg = svc_list[idx]; + int svc_line = svc_cfg.getSourceLine(); + ServiceGroup svc_info; + + if (ts::config::GroupValue != svc_cfg.getType()) { + zret.push(Service_Not_A_Group(svc_line)); + continue; + } + + // Get the service ID. + if ((prop = svc_cfg[SVC_PROP_ID]).hasValue()) { + if (ts::config::IntegerValue == prop.getType()) { + x = atoi(prop.getText()._ptr); + if (0 <= x && x <= 255) + svc_info.setSvcId(x); + else + zret.push(Svc_Prop_Out_Of_Range(SVC_PROP_ID, prop, x, 0, 255)); + } else { + zret.push(Prop_Invalid_Type(prop, ts::config::IntegerValue)); + } + } else { + zret.push(Prop_Not_Found(SVC_PROP_ID, SVC_NAME, svc_line)); + } + + // Service type. + if ((prop = svc_cfg[SVC_PROP_TYPE]).hasValue()) { + if (ts::config::StringValue == prop.getType()) { + text = prop.getText(); + if ("DYNAMIC" == text) + svc_info.setSvcType(ServiceGroup::DYNAMIC); + else if ("STANDARD" == text) + svc_info.setSvcType(ServiceGroup::STANDARD); + else + zret.push(Service_Type_Invalid(text, prop.getSourceLine())); + } else { + zret.push(Prop_Invalid_Type(prop, ts::config::StringValue)); + } + } else { // default type based on ID. + ServiceGroup::Type svc_type = + svc_info.getSvcId() <= ServiceGroup::RESERVED + ? ServiceGroup::STANDARD + : ServiceGroup::DYNAMIC + ; + svc_info.setSvcType(svc_type); + zret.push(Service_Type_Defaulted(svc_type, svc_line)); + } + + // Get the protocol. + if ((prop = svc_cfg[SVC_PROP_PROTOCOL]).hasValue()) { + if (svc_info.getSvcType() == ServiceGroup::STANDARD) { + zret.push(Svc_Prop_Ignored(SVC_PROP_PROTOCOL, prop.getSourceLine())); + } else if (ts::config::IntegerValue == prop.getType()) { + x = atoi(prop.getText()._ptr); + if (0 <= x && x <= 255) + svc_info.setProtocol(x); + else + zret.push(Svc_Prop_Out_Of_Range(SVC_PROP_ID, prop, x, 0, 255)); + } else { + zret.push(Prop_Invalid_Type(prop, ts::config::IntegerValue)); + } + } else if (svc_info.getSvcType() != ServiceGroup::STANDARD) { + // Required if it's not standard / predefined. + zret.push(Prop_Not_Found(SVC_PROP_PROTOCOL, SVC_NAME, svc_line)); + } + + // Get the priority. + svc_info.setPriority(0); // OK to default to this value. + if ((prop = svc_cfg[SVC_PROP_PRIORITY]).hasValue()) { + if (svc_info.getSvcType() == ServiceGroup::STANDARD) { + zret.push(Svc_Prop_Ignored(SVC_PROP_PRIORITY, prop.getSourceLine())); + } else if (ts::config::IntegerValue == prop.getType()) { + x = atoi(prop.getText()._ptr); + if (0 <= x && x <= 255) + svc_info.setPriority(x); + else + zret.push(Svc_Prop_Out_Of_Range(SVC_PROP_ID, prop, x, 0, 255)); + } else { + zret.push(Prop_Invalid_Type(prop, ts::config::IntegerValue)); + } + } + + // Service flags. + svc_info.setFlags(0); + if ((prop = svc_cfg[SVC_PROP_PRIMARY_HASH]).hasValue()) { + ts::Errata status = load_option_set(prop, HASH_OPTS, N_OPTS(HASH_OPTS)); + uint32_t f = 0; + src_line = prop.getSourceLine(); + for ( size_t i = 0 ; i < N_OPTS(HASH_OPTS) ; ++i ) + if (HASH_OPTS[i].m_found) f |= ServiceGroup::SRC_IP_HASH << i; + if (f) { + svc_info.enableFlags(f); + if (!status) zret.push(Ignored_Opt_Errors(SVC_PROP_PRIMARY_HASH, src_line).set(status)); + } else { + zret.push(List_Valid_Opts(prop.getName(), src_line, HASH_OPTS, N_OPTS(HASH_OPTS)).set(status)); + } + } else { + zret.push(Prop_Not_Found(SVC_PROP_PRIMARY_HASH, SVC_NAME, svc_line)); + } + + if ((prop = svc_cfg[SVC_PROP_ALT_HASH]).hasValue()) { + ts::Errata status = load_option_set(prop, HASH_OPTS, N_OPTS(HASH_OPTS)); + uint32_t f = 0; + src_line = prop.getSourceLine(); + for ( size_t i = 0 ; i < N_OPTS(HASH_OPTS) ; ++i ) + if (HASH_OPTS[i].m_found) f |= ServiceGroup::SRC_IP_ALT_HASH << i; + if (f) svc_info.enableFlags(f); + if (!status) zret.push(Ignored_Opt_Errors(SVC_PROP_ALT_HASH, src_line).set(status)); + } + + if ((prop = svc_cfg[SVC_PROP_PORT_TYPE]).hasValue()) { + src_line = prop.getSourceLine(); + if (ts::config::StringValue == prop.getType()) { + text = prop.getText(); + if ("src" == text) + svc_info.enableFlags(ServiceGroup::PORTS_SOURCE); + else if ("dst" == text) + svc_info.disableFlags(ServiceGroup::PORTS_SOURCE); + else + zret.push(Port_Type_Invalid(text, src_line)); + } else { + zret.push(Prop_Invalid_Type(prop, ts::config::StringValue)); + } + } + + // Ports for service. + svc_info.clearPorts(); + if ((prop = svc_cfg[SVC_PROP_PORTS]).hasValue()) { + src_line = prop.getSourceLine(); + if (ServiceGroup::STANDARD == svc_info.getSvcType()) { + zret.push(Svc_Prop_Ignored_In_Standard(SVC_PROP_PORTS, src_line)); + } else { + if ( prop.isContainer() ) { + size_t nport = prop.childCount(); + size_t pidx, sidx; + bool malformed_error = false; + // Clip to maximum protocol allowed ports. + if (nport > ServiceGroup::N_PORTS) { + zret.push(Svc_Ports_Too_Many(src_line, nport)); + nport = ServiceGroup::N_PORTS; + } + // Step through the ports. + for ( pidx = sidx = 0 ; pidx < nport ; ++pidx ) { + Value const& port_cfg = prop[pidx]; + if (ts::config::IntegerValue == port_cfg.getType()) { + x = atoi(port_cfg.getText()._ptr); + if (0 <= x && x <= 65535) + svc_info.setPort(sidx++, x); + else + zret.push(Svc_Prop_Out_Of_Range(SVC_PROP_PORTS, port_cfg, x, 0, 65535)); + } else if (!malformed_error) { // only report this once. + zret.push(Svc_Ports_Malformed(src_line)); + malformed_error = true; + } + } + if (sidx) svc_info.enableFlags(ServiceGroup::PORTS_DEFINED); + else zret.push(Svc_Ports_None_Valid(src_line)); + } else { + zret.push(Prop_Invalid_Type(prop, ts::config::ListValue)); + } + } + } else if (ServiceGroup::STANDARD != svc_info.getSvcType()) { + zret.push(Svc_Ports_Not_Found(svc_line)); + } + + // Security option for this service group. + if ((prop = svc_cfg[SVC_PROP_SECURITY]).hasValue()) { + ts::Rv security = load_security(prop); + if (security.isOK()) { + use_group_local_security = true; + if (security.result()._ptr) { + md5_key = security.result()._ptr; + security_style = SECURITY_MD5; + } else { + security_style = SECURITY_NONE; + } + } + zret.pull(security.errata()); + } + + // Get any group specific routers. + routers.clear(); // reset list. + if ((prop = svc_cfg[SVC_PROP_ROUTERS]).hasValue()) { + ts::Errata status = load_routers(prop, routers); + if (!status) + zret.push(ts::Errata::Message(23, LVL_INFO, "Router specification invalid.").set(status)); + } + if (!routers.size() && !Seed_Router.size()) + zret.push(No_Valid_Routers(svc_line)); + + // See if can proceed with service group creation. + ts::Errata::Code code = code_max(zret); + if (code >= LVL_WARN) { + zret = Unable_To_Create_Service_Group(svc_line).set(zret); + return zret; + } + + // Properties after this are optional so we can proceed if they fail. + GroupData& svc = this->defineServiceGroup(svc_info); + // Add seed routers. + std::vector::iterator rspot, rlimit; + for ( rspot = routers.begin(), rlimit = routers.end() ; rspot != rlimit ; ++rspot ) + svc.seedRouter(*rspot); + for ( rspot = Seed_Router.begin(), rlimit = Seed_Router.end() ; rspot != rlimit ; ++rspot ) + svc.seedRouter(*rspot); + + if (use_group_local_security) + svc.setSecurity(security_style).setKey(md5_key); + + // Look for optional properties. + + svc.m_packet_forward = ServiceGroup::GRE; // default + if ((prop = svc_cfg[SVC_PROP_FORWARD]).hasValue()) { + ts::Errata status = load_option_set(prop, FORWARD_OPTS, N_FORWARD_OPTS); + bool gre = FORWARD_OPTS[0].m_found; + bool l2 = FORWARD_OPTS[1].m_found; + if (gre || l2) { + svc.m_packet_forward = + gre + ? l2 ? ServiceGroup::GRE_OR_L2 : ServiceGroup::GRE + : ServiceGroup::L2 + ; + if (!status.isOK()) + zret.push(Ignored_Opt_Errors(SVC_PROP_FORWARD, prop.getSourceLine()).set(status)); + } else { + zret.push(ts::Errata::Message(26, LVL_INFO, "Defaulting to GRE forwarding.").set(status)); + } + } + + svc.m_packet_return = ServiceGroup::GRE; // default. + if ((prop = svc_cfg[SVC_PROP_RETURN]).hasValue()) { + ts::Errata status = load_option_set(prop, RETURN_OPTS, N_RETURN_OPTS); + bool gre = RETURN_OPTS[0].m_found; + bool l2 = RETURN_OPTS[1].m_found; + if (gre || l2) { + svc.m_packet_return = + gre + ? l2 ? ServiceGroup::GRE_OR_L2 : ServiceGroup::GRE + : ServiceGroup::L2 + ; + if (!status.isOK()) zret.push(Ignored_Opt_Errors(SVC_PROP_RETURN, prop.getSourceLine()).set(status)); + } else { + zret.push(ts::Errata::Message(26, LVL_INFO, "Defaulting to GRE return.").set(status)); + } + } + + svc.m_cache_assign = ServiceGroup::HASH_ONLY; // default + if ((prop = svc_cfg[SVC_PROP_ASSIGN]).hasValue()) { + ts::Errata status = load_option_set(prop, ASSIGN_OPTS, N_OPTS(ASSIGN_OPTS)); + bool hash = ASSIGN_OPTS[0].m_found; + bool mask = ASSIGN_OPTS[1].m_found; + if (hash || mask) { + svc.m_cache_assign = + hash + ? mask ? ServiceGroup::HASH_OR_MASK : ServiceGroup::HASH_ONLY + : ServiceGroup::MASK_ONLY + ; + if (!status.isOK()) zret.push(Ignored_Opt_Errors(SVC_PROP_ASSIGN, prop.getSourceLine()).set(status)); + } else { + status.push(ts::Errata::Message(26, LVL_INFO, "Defaulting to hash assignment only.")); + zret.push(List_Valid_Opts(prop.getName(), src_line, ASSIGN_OPTS, N_OPTS(ASSIGN_OPTS)).set(status)); + } + } + } + return zret; +} + +} // namespace. diff --git a/lib/wccp/WccpEndPoint.cc b/lib/wccp/WccpEndPoint.cc new file mode 100644 index 00000000..ed2b5b44 --- /dev/null +++ b/lib/wccp/WccpEndPoint.cc @@ -0,0 +1,1218 @@ +/** @file WCCP End Point class implementation. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "WccpLocal.h" +# include "WccpUtil.h" +# include "WccpMeta.h" +# include +// ------------------------------------------------------ +namespace wccp { +// ------------------------------------------------------ +Impl::GroupData::GroupData() + : m_generation(0) + , m_use_security_opt(false) + , m_use_security_key(false) { +} + +Impl::GroupData& +Impl::GroupData::setKey(char const* key) { + m_use_security_key = true; + memset(m_security_key, 0, SecurityComp::KEY_SIZE); + strncpy(m_security_key, key, SecurityComp::KEY_SIZE); + return *this; +} + +Impl::GroupData& +Impl::GroupData::setSecurity(SecurityOption style) { + m_use_security_opt = true; + m_security_opt = style; + return *this; +} + +Impl::Impl() + : m_addr(INADDR_ANY) + , m_fd(ts::NO_FD) { +} + +Impl::~Impl() { + this->close(); +} + +int +Impl::open(uint addr) { + struct sockaddr saddr; + sockaddr_in& in_addr = reinterpret_cast(saddr); + int fd; + + if (ts::NO_FD != m_fd) { + log(LVL_INFO, "Attempted to open already open WCCP Endpoint"); + return -EALREADY; + } + + if (ts::NO_FD == (fd = socket(PF_INET, SOCK_DGRAM, 0))) { + log_errno(LVL_FATAL, "Failed to create socket"); + return -errno; + } + + if (INADDR_ANY != addr) m_addr = addr; // overridden. + memset(&saddr, 0, sizeof(saddr)); + in_addr.sin_family = AF_INET; + in_addr.sin_port = htons(DEFAULT_PORT); + in_addr.sin_addr.s_addr = m_addr; + int zret = bind(fd, &saddr, sizeof(saddr)); + if (-1 == zret) { + log_errno(LVL_FATAL, "Failed to bind socket to port"); + this->close(); + return -errno; + } + logf(LVL_INFO, "Socket bound to %s:%d", ip_addr_to_str(m_addr), DEFAULT_PORT); + + // Now get the address. Usually the same but possibly different, + // certainly if addr was INADDR_ANY. + if (INADDR_ANY == m_addr && INADDR_ANY == (m_addr = Get_Local_Address(fd))) { + log_errno(LVL_FATAL, "Failed to get local address for socket"); + this->close(); + return -errno; + } + + // Enable retrieval of destination address on packets. + int ip_pktinfo_flag = 1; + if (-1 == setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &ip_pktinfo_flag, sizeof(ip_pktinfo_flag))) { + log_errno(LVL_FATAL, "Failed to enable destination address retrieval"); + this->close(); + return -errno; + } + +# if defined IP_MTU_DISCOVER + /// Disable PMTU on Linux because of a bug in IOS routers. + /// WCCP packets are rejected as duplicates if the IP fragment + /// identifier is 0, which is the value used when PMTU is enabled. + int pmtu = IP_PMTUDISC_DONT; + if (-1 == setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu))) { + log_errno(LVL_FATAL, "Failed to disable PMTU on WCCP socket."); + this->close(); + return -errno; + } +# endif + + m_fd = fd; + return 0; +} + +void +Impl::close() { + if (ts::NO_FD != m_fd) { + ::close(m_fd); + m_fd = ts::NO_FD; + } +} + +void +Impl::useMD5Security(ts::ConstBuffer const& key) { + m_use_security_opt = true; + m_security_opt = SECURITY_MD5; + m_use_security_key = true; + memset(m_security_key, 0, SecurityComp::KEY_SIZE); + // Great. Have to cast or we get a link error. + strncpy(m_security_key, key._ptr, std::min(key._size, static_cast(SecurityComp::KEY_SIZE))); +} + +SecurityOption +Impl::setSecurity(BaseMsg& msg, GroupData const& group) const { + SecurityOption zret = SECURITY_NONE; + if (group.m_use_security_opt) zret = group.m_security_opt; + else if (m_use_security_opt) zret = m_security_opt; + if (group.m_use_security_key) msg.m_security.setKey(group.m_security_key); + else if (m_use_security_key) msg.m_security.setKey(m_security_key); + return zret; +} + +bool +Impl::validateSecurity(BaseMsg& msg, GroupData const& group) { + SecurityOption opt = msg.m_security.getOption(); + if (group.m_use_security_opt) { + if (opt != group.m_security_opt) return false; + } else if (m_use_security_opt) { + if (opt != m_security_opt) return false; + } + if (opt == SECURITY_MD5) { + if (group.m_use_security_key) msg.m_security.setKey(group.m_security_key); + else if (m_use_security_key) msg.m_security.setKey(m_security_key); + return msg.validateSecurity(); + } + return true; +} + +ts::Rv +Impl::handleMessage() { + ts::Rv zret; + ssize_t n; // recv byte count. + struct sockaddr src_addr; // sender's address. + msghdr recv_hdr; + iovec recv_buffer; + IpHeader ip_header; + static ssize_t const BUFFER_SIZE = 65536; + char buffer[BUFFER_SIZE]; + static size_t const ANC_BUFFER_SIZE = CMSG_ALIGN(CMSG_SPACE(sizeof(in_pktinfo))); + char anc_buffer[ANC_BUFFER_SIZE]; + + if (ts::NO_FD == m_fd) return -ENOTCONN; + + recv_buffer.iov_base = buffer; + recv_buffer.iov_len = BUFFER_SIZE; + + recv_hdr.msg_name = &src_addr; + recv_hdr.msg_namelen = sizeof(src_addr); + recv_hdr.msg_iov = &recv_buffer; + recv_hdr.msg_iovlen = 1; + recv_hdr.msg_control = anc_buffer; + recv_hdr.msg_controllen = ANC_BUFFER_SIZE; + + n = recvmsg(m_fd, &recv_hdr, MSG_TRUNC); + if (n > BUFFER_SIZE) return -EMSGSIZE; + else if (n < 0) return -errno; + + // Extract the original destination address. + ip_header.m_src = access_field(&sockaddr_in::sin_addr, &src_addr).s_addr; + for ( cmsghdr* anc = CMSG_FIRSTHDR(&recv_hdr); + anc; + anc = CMSG_NXTHDR(&recv_hdr, anc) + ) { + if (anc->cmsg_level == IPPROTO_IP && anc->cmsg_type == IP_PKTINFO) { + ip_header.m_dst = access_field(&in_pktinfo::ipi_addr, CMSG_DATA(anc)).s_addr; + break; + } + } + + // Check to see if there is a valid header. + MsgHeaderComp header; + MsgBuffer msg_buffer(buffer,n); + if (PARSE_SUCCESS == header.parse(msg_buffer)) { + message_type_t msg_type = header.getType(); + ts::Buffer chunk(buffer,n); + + switch (msg_type) { + case HERE_I_AM: this->handleHereIAm(ip_header, chunk); break; + case I_SEE_YOU: this->handleISeeYou(ip_header, chunk); break; + case REDIRECT_ASSIGN: this->handleRedirectAssign(ip_header, chunk); break; + case REMOVAL_QUERY: this->handleRemovalQuery(ip_header, chunk); break; + default: fprintf(stderr, "Unknown message type %d ignored.\n", msg_type); + break; + }; + } else { + fprintf(stderr, "Malformed message ignored.\n"); + } + return zret; +} + +ts::Errata +Impl::handleHereIAm(IpHeader const&, ts::Buffer const&) { + return log(LVL_INFO, "Unanticipated WCCP2_HERE_I_AM message ignored"); +} +ts::Errata +Impl::handleISeeYou(IpHeader const&, ts::Buffer const& data) { + return log(LVL_INFO, "Unanticipated WCCP2_I_SEE_YOU message ignored."); +} +ts::Errata +Impl::handleRedirectAssign(IpHeader const&, ts::Buffer const& data) { + return log(LVL_INFO, "Unanticipated WCCP2_REDIRECT_ASSIGN message ignored."); +} +ts::Errata +Impl::handleRemovalQuery(IpHeader const&, ts::Buffer const& data) { + return log(LVL_INFO, "Unanticipated WCCP2_REMOVAL_QUERY message ignored."); +} +// ------------------------------------------------------ +CacheImpl::GroupData::GroupData() + : m_assignment_pending(false) { +} + +CacheImpl::GroupData& +CacheImpl::GroupData::seedRouter(uint32_t addr) { + // Be nice and don't add it if it's already there. + if (m_seed_routers.end() == find_by_member(m_seed_routers, &SeedRouter::m_addr, addr)) + m_seed_routers.push_back(SeedRouter(addr)); + return *this; +} + +time_t +CacheImpl::GroupData::removeSeedRouter(uint32_t addr) { + time_t zret = 0; + std::vector::iterator begin = m_seed_routers.begin(); + std::vector::iterator end = m_seed_routers.end(); + std::vector::iterator spot = + std::find_if(begin, end, ts::predicate(&SeedRouter::m_addr, addr)); + + if (end != spot) { + zret = spot->m_xmit; + m_seed_routers.erase(spot); + } + + return zret; +} + +CacheImpl::GroupData& CacheImpl::GroupData::setKey(char const* key) { return static_cast(this->super::setKey(key)); } + +CacheImpl::GroupData& CacheImpl::GroupData::setSecurity(SecurityOption style) { return static_cast(this->super::setSecurity(style)); } + +CacheImpl::CacheBag::iterator +CacheImpl::GroupData::findCache(uint32_t addr) { + return std::find_if( + m_caches.begin(), + m_caches.end(), + ts::predicate(&CacheData::idAddr, addr) + ); +} + +CacheImpl::RouterBag::iterator +CacheImpl::GroupData::findRouter(uint32_t addr) { + return std::find_if( + m_routers.begin(), + m_routers.end(), + ts::predicate(&RouterData::m_addr, addr) + ); +} + +void +CacheImpl::GroupData::resizeCacheSources() { + int count = m_routers.size(); + for ( CacheBag::iterator spot = m_caches.begin(), + limit = m_caches.end(); + spot != limit; + ++spot + ) { + spot->m_src.resize(count); + } +} + +inline CacheImpl::RouterData::RouterData() + : m_addr(0) + , m_generation(0) + , m_rapid(0) + , m_assign(false) + , m_send_caps(false) { +} + +inline CacheImpl::RouterData::RouterData(uint32_t addr) + : m_addr(addr) + , m_generation(0) + , m_rapid(0) + , m_assign(false) + , m_send_caps(false) { +} + +time_t +CacheImpl::RouterData::pingTime(time_t now) const { + time_t tx = m_xmit.m_time + (m_rapid ? TIME_UNIT/10 : TIME_UNIT); + return tx < now ? 0 : tx - now; +} + +time_t +CacheImpl::RouterData::waitTime(time_t now) const { + return m_assign ? 0 : this->pingTime(now); +} + +inline uint32_t +CacheImpl::CacheData::idAddr() const { + return m_id.getAddr(); +} + +CacheImpl::GroupData& +CacheImpl::defineServiceGroup( + ServiceGroup const& svc, + ServiceGroup::Result* result +) { + uint8_t svc_id = svc.getSvcId(); + GroupMap::iterator spot = m_groups.find(svc_id); + GroupData* group; // service with target ID. + ServiceGroup::Result zret; + if (spot == m_groups.end()) { // not defined + group = &(m_groups[svc_id]); + group->m_svc = svc; + memset(&group->m_id, 0, sizeof(group->m_id)); + group->m_id.initDefaultHash(m_addr); + zret = ServiceGroup::DEFINED; + } else { + group = &spot->second; + zret = group->m_svc == svc ? ServiceGroup::EXISTS : ServiceGroup::CONFLICT; + } + if (result) *result = zret; + return *group; +} + +time_t +CacheImpl::GroupData::waitTime(time_t now) const { + time_t zret = std::numeric_limits::max(); + // Active routers. + for ( RouterBag::const_iterator router = m_routers.begin(), + router_limit = m_routers.end() ; + router != router_limit && zret; + ++router + ) { + zret = std::min(zret, router->waitTime(now)); + } + // Seed routers. + for ( std::vector::const_iterator + router = m_seed_routers.begin(), + router_limit = m_seed_routers.end() ; + router != router_limit && zret; + ++router + ) { + time_t tx = router->m_xmit + TIME_UNIT; + if (tx < now) zret = 0; + else zret = std::min(tx - now, zret); + } + // Assignment + if (m_assignment_pending) { + time_t tx = m_generation_time + ( 3 * TIME_UNIT / 2 ); + if (tx < now) zret = 0; + else zret = std::min(tx - now, zret); + } + + return zret; +} + +bool +CacheImpl::GroupData::cullRouters(time_t now) { + bool zret = false; + size_t idx = 0, n = m_routers.size(); + while ( idx < n ) { + RouterData& router = m_routers[idx]; + if (router.m_recv.m_time + TIME_UNIT * 3 < now) { + uint32_t addr = router.m_addr; + // Clip the router by copying down and resizing. + // Must do all caches as well. + --n; // Decrement router counter first. + if (idx < n) router = m_routers[n]; + m_routers.resize(n); + for ( CacheBag::iterator + cache = m_caches.begin(), + cache_limit = m_caches.end(); + cache != cache_limit; + ++cache + ) { + if (idx < n) cache->m_src[idx] = cache->m_src[n]; + cache->m_src.resize(n); + } + // Put it back in the seeds. + this->seedRouter(addr); + zret = true; // Router was culled, report it to caller. + logf(LVL_INFO, "Router " ATS_IP_PRINTF_CODE " timed out and was removed from the active list.", ATS_IP_OCTETS(addr)); + } else { + ++idx; // move to next router. + } + } + if (zret) this->viewChanged(now); + return zret; +} + +CacheImpl::GroupData& +CacheImpl::GroupData::viewChanged(time_t now) { + m_generation += 1; + m_generation_time = now; + m_assign_info.setActive(false); // invalidate current assignment. + m_assignment_pending = m_routers.size() && m_caches.size(); + // Cancel any pending assignment transmissions. + ts::for_each(m_routers, ts::assign_member(&RouterData::m_assign, false)); + logf(LVL_DEBUG, "Service group %d view change (%d)", m_svc.getSvcId(), m_generation); + + return *this; +} + +Cache::Service& +Cache::Service::setKey(char const* key) { + m_group->setKey(key); + return *this; +} + +Cache::Service& +Cache::Service::setSecurity(SecurityOption opt) { + m_group->setSecurity(opt); + return *this; +} + +CacheImpl& +CacheImpl::seedRouter(uint8_t id, uint32_t addr) { + GroupMap::iterator spot = m_groups.find(id); + if (spot != m_groups.end()) spot->second.seedRouter(addr); + return *this; +} + +bool +CacheImpl::isConfigured() const { + return INADDR_ANY != m_addr && m_groups.size() > 0; +} + +int +CacheImpl::open(uint32_t addr) { + int zret = this->super::open(addr); + // If the socket was successfully opened, go through the + // services and update the local service descriptor. + if (0 <= zret) { + for ( GroupMap::iterator spot = m_groups.begin(), limit = m_groups.end(); + spot != limit; + ++spot + ) { + spot->second.m_id.setAddr(m_addr); + } + } + return zret; +} + +time_t +CacheImpl::waitTime() const { + time_t now = time(0); + return ts::minima(m_groups, &GroupData::waitTime, now); +} + +void +CacheImpl::generateHereIAm( + HereIAmMsg& msg, + GroupData& group +) { + msg.fill(group, group.m_id, this->setSecurity(msg, group)); + msg.finalize(); +} + +void +CacheImpl::generateHereIAm( + HereIAmMsg& msg, + GroupData& group, + RouterData& router +) { + SecurityOption sec_opt = this->setSecurity(msg, group); + + msg.fill(group, group.m_id, sec_opt); + if (router.m_local_cache_id.getSize()) + msg.m_cache_id.setUnassigned(false); + + msg.fill_caps(router); + msg.finalize(); +} + +void +CacheImpl::generateRedirectAssign( + RedirectAssignMsg& msg, + GroupData& group +) { + msg.fill(group, this->setSecurity(msg, group)); + msg.finalize(); +} + +ts::Errata +CacheImpl::checkRouterAssignment( + GroupData const& group, + RouterViewComp const& comp +) const { + detail::Assignment const& ainfo = group.m_assign_info; + // If group doesn't have an active assignment, always match w/o checking. + ts::Errata zret; // default is success. + + // if active assignment and data we can check, then check. + if (ainfo.isActive() && ! comp.isEmpty()) { + // Validate the assignment key. + if (ainfo.getKey().getAddr() != comp.getKeyAddr() + || ainfo.getKey().getChangeNumber() != comp.getKeyChangeNumber() + ) { + log(zret, LVL_INFO, "Router assignment key did not match.");; + } else if (ServiceGroup::HASH_ONLY == group.m_cache_assign + ) { + // Still not sure how much checking we really want or should + // do here. For now, we'll just leave the checks validating + // the assignment key. + } else if (ServiceGroup::MASK_ONLY == group.m_cache_assign) { + // The data passed back is useless. In practice the interesting + // data in the mask case is in the Assignment Map Component + // which the router seems to send when using mask assignment. + } + } + return zret; +} + +int +CacheImpl::housekeeping() { + int zret = 0; + sockaddr_in dst_addr; + sockaddr* addr_ptr = reinterpret_cast(&dst_addr); + time_t now = time(0); + static size_t const BUFFER_SIZE = 4096; + MsgBuffer msg_buffer; + char msg_data[BUFFER_SIZE]; + msg_buffer.set(msg_data, BUFFER_SIZE); + + // Set up everything except the IP address. + memset(&dst_addr, 0, sizeof(dst_addr)); + dst_addr.sin_family = AF_INET; + dst_addr.sin_port = htons(DEFAULT_PORT); + + // Walk the service groups and do their housekeeping. + for ( GroupMap::iterator + svc_spot = m_groups.begin(), + svc_limit = m_groups.end(); + svc_spot != svc_limit; + ++svc_spot + ) { + GroupData& group = svc_spot->second; + + // Check to see if it's time for an assignment. + if (group.m_assignment_pending + && group.m_generation_time + ASSIGN_WAIT <= now + ) { + // Is a valid assignment possible? + if (group.m_assign_info.fill(group, m_addr)) { + group.m_assign_info.setActive(true); + ts::for_each(group.m_routers, + ts::assign_member(&RouterData::m_assign, true) + ); + } + + // Always clear because no point in sending an assign we can't generate. + group.m_assignment_pending = false; + } + + group.cullRouters(now); // TBD UPDATE VIEW! + + // Check the active routers for scheduled packets. + for ( RouterBag::iterator rspot = group.m_routers.begin(), + rend = group.m_routers.end() ; + rspot != rend ; + ++rspot + ) { + dst_addr.sin_addr.s_addr = rspot->m_addr; + if (0 == rspot->pingTime(now)) { + HereIAmMsg here_i_am; + here_i_am.setBuffer(msg_buffer); + this->generateHereIAm(here_i_am, group, *rspot); + zret = sendto(m_fd, msg_data, here_i_am.getCount(), 0, addr_ptr, sizeof(dst_addr)); + if (0 <= zret) { + rspot->m_xmit.set(now, group.m_generation); + rspot->m_send_caps = false; + logf(LVL_DEBUG, "Sent HERE_I_AM for service group %d to router %s%s[#%d,%lu].", + group.m_svc.getSvcId(), + ip_addr_to_str(rspot->m_addr), + rspot->m_rapid ? " [rapid] " : " ", + group.m_generation, now + ); + if (rspot->m_rapid) --(rspot->m_rapid); + } else { + logf_errno(LVL_WARN, "Failed to send to router " ATS_IP_PRINTF_CODE " - ", ATS_IP_OCTETS(rspot->m_addr)); + } + } else if (rspot->m_assign) { + RedirectAssignMsg redirect_assign; + redirect_assign.setBuffer(msg_buffer); + this->generateRedirectAssign(redirect_assign, group); + zret = sendto(m_fd, msg_data, redirect_assign.getCount(), 0, addr_ptr, sizeof(dst_addr)); + if (0 <= zret) rspot->m_assign = false; + } + } + + // Seed routers. + for ( std::vector::iterator + sspot = group.m_seed_routers.begin(), + slimit = group.m_seed_routers.end() ; + sspot != slimit ; + ++sspot + ) { + HereIAmMsg here_i_am; + here_i_am.setBuffer(msg_buffer); + // Is the router due for a ping? + if (sspot->m_xmit + TIME_UNIT > now) continue; // no + + this->generateHereIAm(here_i_am, group); + + dst_addr.sin_addr.s_addr = sspot->m_addr; + zret = sendto(m_fd, msg_data, here_i_am.getCount(), 0, + addr_ptr, sizeof(dst_addr)); + if (0 <= zret) { + logf(LVL_DEBUG, "Sent HERE_I_AM for SG %d to seed router %s [gen=#%d,t=%lu,n=%lu].", + group.m_svc.getSvcId(), + ip_addr_to_str(sspot->m_addr), + group.m_generation, now, here_i_am.getCount() + ); + sspot->m_xmit = now; + sspot->m_count += 1; + } + else logf(LVL_DEBUG, + "Error [%d:%s] sending HERE_I_AM for SG %d to seed router %s [#%d,%lu].", + zret, strerror(errno), + group.m_svc.getSvcId(), + ip_addr_to_str(sspot->m_addr), + group.m_generation, now + ); + } + } + return zret; +} + +ts::Errata +CacheImpl::handleISeeYou(IpHeader const& ip_hdr, ts::Buffer const& chunk) { + ts::Errata zret; + ISeeYouMsg msg; + // Set if our view of the group changes enough to bump the + // generation number. + bool view_changed = false; + time_t now = time(0); // don't call this over and over. + int parse = msg.parse(chunk); + + if (PARSE_SUCCESS != parse) + return logf(LVL_INFO, "Ignored malformed [%d] WCCP2_I_SEE_YOU message.", parse); + + ServiceGroup svc(msg.m_service); + GroupMap::iterator spot = m_groups.find(svc.getSvcId()); + if (spot == m_groups.end()) + return logf(LVL_INFO, "WCCP2_I_SEE_YOU ignored - service group %d not found.", svc.getSvcId()); + + GroupData& group = spot->second; + + if (!this->validateSecurity(msg, group)) + return log(LVL_INFO, "Ignored WCCP2_I_SEE_YOU with invalid security.\n"); + + if (svc != group.m_svc) + return logf(LVL_INFO, "WCCP2_I_SEE_YOU ignored - service group definition %d does not match.\n", svc.getSvcId()); + + if (-1 == msg.m_router_id.findFromAddr(m_addr)) + return logf(LVL_INFO, "WCCP2_I_SEE_YOU ignored -- cache not in from list.\n"); + + logf(LVL_DEBUG, "Received WCCP2_I_SEE_YOU for group %d.", group.m_svc.getSvcId()); + + // Prefered address for router. + uint32_t router_addr = msg.m_router_id.idElt().getAddr(); + // Where we sent our packet. + uint32_t to_addr = msg.m_router_id.getToAddr(); + uint32_t recv_id = msg.m_router_id.idElt().getRecvId(); + RouterBag::iterator ar_spot; // active router + int router_idx; // index in active routers. + std::vector< SeedRouter >::iterator seed_spot; + + CapComp& caps = msg.m_capabilities; + // Handle the router that sent us this. + ar_spot = find_by_member(group.m_routers, &RouterData::m_addr, router_addr); + if (ar_spot == group.m_routers.end()) { + // This is a new router that's replied to one of our pings. + // Need to do various setup and reply things to get the connection + // established. + + // Remove this from the seed routers and copy the last packet + // sent time. + RouterData r(router_addr); // accumulate state before we commit it. + r.m_xmit.m_time = group.removeSeedRouter(to_addr); + + // Validate capabilities. + ServiceGroup::PacketStyle ps; + ServiceGroup::CacheAssignmentStyle as; + char const* caps_tag = caps.isEmpty() ? "default" : "router"; + + // No caps -> use GRE forwarding. + ps = caps.isEmpty() ? ServiceGroup::GRE : caps.getPacketForwardStyle(); + if (ServiceGroup::GRE & ps & group.m_packet_forward) + r.m_packet_forward = ServiceGroup::GRE; + else if (ServiceGroup::L2 & ps & group.m_packet_forward) + r.m_packet_forward = ServiceGroup::L2; + else + logf(zret, LVL_WARN, "Packet forwarding (config=%d, %s=%d) did not match.", group.m_packet_forward, caps_tag, ps); + + // No caps -> use GRE return. + ps = caps.isEmpty() ? ServiceGroup::GRE : caps.getPacketReturnStyle(); + if (ServiceGroup::GRE & ps & group.m_packet_return) + r.m_packet_return = ServiceGroup::GRE; + else if (ServiceGroup::L2 & ps & group.m_packet_return) + r.m_packet_return = ServiceGroup::L2; + else + logf(zret, LVL_WARN, "Packet return (local=%d, %s=%d) did not match.", group.m_packet_return, caps_tag, ps); + + // No caps -> use HASH assignment. + as = caps.isEmpty() ? ServiceGroup::HASH_ONLY : caps.getCacheAssignmentStyle(); + if (ServiceGroup::HASH_ONLY & as & group.m_cache_assign) + r.m_cache_assign = ServiceGroup::HASH_ONLY; + else if (ServiceGroup::MASK_ONLY & as & group.m_cache_assign) { + r.m_cache_assign = ServiceGroup::MASK_ONLY; + group.m_id.initDefaultMask(m_addr); // switch to MASK style ID. + } else + logf(zret, LVL_WARN, "Cache assignment (local=%d, %s=%d) did not match.", group.m_cache_assign, caps_tag, as); + + if (!zret) { + // cancel out, can't use this packet because we reject the router. + return logf(zret, LVL_WARN, "Router %s rejected because of capabilities mismatch.", ip_addr_to_str(router_addr)); + } + + group.m_routers.push_back(r); + ar_spot = group.m_routers.end() - 1; + view_changed = true; + logf(LVL_INFO, "Added source router %s to view %d", ip_addr_to_str(router_addr), group.m_svc.getSvcId()); + } else { + // Existing router. Update the receive ID in the assignment object. + group.m_assign_info.updateRouterId(router_addr, recv_id, msg.m_router_view.getChangeNumber()); + // Check the assignment to see if we need to send it again. + ts::Errata status = this->checkRouterAssignment(group, msg.m_router_view); + if (status.size()) { + ar_spot->m_assign = true; // schedule an assignment message. + logf(status, LVL_INFO, "Router assignment reported from " + ATS_IP_PRINTF_CODE + " did not match local assignment. Resending assignment.\n ", + ATS_IP_OCTETS(router_addr) + ); + } + } + ar_spot->m_recv.set(now, recv_id); + ar_spot->m_generation = msg.m_router_view.getChangeNumber(); + router_idx = ar_spot - group.m_routers.begin(); + // Reply with our own capability options iff the router sent one to us. + // This is a violation of the spec but it's what we have to do in practice + // for mask assignment. + ar_spot->m_send_caps = ! caps.isEmpty(); + + // For all the other listed routers, seed them if they're not + // already active. + uint32_t nr = msg.m_router_view.getRouterCount(); + for ( uint32_t idx = 0; idx < nr ; ++idx ) { + uint32_t addr = msg.m_router_view.getRouterAddr(idx); + if (group.m_routers.end() == find_by_member(group.m_routers, &RouterData::m_addr, addr)) + group.seedRouter(addr); + } + + // Update/Install the caches. + // TBD: Must bump view if a router fails to report a cache it reported + // in its last packet. + group.resizeCacheSources(); + uint32_t nc = msg.m_router_view.getCacheCount(); + for ( uint32_t idx = 0 ; idx < nc ; ++idx ) { + CacheIdBox& cache = msg.m_router_view.cacheId(idx); + CacheBag::iterator ac_spot = group.findCache(cache.getAddr()); + if (group.m_caches.end() == ac_spot) { + group.m_caches.push_back(CacheData()); + ac_spot = group.m_caches.end() - 1; + ac_spot->m_src.resize(group.m_routers.size()); + logf(LVL_INFO, "Added cache %s to view %d", ip_addr_to_str(cache.getAddr()), group.m_svc.getSvcId()); + view_changed = true; + } + ac_spot->m_id.fill(cache); + // If cache is this cache, update data in router record. + if (cache.getAddr() == m_addr) ar_spot->m_local_cache_id.fill(cache); + ac_spot->m_src[router_idx].set(now, recv_id); + } + + if (view_changed) group.viewChanged(now); + + return zret; +} + +ts::Errata +CacheImpl::handleRemovalQuery(IpHeader const& ip_hdr, ts::Buffer const& chunk) { + ts::Errata zret; + RemovalQueryMsg msg; + time_t now = time(0); + int parse = msg.parse(chunk); + + if (PARSE_SUCCESS != parse) + return log(LVL_INFO, "Ignored malformed WCCP2_REMOVAL_QUERY message."); + + ServiceGroup svc(msg.m_service); + GroupMap::iterator spot = m_groups.find(svc.getSvcId()); + if (spot == m_groups.end()) + return logf(LVL_INFO, "WCCP2_REMOVAL_QUERY ignored - service group %d not found.", svc.getSvcId()); + + GroupData& group = spot->second; + + if (!this->validateSecurity(msg, group)) + return log(LVL_INFO, "Ignored WCCP2_REMOVAL_QUERY with invalid security.\n"); + + if (svc != group.m_svc) + return logf(LVL_INFO, "WCCP2_REMOVAL_QUERY ignored - service group definition %d does not match.\n", svc.getSvcId()); + + uint32_t target_addr = msg.m_query.getCacheAddr(); // intended cache + if (m_addr == target_addr) { + uint32_t raddr = msg.m_query.getRouterAddr(); + RouterBag::iterator router = group.findRouter(raddr); + if (group.m_routers.end() != router) { + router->m_rapid = true; // do rapid responses. + router->m_recv.set(now, msg.m_query.getRecvId()); + logf(LVL_INFO, "WCCP2_REMOVAL_QUERY from router " + ATS_IP_PRINTF_CODE ".\n", + ATS_IP_OCTETS(raddr) + ); + } else { + logf(LVL_INFO, "WCCP2_REMOVAL_QUERY from unknown router " + ATS_IP_PRINTF_CODE ".\n", + ATS_IP_OCTETS(raddr) + ); + } + } else { + // Not an error in the multi-cast case, so just log under debug. + logf(LVL_DEBUG, "WCCP2_REMOVAL_QUERY ignored -- target cache address " + ATS_IP_PRINTF_CODE + " did not match local address " + ATS_IP_PRINTF_CODE + "\n.", + ATS_IP_OCTETS(target_addr), ATS_IP_OCTETS(m_addr) + ); + } + + logf(LVL_DEBUG, "Received WCCP2_REMOVAL_QUERY for group %d.", group.m_svc.getSvcId()); + + return zret; +} +// ------------------------------------------------------ +inline uint32_t +RouterImpl::CacheData::idAddr() const { + return m_id.getAddr(); +} + +RouterImpl::GroupData::GroupData() { } + +RouterImpl::CacheBag::iterator +RouterImpl::GroupData::findCache(uint32_t addr) { + return std::find_if( + m_caches.begin(), + m_caches.end(), + ts::predicate(&CacheData::idAddr, addr) + ); +} + +RouterImpl::GroupData& +RouterImpl::defineServiceGroup( + ServiceGroup const& svc, + ServiceGroup::Result* result +) { + uint8_t svc_id = svc.getSvcId(); + GroupMap::iterator spot = m_groups.find(svc_id); + GroupData* group; // service with target ID. + ServiceGroup::Result zret; + if (spot == m_groups.end()) { // not defined + group = &(m_groups[svc_id]); + group->m_svc = svc; + zret = ServiceGroup::DEFINED; + } else { + group = &spot->second; + zret = group->m_svc == svc ? ServiceGroup::EXISTS : ServiceGroup::CONFLICT; + } + if (result) *result = zret; + return *group; +} + +void +RouterImpl::GroupData::resizeRouterSources() { + ts::for_each(m_routers, &RouterData::resize, m_caches.size()); +} + +ts::Errata +RouterImpl::handleHereIAm(IpHeader const& ip_hdr, ts::Buffer const& chunk) { + ts::Errata zret; + HereIAmMsg msg; + static GroupData nil_group; // scratch until I clean up the security. + // Set if our view of the group changes enough to bump the + // generation number. + bool view_changed = false; + int i; // scratch index var. + time_t now = time(0); // don't call this over and over. + int parse = msg.parse(chunk); + + if (PARSE_SUCCESS != parse) + return log(LVL_INFO, "Ignored malformed WCCP2_HERE_I_AM message.\n"); + + if (!this->validateSecurity(msg, nil_group)) + return log(LVL_INFO, "Ignored WCCP2_HERE_I_AM with invalid security.\n"); + + ServiceGroup svc(msg.m_service); + ServiceGroup::Result r; + GroupData& group = this->defineServiceGroup(svc, &r); + if (ServiceGroup::CONFLICT == r) + return logf(LVL_INFO, "WCCP2_HERE_I_AM ignored - service group %d definition does not match.\n", svc.getSvcId()); + else if (ServiceGroup::DEFINED == r) + return logf(LVL_INFO, "Service group %d defined by WCCP2_HERE_I_AM.\n", svc.getSvcId()); + + // Check if this cache is already known. + uint32_t cache_addr = msg.m_cache_id.getAddr(); + int cache_idx; + uint32_t cache_gen; + CacheBag::iterator cache = group.findCache(cache_addr); + if (cache == group.m_caches.end()) { // not known + group.m_caches.push_back(CacheData()); + // Vector modified, need clean end value. + cache = group.m_caches.end() - 1; + cache->m_recv_count = 0; + group.resizeRouterSources(); + view_changed = true; + } else { + // Did the cache mention us specifically? + // If so, make sure the sequence # is correct. + RouterIdElt* me = msg.m_cache_view.findf_router_elt(m_addr); + if (me && me->getRecvId() != cache->m_recv_count) + return logf(LVL_INFO, "Discarded out of date (recv=%d, local=%ld) WCCP2_HERE_I_AM.\n", me->getRecvId(), cache->m_recv_count); + } + + cache_gen = msg.m_cache_view.getChangeNumber(); + + cache_idx = cache - group.m_caches.begin(); + cache->m_id.fill(msg.m_cache_id.cacheId()); + cache->m_recv.set(now, cache_gen); + cache->m_pending = true; + cache->m_to_addr = ip_hdr.m_dst; + + // Add any new routers + i = msg.m_cache_view.getRouterCount(); + while(i-- > 0) { + uint32_t addr = msg.m_cache_view.routerElt(i).getAddr(); + RouterBag::iterator spot = find_by_member(group.m_routers, &RouterData::m_addr, addr); + if (spot == group.m_routers.end()) { + group.m_routers.push_back(RouterData()); + // Can't count on previous end value, modified container. + spot = group.m_routers.end() - 1; + spot->m_addr = addr; + spot->m_src.resize(group.m_caches.size()); + view_changed = true; + } + spot->m_src[cache_idx].set(now, cache_gen); + } + + if (view_changed) ++(group.m_generation); + return zret; +} + +void +RouterImpl::generateISeeYou( + ISeeYouMsg& msg, + GroupData& group, + CacheData& cache +) { + int i; + size_t n_routers = group.m_routers.size(); + size_t n_caches = group.m_caches.size(); + + // Not handling multi-cast so target caches is hardwired to 1. + msg.fill(group, this->setSecurity(msg, group), group.m_assign_info, 1, n_routers, n_caches); + + // Fill in ID data not done by fill. + msg.m_router_id + .setIdElt(m_addr, cache.m_recv_count + 1) + .setToAddr(cache.m_to_addr) + .setFromAddr(0, cache.idAddr()); + ; + + // Fill view routers. + i = 0; + for ( RouterBag::iterator router = group.m_routers.begin(), + router_limit = group.m_routers.end(); + router != router_limit; + ++router, ++i + ) { + msg.m_router_view.setRouterAddr(i, router->m_addr); + } + + // Fill view caches. + i = 0; + for ( CacheBag::iterator spot = group.m_caches.begin(), + limit = group.m_caches.end(); + spot != limit; + ++spot, ++i + ) { + // TBD: This needs to track memory because cache ID elements + // turn out to be variable sized. +// msg.m_router_view.cacheId(i) = spot->m_id; + } + + msg.finalize(); +} + +int +RouterImpl::xmitISeeYou() { + int zret = 0; + ISeeYouMsg msg; + MsgBuffer buffer; + sockaddr_in dst_addr; + time_t now = time(0); + static size_t const BUFFER_SIZE = 4096; + char* data = static_cast(alloca(BUFFER_SIZE)); + + memset(&dst_addr, 0, sizeof(dst_addr)); + dst_addr.sin_family = AF_INET; + dst_addr.sin_port = htons(DEFAULT_PORT); + buffer.set(data, BUFFER_SIZE); + + // Send out messages for each service group. + for ( GroupMap::iterator svc_spot = m_groups.begin(), + svc_limit = m_groups.end() ; + svc_spot != svc_limit ; + ++svc_spot + ) { + GroupData& group = svc_spot->second; + + // Check each active cache in the group. + for ( CacheBag::iterator cache = group.m_caches.begin(), + cache_limit = group.m_caches.end() ; + cache != cache_limit ; + ++cache + ) { + if (!cache->m_pending) continue; + + msg.setBuffer(buffer); + this->generateISeeYou(msg, group, *cache); + dst_addr.sin_addr.s_addr = cache->m_id.getAddr(); + zret = sendto(m_fd, data, msg.getCount(), 0, + reinterpret_cast(&dst_addr), sizeof(dst_addr)); + if (0 <= zret) { + cache->m_xmit.set(now, group.m_generation); + cache->m_pending = false; + cache->m_recv_count = msg.m_router_id.getRecvId(); + logf(LVL_DEBUG, "I_SEE_YOU -> %s\n", ip_addr_to_str(cache->m_id.getAddr())); + } + else { + log_errno(LVL_WARN, "Router transmit failed -"); + return zret; + } + } + } + return zret; +} + +int +RouterImpl::housekeeping() { + return this->xmitISeeYou(); +} + +bool +RouterImpl::isConfigured() const { + return false; +} +// ------------------------------------------------------ +EndPoint::EndPoint() { +} + +EndPoint::~EndPoint() { +} + +EndPoint::EndPoint(self const& that) + : m_ptr(that.m_ptr) { +} + +inline EndPoint::ImplType* +EndPoint::instance() { + return m_ptr ? m_ptr.get() : this->make(); +} + +EndPoint& EndPoint::setAddr(uint32_t addr) { + this->instance()->m_addr = addr; + logf(LVL_DEBUG, "Endpoint address set to %s\n", ip_addr_to_str(addr)); + return *this; +} + +bool +EndPoint::isConfigured() const { + return m_ptr && m_ptr->isConfigured(); +} + +int +EndPoint::open(uint32_t addr) { + return this->instance()->open(addr); +} + +void +EndPoint::useMD5Security(ts::ConstBuffer const& key) { + this->instance()->useMD5Security(key); +} + +int EndPoint::getSocket() const { + return m_ptr ? m_ptr->m_fd : ts::NO_FD; +} + +int +EndPoint::housekeeping() { + // Don't force an instance because if there isn't one, + // there's no socket either. + return m_ptr && ts::NO_FD != m_ptr->m_fd ? m_ptr->housekeeping() : -ENOTCONN; +} + +ts::Rv +EndPoint::handleMessage() { + return m_ptr + ? m_ptr->handleMessage() + : ts::Rv(-ENOTCONN, log(LVL_INFO, "EndPoint::handleMessage called on unconnected instance")); +} +// ------------------------------------------------------ +Cache::Cache() { +} + +Cache::~Cache() { +} + +EndPoint::ImplType* +Cache::make() { + m_ptr.assign(new ImplType); + return m_ptr.get(); +} + +inline Cache::ImplType* +Cache::instance() { + return static_cast(this->super::instance()); +} + +inline Cache::ImplType* Cache::impl() { + return static_cast(m_ptr.get()); +} + +inline Cache::ImplType const* Cache::impl() const { + return static_cast(m_ptr.get()); +} + +Cache::Service +Cache::defineServiceGroup( + ServiceGroup const& svc, + ServiceGroup::Result* result +) { + return Service(*this, this->instance()->defineServiceGroup(svc, result)); +} + +time_t Cache::waitTime() const { + return m_ptr ? this->impl()->waitTime() : std::numeric_limits::max(); +} + +Cache& +Cache::addSeedRouter(uint8_t id, uint32_t addr) { + this->instance()->seedRouter(id, addr); + return *this; +} + +ts::Errata +Cache::loadServicesFromFile(char const* path) { + return this->instance()->loadServicesFromFile(path); +} +// ------------------------------------------------------ +Router::Router() { +} + +Router::~Router() { +} + +EndPoint::ImplType* +Router::make() { + m_ptr.assign(new ImplType); + return m_ptr.get(); +} + +inline Router::ImplType* +Router::instance() { + return static_cast(this->super::instance()); +} + +inline Router::ImplType* +Router::impl() { + return static_cast(m_ptr.get()); +} +// ------------------------------------------------------ +} // namespace wccp diff --git a/lib/wccp/WccpLocal.h b/lib/wccp/WccpLocal.h new file mode 100644 index 00000000..c8f5f3f5 --- /dev/null +++ b/lib/wccp/WccpLocal.h @@ -0,0 +1,3577 @@ +# if !defined(TS_WCCP_LOCAL_HEADER) +# define TS_WCCP_LOCAL_HEADER + +/** @file + WCCP (v2) support for Apache Traffic Server. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "Wccp.h" +# include "WccpUtil.h" +# include +// Needed for template use of byte ordering functions. +# include +# include +# include +# include + +namespace ts { +/// Null / invalid file descriptor. +static const int NO_FD = -1; +} + +namespace wccp { + +// Forward declares +namespace detail { + class Assignment; + namespace cache { + class RouterData; + } +} + +/// Default port used by the protocol. +static unsigned int const DEFAULT_PORT = 2048; +/// Number of buckets in WCCP hash allocation. +static unsigned int const N_BUCKETS = 256; +/// Unassigned bucket value (defined by protocol). +static uint8_t const UNASSIGNED_BUCKET = 0xFF; +/// Size of group password in octets. +static unsigned int const GROUP_PASSWORD_SIZE = 8; +/// Maximum # of caches +static uint32_t const MAX_CACHES = 32; +/// Maximum # of routers +static uint32_t const MAX_ROUTERS = 32; + +/// Our version of the protocol. +static unsigned int const VERSION = 0x200; + +/// @name Parse results. +/// @note Internal values are positive. System errors are reported as +/// the negative of errno. +//@{ +/// Successful parse (message is well formatted) +static int const PARSE_SUCCESS = 0; +/// Component is the wrong type but looks like a valid type. +static int const PARSE_COMP_OTHER_TYPE = 1; +/// Component has a bogus type (cannot be valid). +static int const PARSE_COMP_TYPE_INVALID = 2; +/// Length in message is larger than actual message data. +static int const PARSE_MSG_TOO_BIG = 3; +/// Message header has invalid data. +static int const PARSE_MSG_INVALID = 5; +/// Component is malformed. +static int const PARSE_COMP_INVALID = 4; +/// Message is not the expected type. +static int const PARSE_MSG_WRONG_TYPE = 6; +/// Variable data for component can't fit in remaining data. +static int const PARSE_COMP_TOO_BIG = 7; +/// Fixed data for component can't fit in remaining data. +static int const PARSE_BUFFER_TOO_SMALL = 8; +/// Stored component size doesn't agree with locally computed size. +static int const PARSE_COMP_WRONG_SIZE = 9; +/// More data in message than can be accounted for. +static int const PARSE_DATA_OVERRUN = 10; +//@} + +/** Buffer for serialized data. + Takes the basic ATS buffer and adds a count field to track + the amount of buffer in use. +*/ +class MsgBuffer : protected ts::Buffer { +public: + typedef MsgBuffer self; ///< Self reference type. + typedef ts::Buffer super; ///< Parent type. + + MsgBuffer(); ///< Default construct empty buffer. + /// Construct from ATS buffer. + MsgBuffer( + super const& that ///< Instance to copy. + ); + /// Construct from pointer and size. + MsgBuffer( + void* ptr, ///< Pointer to buffer. + size_t n ///< Size of buffer. + ); + /// Assign a buffer. + MsgBuffer& set( + void* ptr, ///< Pointer to buffer. + size_t n ///< Size of buffer. + ); + /// Extract memory chunk + operator super const& () const; + + /// Get the buffer size. + size_t getSize() const; + /// Get the content size (use count). + size_t getCount() const; + /// Get address of first unused byte. + char* getTail(); + /// Get address of first byte. + char* getBase(); + /// Get address of first byte. + char const* getBase() const; + /// Get the remaining space in the buffer. + size_t getSpace() const; + /// Mark additional space in use. + self& use( + size_t n ///< Additional space to mark in use. + ); + /// Mark all space as unused. + self& reset(); + + /// Reset and zero the buffer. + self& zero(); + + size_t _count; ///< Number of bytes in use. +}; + +/// Sect 4.4: Cache assignment method. +enum CacheAssignmentType { + ASSIGNMENT_BY_HASH = 0, + ASSIGNMENT_BY_MASK = 1 +}; + +/// Top level message types. +enum message_type_t { + INVALID_MSG_TYPE = 0, + HERE_I_AM = 10, + I_SEE_YOU = 11, + REDIRECT_ASSIGN = 12, + REMOVAL_QUERY = 13 +}; + +/// Message component type. +/// See Sect 5.1 - 5.4 +enum CompType { + SECURITY_INFO = 0, + SERVICE_INFO = 1, + ROUTER_ID_INFO = 2, + CACHE_ID_INFO = 3, + RTR_VIEW_INFO = 4, + CACHE_VIEW_INFO = 5, + REDIRECT_ASSIGNMENT = 6, + QUERY_INFO = 7, + CAPABILITY_INFO = 8, + ALT_ASSIGNMENT = 13, + ASSIGN_MAP = 14, + COMMAND_EXTENSION = 15, + COMP_TYPE_MIN = SECURITY_INFO, + COMP_TYPE_MAX = COMMAND_EXTENSION +}; + +/// Router Identity. +/// Data is stored in host order. This structure is not used publicly. +struct RouterId { + typedef RouterId self; ///< Self reference type. + + RouterId(); ///< Default constructor. + /// Construct from address and sequence number. + RouterId( + uint32_t addr, ///< Router address. + uint32_t recv_id ///< Receive ID (sequence number). + ); + + uint32_t m_addr; ///< Identifying router IP address. + uint32_t m_recv_id; ///< Recieve ID (sequence #). +}; + +/** Sect 5.7.1: Router Identity Element. + + This maps directly on to message content. + + @internal A @c RouterId with accessors to guarantee correct memory + layout. +*/ +class RouterIdElt : protected RouterId { +protected: + typedef RouterId super; ///< Parent type. +public: + typedef RouterIdElt self; ///< Self reference type. + + /// Default constructor, members zero initialized. + RouterIdElt(); + /// Construct from address and sequence number. + RouterIdElt( + uint32_t addr, ///< Router address. + uint32_t recv_id ///< Receive ID (sequence number). + ); + + /// @name Accessors + //@{ + uint32_t getAddr() const; ///< Get the address field. + self& setAddr(uint32_t addr); ///< Set the address field to @a addr. + uint32_t getRecvId() const; ///< Get the receive ID field. + self& setRecvId(uint32_t id); ///< Set the receive ID field to @a id. + //@} + + /// Assign from non-serialized variant. + self& operator = (super const& that); +}; + +/// Sect 5.7.3: Assignment Key Element +/// @note This maps directly on to message content. +/// @internal: At top level because it is used in more than one component. +class AssignmentKeyElt { +public: + typedef AssignmentKeyElt self; ///< Self reference type. + + AssignmentKeyElt(); ///< Default constructor. No member initialization. + /// Construct from address and sequence number. + AssignmentKeyElt( + uint32_t addr, ///< Key address. + uint32_t generation ///< Change number. + ); + + /// @name Accessors + //@{ + uint32_t getAddr() const; ///< Get the address field. + self& setAddr(uint32_t addr); ///< Set the address field to @a addr. + uint32_t getChangeNumber() const; ///< Get change number field. + self& setChangeNumber(uint32_t n); ///< Set change number field to @a n. + //@} +protected: + uint32_t m_addr; ///< Identifying router IP address. + uint32_t m_change_number; ///< Change number (sequence #). +}; + +/// Sect 5.7.4: Router Assignment Element +/// @note This maps directly on to message content. +/// @internal: At top level because it is used in more than one component. +class RouterAssignElt : public RouterIdElt { +public: + typedef RouterAssignElt self; ///< Self reference type. + typedef RouterIdElt super; ///< Parent type. + + /// Default constructor, members zero initialized. + RouterAssignElt(); + /// Construct from address and sequence number. + RouterAssignElt( + uint32_t addr, ///< Router address. + uint32_t recv_id, ///< Receive ID (sequence number). + uint32_t change_number ///< Change number (sequence number). + ); + + /// @name Accessors + //@{ + uint32_t getChangeNumber() const; ///< Get change number field. + self& setChangeNumber(uint32_t n); ///< Set change number field to @a n. + //@} +protected: + uint32_t m_change_number; ///< Change number (sequence #). +}; + +/** List of @c RouterAssignElt + @note Not explicitly part of the spec, but it shows up in multiple + places. + */ +class RouterAssignListElt { +public: + typedef RouterAssignListElt self; ///< Self reference type. + + /// Default constructor - @b no initialization. + RouterAssignListElt(); + /// Construct with @n elements. + RouterAssignListElt( + int n ///< Number of elements. + ); + + /// @name Accessors + //@{ + /// Access element. + RouterAssignElt& elt( + int idx ///< Index of target element. + ); + /// Access const element. + RouterAssignElt const& elt( + int idx ///< Index of target element. + ) const; + /// Get the number of elements. + uint32_t getCount() const; + //@} + + /// Update ID for a router. + self& updateRouterId( + uint32_t addr, ///< Identifying IP address of router. + uint32_t rcvid, ///< New receive ID value. + uint32_t cno ///< New change number. + ); + + /// Get size in bytes of this structure. + size_t getSize() const; + /// Get the size of the variable part only. + /// This is useful for classes that put this element in their + /// stub structure. + size_t getVarSize() const; + /// Calculate size in bytes for @a n elements. + static size_t calcSize( + int n ///< Number of elements. + ); + /// Calculate size of variable data in bytes for @a n elements. + static size_t calcVarSize( + int n ///< Number of elements. + ); +protected: + uint32_t m_count; ///< # of elements (network order). +}; + +/// Sect 5.7.5: Capability Element +/// @note This maps directly on to message content. +class CapabilityElt { +public: + typedef CapabilityElt self; ///< Self reference type. + + /// Capability types. + enum Type { + PACKET_FORWARD_METHOD = 1, ///< Packet forwarding methods. + CACHE_ASSIGNMENT_METHOD = 2, ///< Cache assignment methods. + PACKET_RETURN_METHOD = 3 ///< Packet return methods. + }; + + CapabilityElt(); ///< Default constructor. + /// Construct from address and sequence number. + CapabilityElt( + Type type, ///< Capability type. + uint32_t data ///< Capability data. + ); + + /// @name Accessors + //@{ + Type getCapType() const; ///< Get the capability type. + /// Set capability type. + self& setCapType( + Type cap ///< Capability type. + ); + uint32_t getCapData() const; ///< Get capability data. + /// Set capability data. + self& setCapData( + uint32_t data ///< Data value. + ); + //@} +protected: + uint16_t m_cap_type; ///< Capability type. + uint16_t m_cap_length; ///< Length of capability data. + uint32_t m_cap_data; ///< Capability data. +}; + +/// Sect 5.7.7: Mask element +class MaskElt { +public: + typedef MaskElt self; ///< Self reference type. + + /// Default constructor - @b no initialization. + MaskElt(); + /// Construct with specific values. + MaskElt( + uint32_t srcAddr, ///< Mask for source address. + uint32_t dstAddr, ///< Mask for destination address. + uint16_t srcPort, ///< Mask for source port. + uint16_t dstPort ///< Mask for destination port. + ); + + /// @name Accessors + //@{ + /// Get source address mask field. + uint32_t getSrcAddr() const; + /// Set source address mask field to @a mask. + self& setSrcAddr(uint32_t mask); + /// Get destination address field. + uint32_t getDstAddr() const; + /// Set destination address field to @a mask. + self& setDstAddr(uint32_t mask); + /// Get source port mask field. + uint16_t getSrcPort() const; + /// Set source port mask field to @a mask. + self& setSrcPort(uint16_t mask); + /// Get destination port mask field. + uint16_t getDstPort() const; + /// Set destination port mask field to @a mask. + self& setDstPort(uint16_t mask); + //@} + +protected: + uint32_t m_src_addr; ///< Source address mask. + uint32_t m_dst_addr; ///< Destination address mask. + uint16_t m_src_port; ///< Source port mask. + uint16_t m_dst_port; ///< Destination port mask. +}; + +/// Sect 5.7.8: Value element. +class ValueElt { +public: + typedef ValueElt self; ///< Self reference type. + + /// Default constructor - @b no initialization. + ValueElt(); + /// Construct a specific value. + ValueElt( + uint32_t cacheAddr, ///< Address of cache for this value. + uint32_t srcAddr, ///< Value for source address. + uint32_t dstAddr, ///< Value for destination address. + uint16_t srcPort, ///< Value for source port. + uint16_t dstPort ///< Value for destination port. + ); + + /// @name Accessors + //@{ + uint32_t getf_src_addr() const; ///< Get source address field. + self& setf_src_addr(uint32_t addr); ///< Set source address field to @a addr. + uint32_t getDstAddr() const; ///< Get destination address field. + self& setf_dst_addr(uint32_t addr); ///< Set destination address field to @a addr. + uint16_t getf_src_port() const; ///< Get source port field. + self& setf_src_port(uint16_t port); ///< Set source port field to @a port. + uint16_t getDstPort() const; ///< Get destination port field. + self& setf_dst_port(uint16_t port); ///< Set destination port field to @a port. + uint32_t getCacheAddr() const; ///< Get cache address field. + self& setCacheAddr(uint32_t addr); ///< Set cache address field to @a addr + //@} + +protected: + uint32_t m_src_addr; ///< Source address. + uint32_t m_dst_addr; ///< Destination address. + uint16_t m_src_port; ///< Source port. + uint16_t m_dst_port; ///< Destination port. + uint32_t m_cache_addr; ///< Cache address. +}; + +/** Sect 5.7.6: Mask/Value Set Element + This is a variable sized element. + */ +class MaskValueSetElt { +public: + typedef MaskValueSetElt self; ///< Self reference type. + + MaskValueSetElt(); ///< Default constructor. + /// Construct from address and sequence number. + MaskValueSetElt( + uint32_t n ///< Value count. + ); + + /// @name Accessors + //@{ + /// Directly access contained mask element. + MaskElt& maskElt(); + + /// Get source address mask field. + uint32_t getSrcAddrMask() const; + /// Set source address mask field to @a mask. + self& setSrcAddrMask(uint32_t mask); + /// Get destination address field. + uint32_t getDstAddrMask() const; + /// Set destination address field to @a mask. + self& setDstAddrMask(uint32_t mask); + /// Get source port mask field. + uint16_t getSrcPortMask() const; + /// Set source port mask field to @a mask. + self& setSrcPortMask(uint16_t mask); + /// Get destination port mask field. + uint16_t getDstPortMask() const; + /// Set destination port mask field to @a mask. + self& setDstPortMask(uint16_t mask); + + /// Append a value to this set. + self& addValue( + uint32_t cacheAddr, ///< Address of cache for this value. + uint32_t srcAddr, ///< Value for source address. + uint32_t dstAddr, ///< Value for destination address. + uint16_t srcPort, ///< Value for source port. + uint16_t dstPort ///< Value for destination port. + ); + + /// Get the value count. + /// @note No corresponding @c set because this cannot be directly changed. + uint32_t getCount() const; + /// Access value element. + ValueElt& operator [] ( + int idx ///< Index of target element. + ); + //@} + /// Calcuate the size of an element with @a n values. + static size_t calcSize( + uint32_t n ///< Number of values. + ); + /// Get the size (length) of this element. + size_t getSize() const; +protected: + // All members are kept in network order. + MaskElt m_mask; ///< Base mask element. + uint32_t m_count; ///< Number of value elements. + + /// Get base address of Value elements. + ValueElt* values(); + /// Get base address of Value elements. + ValueElt const* values() const; +}; + +/// Assignment of caches by hash. +/// Not in specification. +class HashAssignElt { +public: + typedef HashAssignElt self; ///< Self reference type. + + /// Hash assignment bucket. + struct Bucket { + unsigned int m_idx:7; ///< Cache index. + unsigned int m_alt:1; ///< Alternate hash flag. + + /// Test for unassigned value in bucket. + bool is_unassigned() const; + } __attribute__((aligned(1),packed)); + + /// Default constructor - @b no initialization. + HashAssignElt(); + /// Construct with @n elements. + HashAssignElt( + int n ///< Number of elements. + ); + + /// @name Accessors + //@{ + /// Get the number of caches. + uint32_t getCount() const; + /// Get a cache address. + uint32_t getAddr( + int idx ///< Index of target address. + ) const; + /// Set a cache address. + self& setAddr( + int idx, ///< Index of target address. + uint32_t addr ///< Address value to set. + ); + /// Access a bucket. + Bucket& operator [] ( + size_t idx ///< Bucket index (0..N_BUCKETS-1) + ); + /// Access a const bucket. + Bucket const& operator [] ( + size_t idx ///< Bucket index (0..N_BUCKETS-1) + ) const; + //@} + + /** Do a round robin assignment. + The buckets are assigned round robin, starting with 0, up to the + index of the last cache. + @return @c this. + */ + self& round_robin_assign(); + + /// Get size in bytes of this structure. + size_t getSize() const; + /// Calculate size in bytes for @a n caches. + static size_t calcSize( + int n ///< Number of caches. + ); +protected: + uint32_t m_count; ///< # of caches (network order). + + Bucket* getBucketBase(); +}; + +/** Assignment of caches by mask. + @note Not in specification. + + @internal Because this is an element, it must correspond exactly + to the serialized layout. Therefore we can't keep extra accounting + data around to make manipulation easier. We need a helper class + for that, which functions in a manner similar to an iterator. + */ + +class MaskAssignElt { +public: + typedef MaskAssignElt self; ///< Self reference type. + + /// Default constructor - @b no initialization. + MaskAssignElt(); + + /** A minimalist insert iterator. + */ + struct appender { + typedef appender self; ///< Self reference type. + /// Get pointer to current set. + MaskValueSetElt* operator -> (); + /// Append a new mask/value set. + /// @return A pointer to the new set. + MaskValueSetElt* mask( + uint32_t srcAddr, ///< Mask for source address. + uint32_t dstAddr, ///< Mask for destination address. + uint16_t srcPort, ///< Mask for source port. + uint16_t dstPort ///< Mask for destination port. + ); + /// Initialize the current set to empty with specific mask values. + /// @return A pointer to the new set. + MaskValueSetElt* initSet( + uint32_t srcAddr, ///< Mask for source address. + uint32_t dstAddr, ///< Mask for destination address. + uint16_t srcPort, ///< Mask for source port. + uint16_t dstPort ///< Mask for destination port. + ); + MaskValueSetElt* m_set; ///< Current set. + MaskAssignElt* m_elt; ///< Parent element. + }; + + /// @name Accessors + //@{ + /// Get the number of mask/value sets. + uint32_t getCount() const; + //@} + + appender init( + uint32_t srcAddr, ///< Mask for source address. + uint32_t dstAddr, ///< Mask for destination address. + uint16_t srcPort, ///< Mask for source port. + uint16_t dstPort ///< Mask for destination port. + ); + + /// Get size in bytes of this structure. + /// @note This is not constant time. The mask/value sets must be traversed + /// to get the total size. + size_t getSize() const; + /// Get the size in bytes of the variable part of this structure. + /// @note This is not constant time. The mask/value sets must be traversed + /// to get the total size. + size_t getVarSize() const; +protected: + uint32_t m_count; ///< # of sets (network order). + + friend struct appender; +}; + +class CacheIdBox; + +/** Sect 5.7.2: Web-Cache Identity Element + According to the specification, this is a fixed structure with + hash data. However, in practice there is an undocumented variant for + mask assignment where it contains mask data instead of hash data. + + This class provides basic control. Two subclasses specialize for the + two variants. Use @c isMask to detect which variant is present. + + @note Do not add virtual methods, as reasonable as that seems because + this is a serialized object and the memory layout correspond to the + protocol definition. + + @see CacheHashIdElt + @see CacheMaskIdElt +*/ +class CacheIdElt { + friend class CacheIdBox; +public: + typedef CacheIdElt self; ///< Self reference type. + + /// Hash revision (protocol required). + static uint16_t const HASH_REVISION = 0; + + /// @name Accessors + //@{ + uint32_t getAddr() const; ///< Get address field. + self& setAddr(uint32_t addr); ///< Set address field to @a addr. + uint16_t getHashRev() const; ///< Get hash revision field. + self& setHashRev(uint16_t rev); ///< Set hash revision field to @a rev. + self& initHashRev(); ///< Set hash revision to default value. + bool getUnassigned() const; ///< Get unassigned field. + self& setUnassigned(bool state); ///< Set unassigned field to @a state. + bool isMask() const; ///< @return @c true if this is a mask assignment. + /** Set the maskiness of this structure. + Be very careful with this, as different values change the + memory layout of the object. + */ + self& setMask( + bool state ///< @c true to be mask, @c false to be hash. + ); + + self& clearReserved(); ///< Set reserved bits to zero. + //@} + +protected: + uint32_t m_addr; ///< Identifying cache IP address. + uint16_t m_hash_rev; ///< Hash revision. + unsigned int m_reserved_0:7; ///< Reserved bits. + /** Cache not assigned. + If set the cache does not have an assignment in the redirection + hash table and the data in @a m_buckets is historical. This allows + a cache that was removed to be added back in the same buckets. + */ + unsigned int m_unassigned:1; + unsigned int m_reserved_1:1; ///< Reserved (unused). + unsigned int m_is_mask:1; ///< Set -> mask, Clear -> hash. + unsigned int m_reserved_2:6; ///< Reserved (unused). + /** Trailing elements common to all cache ID variants. + Unfortunately, although @c weight and @c status are common, they are + after the variable data and so can't be put in the base class. + Best we can do is declare a struct for them for later convenience. + */ + struct Tail { + uint16_t m_weight; ///< Weight of assignment. + uint16_t m_status; ///< Cache status. + }; +}; + +/** Cache ID for Hash assignment. + */ +class CacheHashIdElt : public CacheIdElt { + friend class CacheIdBox; +public: + typedef CacheHashIdElt self; ///< Self reference type. + typedef CacheIdElt super; ///< Parent type. + /// Container for hash assignment. + typedef uint8_t HashBuckets[N_BUCKETS >> 3]; + /// @name Accessors + //@{ + bool getBucket(int idx) const; ///< Get bucket state at index @a idx. + /// Set bucket at index @a idx to @a state. + self& setBucket(int idx, bool state); + self& setBuckets(bool state); ///< Set all buckets to @a state. + uint16_t getWeight() const; ///< Get weight field. + self& setWeight(uint16_t w); ///< Set weight field to @a w. + uint16_t getStatus() const; ///< Get status field. + self& setStatus(uint16_t s); ///< Set status field to @a s. + //@} + /// Get object size in bytes. + size_t getSize() const; +protected: + /// Bit vector of buckets assigned to this cache. + HashBuckets m_buckets; + Tail m_tail; /// Trailing values in element. + + /// Get the address of the tail elements. + Tail* getTailPtr(); +}; + +/** Cache ID for Mask assignment. + Be a little careful with this object. Because it's an element and + must copy the serialized data layout, almost all of the methods are + not constant time but require walking internal data structures. + + @internal Experimentally, + - A mask assign element count of zero does not work. It fails + with the wrongly descriptive message "incompatible assignment data". + - A single mask assign element with a mask set with one value seems to + work. + */ +class CacheMaskIdElt : public CacheIdElt { + friend class CacheIdBox; +public: + typedef CacheMaskIdElt self; ///< Self reference type. + typedef CacheIdElt super; ///< Parent type. + /// @name Accessors + //@{ + uint16_t getWeight() const; ///< Get weight field. + self& setWeight(uint16_t w); ///< Set weight field to @a w. + uint16_t getStatus() const; ///< Get status field. + self& setStatus(uint16_t s); ///< Set status field to @a s. + /// Get the number of mask/value sets. + uint32_t getCount() const; + //@} + /// Get object size in bytes. + size_t getSize() const; +protected: + /// Mask assignment data. + MaskAssignElt m_assign; + /// Get a pointer to where the tail data is. + /// Presumes the assignment is filled out. + Tail* getTailPtr(); +}; + +/** Holder for a @c CacheIdElt. + This class is needed because of the restrictions on element classes and + because a @c CacheIdElt is a variable sized element yet we need to store + instances of it in other classes. This box both holds an instance and + handles some of the memory allocation issues involved. + */ +class CacheIdBox { +public: + typedef CacheIdBox self; ///< Self reference type. + + /// Default constructor. + CacheIdBox(); + + /// @name Accessors + //@{ + /// Get the identifying cache address. + uint32_t getAddr() const; + /// Set the identifying cache address. + self& setAddr( + uint32_t ///< Identifying IP address. + ); + uint16_t getHashRev() const; ///< Get hash revision field. + self& setHashRev(uint16_t rev); ///< Set hash revision field to @a rev. + self& initHashRev(); ///< Set hash revision to default value. + bool getUnassigned() const; ///< Get unassigned field. + self& setUnassigned(bool state); ///< Set unassigned field to @a state. + bool isMask() const; ///< @return @c true if this is a mask assignment. + /** Set the maskiness of this structure. + Be very careful with this, as different values change the + memory layout of the object. + */ + self& setMask( + bool state ///< @c true to be mask, @c false to be hash. + ); + + self& clearReserved(); ///< Set reserved bits to zero. + //@} + /// Initialize to unassigned hash. + /// The cache address is set to @a addr. + self& initDefaultHash( + uint32_t addr ///< Identifying cache address. + ); + /// Initialize to unassigned mask + /// The cache address is set to @a addr. + self& initDefaultMask( + uint32_t addr ///< Identifying cache address. + ); + /** Fill in element from source copy. + Internal memory is allocated and the @a src copied. + */ + self& fill( + self const& src ///< Original source element + ); + /** Fill in element from source copy. + This is used to write the element to memory that is allocated + independently of the box. + @note Caller is expected to have verified sufficient buffer space. + */ + self& fill( + void* base, ///< Target buffer. + self const& src ///< Original source element + ); + /// Initialize box from an existing element in memory. + int parse( + MsgBuffer base ///< Source memory. + ); + + /// Get the size in bytes of the contained element. + size_t getSize() const; +protected: + /// Force buffer to be at least @a n bytes + self& require( + size_t n ///< Minimum buffer size required. + ); + + CacheIdElt* m_base; ///< Base address of memory for element. + CacheIdElt::Tail* m_tail; ///< Base address of trailing data elements. + size_t m_size; ///< Size of element (valid data in buffer); + size_t m_cap; ///< Size of allocated memory. Zero if external memory. +}; + +/** Base class for all components. + + Each component is a fixed sized object that represents a + component in the WCCP message. The component instance points at + its corresponding data in the message. Values in the message are + accessed through accessor methods which have the form @c + getNAME and @c setNAME for "get field" and "set field". The + @c set methods return a reference to the component so that + they can be chained. + + Most components will have an internal typedef @c raw_t which is a + structure with the exact memory layout of the + component. Components without this typedef cannot be directed + represented by a C++ structure (which is why we need this + indirection in the first place). +*/ +class ComponentBase { +public: + typedef ComponentBase self; ///< Self reference type. + /// Default constructor. + ComponentBase(); + /// Check for not present. + bool isEmpty() const; + +protected: + /// Base of component in message data. + /// If this is @c NULL then the component is not in the message. + char* m_base; +}; + +/// Synthetic component to represent the overall message header. +class MsgHeaderComp : public ComponentBase { +public: + typedef MsgHeaderComp self; ///< Self reference type. + typedef ComponentBase super; ///< Parent type. + + /// Sect 5.5: Message Header + /// Serialized layout of message header. + struct raw_t { + uint32_t m_type; ///< @c message_type_t + uint16_t m_version; ///< Implementation version of sender + uint16_t m_length; ///< Message body length (excluding header) + }; + + /// Default constructor. + MsgHeaderComp() {} + + /// @name Accessors + //@{ + message_type_t getType(); ///< Get message type field. + uint16_t getVersion(); ///< Get message version field. + uint16_t getLength(); ///< Get message length field. + self& setType(message_type_t type); ///< Set message type field to @a type. + self& setVersion(uint16_t version); ///< Set version field to @a version. + self& setLength(uint16_t length); ///< Set length field to @a length. + //@} + + /// Write initial values to message data. + /// @a base is updated to account for this component. + self& fill( + MsgBuffer& base, ///< [in,out] Buffer for component storage. + message_type_t t ///< Message type. + ); + + /// Validate component for existing data. + /// @a base is updated to account for this component. + int parse( + MsgBuffer& base ///< [in,out] Base address for component data. + ); + + /// Compute size of a component of this type. + static size_t calcSize(); + + /// Convert to a top level message type. + /// @return The converted type if valid, @c INVALID_MSG_TYPE if not. + static message_type_t toMsgType(int t); +}; + +/** Intermediate base class for components with the standard component header. + + @note That's all of them except the message header itself. + + @internal This saves some work getting around C++ co-variance issues + with return values. +*/ +template < + typename T ///< Child class (CRT pattern) + > +struct CompWithHeader : public ComponentBase { + /** Serialized layout of per component header. + All components except the message header start with this structure. + Provided for ease of use by child classes, which should + subclass this for their own @c raw_t. + */ + struct raw_t { + uint16_t m_type; ///< Serialized @ref CompType. + uint16_t m_length; ///< length of rest of component (not including header). + }; + /** Size of header. + This is needed by all subclasses because the value in the length field + excludes this structure. + */ + static size_t const HEADER_SIZE = sizeof(raw_t); + + /// @name Accessors + //@{ + CompType getType() const; ///< Get component type field. + uint16_t getLength() const; ///< Get component length field. + T& setType(CompType type); ///< Set component type field to @a type. + T& setLength(uint16_t length); ///< Set length field to @a length. + //@} + + /** Check the component header for type and length sanity. + This requires the (subclass) client to + - Do a size check to verify enough space for the component header. + - Set @a m_base + + This method + - Checks the component type against the expected type (@a ect) + - Checks stored component length against the buffer size. + + @return A parse result. + */ + int checkHeader( + MsgBuffer const& buffer, ///< Message buffer. + CompType t ///< Expected component type. + ); +}; + +/** Sect 5.6.1: Security Info Component + This is used for both security options. Clients should check + the @c m_option to see if the @a m_impl member is valid. +*/ +class SecurityComp + : public CompWithHeader { + +public: + typedef SecurityComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + /// Specify the type for this component. + static CompType const COMP_TYPE = SECURITY_INFO; + + /// Import security option type. + typedef SecurityOption Option; + + static size_t const KEY_SIZE = 8; + typedef char Key[KEY_SIZE]; + + /// Raw memory layout, no security. + struct RawNone : public super::raw_t { + uint32_t m_option; ///< @c Option + }; + + /// Raw memory layout, with MD5. + struct RawMD5 : public RawNone { + /// Size of MD5 hash (in bytes). + static size_t const HASH_SIZE = 16; + /// Storage for MD5 hash. + typedef uint8_t HashData[HASH_SIZE]; + /// MD5 hash value. + HashData m_data; + }; + + /// Default constructor. + SecurityComp(); + + /// @name Accessors + //@{ + Option getOption() const; ///< Get security option field. + self& setOption(Option opt); ///< Set security option field to @a opt. + //@} + + /// Write default values to the serialization buffer. + self& fill(MsgBuffer& buffer, Option opt = m_default_opt); + /// Validate an existing structure. + int parse(MsgBuffer& buffer); + + /// Compute the memory size of the component. + static size_t calcSize(Option opt); + + /// Set the global / default security key. + /// This is used for the security hash unless the local key is set. + /// @a key is copied to a global buffer and clipped to @c KEY_SIZE bytes. + static void setDefaultKey( + char const* key ///< Shared key. + ); + static void setDefaultOption( + Option opt ///< Type of security. + ); + + /// Set messsage local security key. + self& setKey( + char const* key ///< Shared key. + ); + + /// Compute and set the security data. + /// @a msg must be a buffer that covers exactly the entire message. + self& secure( + MsgBuffer const& msg ///< Message data. + ); + + bool validate( + MsgBuffer const& msg ///< Message data. + ) const; + +protected: + /// Local to this message shared key / password. + Key m_key; + /// Use local key. + bool m_local_key; + /// Global (static) shared key / password. + static Key m_default_key; + /// Default security option. + static Option m_default_opt; +}; + +/// Sect 5.6.2: Service Info Component +class ServiceComp + : public CompWithHeader { + +public: + typedef ServiceComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Specify the type for this component. + static CompType const COMP_TYPE = SERVICE_INFO; + + /// Serialized format for component. + struct raw_t : public super::raw_t, public ServiceGroup { + }; + + ServiceComp(); ///< Default constructor, no member intialization. + + /// @name Accessors + //@{ + ServiceGroup::Type getSvcType() const; ///< Get service type field. + /** Set the service type. + If @a svc is @c SERVICE_STANDARD then all fields except the + component header and service id are set to zero as required + by the protocol. + */ + self& setSvcType(ServiceGroup::Type svc); + + uint8_t getSvcId() const; ///< Get service ID field. + self& setSvcId(uint8_t id); ///< Set service ID field to @a id. + + uint8_t getPriority() const; ///< Get priority field. + self& setPriority(uint8_t pri); ///< Set priority field to @a p. + + uint8_t getProtocol() const; ///< Get protocol field. + self& setProtocol(uint8_t p); ///< Set protocol field to @a p. + + uint32_t getFlags() const; ///< Get flags field. + self& setFlags(uint32_t f); ///< Set the flags flags in field to @a f. + /// Set the flags in the flag field that are set in @a f. + /// Other flags are unchanged. + self& enableFlags(uint32_t f); + /// Clear the flags in the flag field that are set in @a f. + /// Other flags are unchanged. + self& disableFlags(uint32_t f); + + /// Get a port value. + uint16_t getPort( + int idx ///< Index of target port. + ) const; + /// Set a port value. + self& setPort( + int idx, ///< Index of port. + uint16_t port ///< Value for port. + ); + /// Zero (clear) all ports. + self& clearPorts(); + /** Add a port to the service. + The first port which has not been set is set to @a port. It is an error + to add more than @c N_PORTS ports. + */ + self& addPort( + uint16_t port ///< Port value. + ); + //@} + + /// Raw access to ServiceGroup. + operator ServiceGroup const& () const; + + /** Fill from a service group definition. + */ + self& fill( + MsgBuffer& base, ///< Target storage. + ServiceGroup const& svc ///< Service group definition. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the memory size of the component. + static size_t calcSize(); + +protected: + int m_port_count; ///< Number of ports in use. + + /// Cast raw internal pointer to data type. + raw_t* access(); + /// Cast raw internal pointer to data type. + raw_t const* access() const; +}; + +/// Sect 5.6.3: RouterIdentity Info Component +/// @note An instance of this struct is followed by @a m_count +/// IP addresses. +class RouterIdComp + : public CompWithHeader { + +public: + typedef RouterIdComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Specify the type for this component. + static CompType const COMP_TYPE = ROUTER_ID_INFO; + + /// Stub of serialized layout. + struct raw_t : public super::raw_t { + RouterIdElt m_id; ///< Router ID element. + /// Source address. + /// For response messages, this is the address to which the + /// original message was sent. + uint32_t m_to_addr; + /// # of target cache addresses. + uint32_t m_from_count; + // Addresses follow here. + }; + + /// @name Accessors + //@{ + /// Directly access router ID element. + RouterIdElt& idElt(); + /// Directly access router ID element. + RouterIdElt const& idElt() const; + /// Set the fields in the router ID element. + self& setIdElt( + uint32_t addr, ///< Identifying IP address for router. + uint32_t recv_id ///< Receive count for router to target cache. + ); + uint32_t getAddr() const; ///< Get the address field in the ID element. + self& setAddr(uint32_t addr); ///< Set the address field in the ID element. + uint32_t getRecvId() const; ///< Get the receive ID field in the ID element. + self& setRecvId(uint32_t id); ///< Set the receive ID field in the ID element. + + /// Get the sent to address. + uint32_t getToAddr() const; + /// Set the sent to address. + self& setToAddr( + uint32_t addr ///< Address value. + ); + /// Get router count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getFromCount() const; + /// Get received from address. + uint32_t getFromAddr( + int idx ///< Index of address. + ) const; + /// Set received from address. + self& setFromAddr( + int idx, ///< Index of address. + uint32_t addr ///< Address value. + ); + //@} + /// Find an address in the from list. + /// @return The index of the address, or -1 if not found. + int findFromAddr( + uint32_t addr ///< Search value. + ); + + /** Write serialization data for single cache target. + This completely fills the component. + */ + self& fillSingleton( + MsgBuffer& base, ///< Target storage. + uint32_t addr, ///< Identifying IP address. + uint32_t recv_count, ///< Receive count for target cache. + uint32_t to_addr, ///< Destination address in initial packet. + uint32_t from_addr ///< Identifying IP address of target cache. + ); + + /** Write basic message structure. + The router and cache data must be filled in separately. + */ + self& fill( + MsgBuffer& base, ///< Target storage. + size_t n_caches ///< Number of caches (fromAddr). + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the memory size of the component. + static size_t calcSize( + int n ///< Receive address count + ); +}; + +/** Sect 5.6.4: Web-Cache Identity Info Component +*/ +class CacheIdComp + : public CompWithHeader { + +public: + typedef CacheIdComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = CACHE_ID_INFO; + + /// Serialized format. + struct raw_t : public super::raw_t { + CacheIdElt m_id; ///< Identity element stub. + }; + + /// @name Accessors + //@{ + /// Direct access to the cache ID element. + CacheIdBox& cacheId(); + CacheIdBox const& cacheId() const; + + // Only forward the common ones. + uint32_t getAddr() const; ///< Get address field. + self& setAddr(uint32_t addr); ///< Set address field to @a addr. + uint16_t getHashRev() const; ///< Get hash revision field. + self& setHashRev(uint16_t rev); ///< Set hash revision field to @a rev. + bool getUnassigned() const; ///< Get unassigned field. + self& setUnassigned(bool state); ///< Set unassigned field to @a state. + uint16_t getWeight() const; ///< Get weight field. + self& setWeight(uint16_t w); ///< Set weight field to @a w. + uint16_t getStatus() const; ///< Get status field. + self& setStatus(uint16_t s); ///< Set status field to @a s. + //@} + + /** Write serialization data. + - Sets required header fields for the component. + - Copies the data from @a src. + */ + self& fill( + MsgBuffer& base, ///< Target storage. + CacheIdBox const& src ///< Cache descriptor + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the memory size of the component. + /// Cannot be reliably computed statically. + size_t getSize(); +protected: + CacheIdBox m_box; ///< Wrapper for cache id element. +}; + +/** Sect 5.6.5: Router View Info Component + */ +class RouterViewComp + : public CompWithHeader { + +public: + typedef RouterViewComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = RTR_VIEW_INFO; + + /// Stub of the serialized data. + /// There is more variable sized data that must be handled specially. + struct raw_t : public super::raw_t { + uint32_t m_change_number; ///< Sequence number. + AssignmentKeyElt m_key; ///< Assignment data. + uint32_t m_router_count; ///< # of router elements. + }; + + RouterViewComp(); + + /// @name Accessors + //@{ + /// Directly access assignment key. + AssignmentKeyElt& keyElt(); + /// Directly access assignment key. + AssignmentKeyElt const& keyElt() const; + /// Get address in assignment key. + uint32_t getKeyAddr() const; + /// Set address in assignment key. + self& setKeyAddr(uint32_t addr); + /// Get change number in assignment key. + uint32_t getKeyChangeNumber() const; + /// Set change number in assignment key. + self& setKeyChangeNumber(uint32_t n); + + uint32_t getChangeNumber() const; ///< Get change number field. + self& setChangeNumber(uint32_t n); ///< Set change number field to @a n + + /// Get cache count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getCacheCount() const; + /// Access cache element. + CacheIdBox& cacheId( + int idx ///< Index of target element. + ); + /// Access cache element. + CacheIdBox const& cacheId( + int idx ///< Index of target element. + ) const; + /// Get router count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getRouterCount() const; + /// Get router address. + uint32_t getRouterAddr( + int idx ///< Index of router. + ) const; + /// Set router address. + self& setRouterAddr( + int idx, ///< Index of router. + uint32_t addr ///< Address value. + ); + //@} + + /** Write serialization data. + + A client @b must call this method before writing any fields directly. + After invocation the client must fill in the router and cache elements. + */ + self& fill( + MsgBuffer& base, ///< Target storage. + int n_routers, ///< Number of routers in view. + int n_caches ///< Number of caches in view. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + +protected: + /// Serialized count of cache addresses. + /// The actual addresses start immediate after this. + uint32_t* m_cache_count; + /// Wrappers for cache identity elements. + /// These are variably sized in the general case. + CacheIdBox m_cache_ids[MAX_CACHES]; + + /// Compute the address of the cache count field. + /// Assumes the router count field is set. + uint32_t* calc_cache_count_ptr(); +}; + +/** Sect 5.6.6: Web-Cache View Info Component + */ +class CacheViewComp + : public CompWithHeader { + +public: + typedef CacheViewComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = CACHE_VIEW_INFO; + + /// Stub of the serialized data. + /// There is more variable sized data that must be handled specially. + struct raw_t : public super::raw_t { + uint32_t m_change_number; ///< Sequence number. + uint32_t m_router_count; ///< # of router ID elements. + }; + + /// @name Accessors + //@{ + uint32_t getChangeNumber() const; ///< Get change number field. + self& setChangeNumber(uint32_t n); ///< Set change number field to @a n + + /// Get router count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getRouterCount() const; + /// Access a router ID element. + RouterIdElt& routerElt( + int idx ///< Index of target element. + ); + /** Find a router element by router IP address. + @return A pointer to the router element or @c NULL + if no router is identified by @a addr. + */ + RouterIdElt* findf_router_elt( + uint32_t addr ///< Router IP address. + ); + /// Get cache count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getCacheCount() const; + /// Get a cache address. + uint32_t getCacheAddr( + int idx ///< Index of target address. + ) const; + /// Set a cache address. + self& setCacheAddr( + int idx, ///< Index of target address. + uint32_t addr ///< Address value to set. + ); + //@} + + /** Write serialization data. + + A client @b must call this method before writing any fields directly. + After invocation the client must fill in the router and cache elements. + */ + self& fill( + MsgBuffer& buffer, ///< Target storage. + detail::cache::GroupData const& group ///< Service group information. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the total size of the component. + static size_t calcSize( + int n_routers, ///< Number of routers in view. + int n_caches ///< Number of caches in view. + ); + +protected: + /// Get router element array. + /// @return A pointer to the first router element. + RouterIdElt* atf_router_array(); + /// Serialized count of cache addresses. + /// The actual addresses start immediate after this. + uint32_t* m_cache_count; +}; + +/** Sect 5.6.7: Assignment Info Component + */ +class AssignInfoComp + : public CompWithHeader { + +public: + typedef AssignInfoComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = REDIRECT_ASSIGNMENT; + + /// Stub of the serialized data. + /// There is more variable sized data that must be handled specially. + struct raw_t : public super::raw_t { + AssignmentKeyElt m_key; ///< Assignment key data. + RouterAssignListElt m_routers; ///< Routers. + }; + typedef HashAssignElt::Bucket Bucket; ///< Import type. + + /// @name Accessors + //@{ + /// Directly access assignment key. + AssignmentKeyElt& keyElt(); + /// Directly access assignment key. + AssignmentKeyElt const& keyElt() const; + /// Get address in assignment key. + uint32_t getKeyAddr() const; + /// Set address in assignment key. + self& setKeyAddr(uint32_t addr); + /// Get change number in assignment key. + uint32_t getKeyChangeNumber() const; + /// Set change number in assignment key. + self& setKeyChangeNumber(uint32_t n); + + /// Get router count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getRouterCount() const; + /// Access a router assignment element. + RouterAssignElt& routerElt( + int idx ///< Index of target element. + ); + /// Get cache count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getCacheCount() const; + /// Get a cache address. + uint32_t getCacheAddr( + int idx ///< Index of target address. + ) const; + /// Set a cache address. + self& setCacheAddr( + int idx, ///< Index of target address. + uint32_t addr ///< Address value to set. + ); + /// Access a bucket. + Bucket& bucket( + int idx ///< Index of target bucket. + ); + /// Access a bucket. + Bucket const& bucket( + int idx ///< Index of target bucket. + ) const; + /** Compare a set of buckets. + @return @c true if the buckets are the same, @c false otherwise. + */ + bool compare( + Bucket const buckets[N_BUCKETS] ///< Buckets to compare. + ) const; + //@} + + /// Fill out the component from an @c Assignment. + self& fill( + MsgBuffer& buffer, ///< Target storage. + detail::Assignment const& assign ///< Assignment data. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the total size of the component. + static size_t calcSize( + int n_routers, ///< Number of routers in view. + int n_caches ///< Number of caches in view. + ); + +protected: + /// Serialized count of cache addresses. + /// The actual addresses start immediate after this. + uint32_t* m_cache_count; + /// Serialized bucket data. + Bucket* m_buckets; + /// Calculate the address of the cache count. + uint32_t* calcCacheCountPtr(); + /// Calculate the address of the bucket array. + Bucket* calcBucketPtr(); +}; + +/** Sect 5.6.9: Capabilities Info Component + */ +class CapComp + : public CompWithHeader { + +public: + typedef CapComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = CAPABILITY_INFO; + + // Not even a stub for this component, just an array of elements. + + /// Default constructor. + CapComp(); + + /// @name Accessors. + //@{ + /// Directly access mask value element. + CapabilityElt& elt( + int idx ///< Index of target element. + ); + CapabilityElt const& elt( + int idx ///< Index of target element. + ) const; + /// Get the element count. + /// @note No corresponding @c setf_ because that cannot be changed once set. + /// @see fill + uint32_t getEltCount() const; + //@} + + /** Write serialization data. + + The capability elements must be filled @b after invoking this method. + And, of course, do not fill more than @a n of them. + */ + self& fill( + MsgBuffer& buffer, ///< Target storage. + int n ///< Number of capabilities. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the total size of the component. + static size_t calcSize( + int n ///< Number of capabilities. + ); + + /// Find value for Cache Assignment. + ServiceGroup::CacheAssignmentStyle getCacheAssignmentStyle() const; + /// Find value for packet forwarding. + ServiceGroup::PacketStyle getPacketForwardStyle() const; + /// Find value for packet return. + ServiceGroup::PacketStyle getPacketReturnStyle() const; + /// Invalidate cached values. + /// Needed after modifying elements via the @c elt method. + self& invalidate(); + +protected: + /// Fill the cached values. + void cache() const; + + int m_count; ///< # of elements. + /** Whether the style values are valid. + We load all the values on the first request because we have to walk + all the capabilities anyway, and cache them. + */ + mutable bool m_cached; + /// Style used to forward packets to cache. + mutable ServiceGroup::PacketStyle m_packet_forward; + /// Style used to return packets to the router. + mutable ServiceGroup::PacketStyle m_packet_return; + /// Style used to make cache assignments. + mutable ServiceGroup::CacheAssignmentStyle m_cache_assign; +}; + +/** Sect 5.6.10: Alternate Assignment Component + This is an abstract base class. It is specialized for each alternate. + */ +class AltAssignComp + : public CompWithHeader { + +public: + typedef AltAssignComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = ALT_ASSIGNMENT; + /// Alternate is hash. + static uint16_t const ALT_HASH_ASSIGNMENT = 0; + /// Alternate is mask. + static uint16_t const ALT_MASK_ASSIGNMENT = 1; + + /// Component secondary header. + /// @internal Split out because we need to compute its size. + struct local_header_t { + uint16_t m_assign_type; ///< Assignment body type. + uint16_t m_assign_length; ///< Assignment body length. + }; + /// Stub of the serialized data. + /// There is more variable sized data that must be handled specially. + struct raw_t : public super::raw_t, public local_header_t { + // These are the same in all current subclasses. + AssignmentKeyElt m_key; ///< Assignment key data. + RouterAssignListElt m_routers; ///< Routers. + }; + + /// Force virtual desctructor. + virtual ~AltAssignComp() {} + + /// @name Accessors + //@{ + /// Get the assignment type. + uint16_t getAssignType() const; + /// Set the assignment type. + self& setAssignType( + uint16_t t ///< Assignment type. + ); + /// Get the assignment length. + uint16_t getAssignLength() const; + /// Set the assignment length. + self& setAssignLength( + uint16_t length ///< Length in bytes. + ); + /// Get router count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getRouterCount() const; + /// Directly access assignment key. + AssignmentKeyElt& keyElt(); + /// Directly access assignment key. + AssignmentKeyElt const& keyElt() const; + //@} + + /// Fill out the component from an @c Assignment. + virtual self& fill( + MsgBuffer& buffer, ///< Target storage. + detail::Assignment const& assign ///< Assignment data. + ) = 0; + + /// Validate an existing structure. + /// @return Parse result. + virtual int parse(MsgBuffer& buffer) = 0; + +protected: + /// Calculate the first byte past the end of the variable data. + void* calcVarPtr(); +}; + +/** Sect 5.6.10: Alternate Assignment Component + This is the hash based version. + */ +class AltHashAssignComp + : public AltAssignComp { + +public: + typedef AltHashAssignComp self; ///< Self reference type. + typedef AltAssignComp super; ///< Parent type. + + /// @name Accessors + //@{ + /// Get cache count field. + /// @note No @c setf method because this cannot be changed independently. + /// @see fill + uint32_t getCacheCount() const; + //@} + + /// Force virtual desctructor. + virtual ~AltHashAssignComp() {} + + /// Fill out the component from an @c Assignment. + virtual self& fill( + MsgBuffer& buffer, ///< Target storage. + detail::Assignment const& assign ///< Assignment data. + ); + + /// Validate an existing structure. + /// @return Parse result. + virtual int parse(MsgBuffer& buffer); + + /// Compute the total size of the component. + static size_t calcSize( + int n_routers, ///< Number of routers in view. + int n_caches ///< Number of caches in view. + ); + +protected: + /// Serialized count of cache addresses. + /// The actual addresses start immediate after this. + uint32_t* m_cache_count; + /// Calculate the address of the cache count. + uint32_t* calcCacheCountPtr(); +}; + +/** Sect 5.6.10: Alternate Assignment Component + This is the mask based version. + */ +class AltMaskAssignComp + : public AltAssignComp { + +public: + typedef AltMaskAssignComp self; ///< Self reference type. + typedef AltAssignComp super; ///< Parent type. + + /// Force virtual desctructor. + virtual ~AltMaskAssignComp() {} + + /// Fill out the component from an @c Assignment. + virtual self& fill( + MsgBuffer& buffer, ///< Target storage. + detail::Assignment const& assign ///< Assignment data. + ); + + /// Validate an existing structure. + /// @return Parse result. + virtual int parse(MsgBuffer& buffer); + +protected: + MaskAssignElt* m_mask_elt; ///< Address of the mask assign element. +}; + +/** Sect 5.6.12: Command Info Component + */ +class CmdComp + : public CompWithHeader { + +public: + typedef CmdComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = COMMAND_EXTENSION; + + /// Command types. + enum cmd_t { + SHUTDOWN = 1, ///< Cache is shutting down. + SHUTDOWN_RESPONSE = 2 ///< SHUTDOWN ack. + }; + + /// Serialized data layout. + /// @internal Technically the command data is variable, but all currently + /// defined commands have the same 32 bit data element. + struct raw_t : public super::raw_t { + uint16_t m_cmd; ///< Command type / code. + uint16_t m_cmd_length; ///< Length of command data. + uint32_t m_cmd_data; ///< Command data. + }; + + /// @name Accessors. + //@{ + /// Directly access mask value element. + cmd_t getCmd() const; ///< Get command type. + self& setCmd(cmd_t cmd); ///< Set command type. + uint32_t getCmdData() const; ///< Get command data. + self& setCmdData(uint32_t data); ///< Set command @a data. + //@} + + /// Write basic serialization data. + /// Elements must be filled in seperately and after invoking this method. + self& fill( + MsgBuffer& buffer, ///< Component storage. + cmd_t cmd, ///< Command type. + uint32_t data ///< Command data. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the total size of the component. + static size_t calcSize(); +}; + +/// Sect 5.6.11: Assignment Map Component +class AssignMapComp + : public CompWithHeader { + +public: + typedef AssignMapComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = ASSIGN_MAP; + + /// Serialized layout structure. + /// Not complete, only a stub. + struct raw_t : public super::raw_t { + MaskAssignElt m_assign; + }; + + /// Default constructor. + AssignMapComp(); + + /// @name Accessors. + //@{ + /// Get the element count. + uint32_t getCount() const; + //@} + + /// Fill from assignment data. + self& fill( + MsgBuffer& buffer, ///< Component storage. + detail::Assignment const& assign ///< Assignment data. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); +}; + +/// Sect 5.6.8: Router Query Info Component. +class QueryComp + : public CompWithHeader { +public: + typedef QueryComp self; ///< Self reference type. + typedef CompWithHeader super; ///< Parent type. + + /// Component type ID for this component. + static CompType const COMP_TYPE = QUERY_INFO; + + /// Internal layout. + struct raw_t : public super::raw_t { + uint32_t m_router_addr; ///< Identifying router address. + uint32_t m_recv_id; ///< Receive ID router expects in reply. + uint32_t m_to_addr; ///< Destination address of query. + uint32_t m_cache_addr; ///< Identifying address of cache. + }; + + /// @name Accessors. + //@{ + /// Directly access mask value element. + uint32_t getRouterAddr() const; ///< Get identifying router address. + self& setRouterAddr(uint32_t addr); ///< Set identifying router address. + uint32_t getToAddr() const; ///< Get target address. + self& setToAddr(uint32_t addr); ///< Set target address. + uint32_t getCacheAddr() const; ///< Get identifying cache address. + self& setCacheAddr(uint32_t addr); ///< Set identifying cache address. + uint32_t getRecvId() const; ///< Get receive ID. + self& setRecvId(uint32_t data); ///< Set receive ID. + //@} + + /// Write serialization data. + /// This fills in all fields. + self& fill( + MsgBuffer& buffer, ///< Component storage. + uint32_t routerAddr, ///< Router identifying address. + uint32_t toAddr, ///< Destination address. + uint32_t cacheAddr, ///< Cache identifying address. + uint32_t recvId ///< Recieve ID. + ); + + /// Validate an existing structure. + /// @return Parse result. + int parse(MsgBuffer& buffer); + + /// Compute the total size of the component. + static size_t calcSize(); +}; + +/// Cache assignment hash function. +inline uint8_t +assignment_hash( + uint32_t key ///< Key to hash. +) { + key ^= key >> 16; + key ^= key >> 8; + return key & 0xFF; +} + +/// IP header information for a receive message. +struct IpHeader { + uint32_t m_src; ///< Source address. + uint32_t m_dst; ///< Destination address. +}; + +// Various static values. +char const* const BUFFER_TOO_SMALL_FOR_COMP_TEXT = "Unable to write component -- buffer too small"; + +// ------------------------------------------------------ +namespace detail { + /** Local storage for cache assignment data. + The maintenance of this data is sufficiently complex that it is better + to have a standard class to hold it, rather than updating a serialized + form. + */ + class Assignment { + public: + typedef Assignment self; ///< Self reference type. + typedef AssignmentKeyElt Key; ///< Import assignment key type. + /// Import assignment bucket definition. + /// @internal Just one byte, no serialization issues. + typedef AssignInfoComp::Bucket Bucket; + + /// Default constructor. Initialization to empty state. + Assignment(); + + /** Check for active assignment. + + An assignment is active if it is is current. This means either it + was successfully generated on the cache side, or a valid assignment + was received on the router side and has not expired. + + @return The current active state. + */ + bool isActive() const; + /// Control active flag. + self& setActive( + bool state ///< New active state. + ); + + /** Fill the assignment from cache service group data. + Caches that are obsolete are purged from the data. + @return @c true if a valid assignment was generated, + @c false otherwise. + */ + bool fill( + cache::GroupData& group, ///< Service group data. + uint32_t addr ///< Identifying IP address of designated cache. + ); + /// Update the receive ID for a router. + self& updateRouterId( + uint32_t addr, ///< Identifying IP address of router. + uint32_t rcvid, ///< New receive ID. + uint32_t cno ///< New change number. + ); + + /// Get the assignment key. + AssignmentKeyElt const& getKey() const; + /// Get the router assignment list. + RouterAssignListElt const& getRouterList() const; + /// Get the hash assignment. + HashAssignElt const& getHash() const; + /// Get the mask assignment. + MaskAssignElt const& getMask() const; + + protected: + Key m_key; ///< Assignment key. + bool m_active; ///< Active state. + + // These store the serialized assignment chunks which are assembled + // in to the components as needed. Each points in to the serialization + // buffer, or is @c NULL if that assignment data isn't valid. + /// Router assignments. + RouterAssignListElt *m_router_list; + /// Hash assignment. + HashAssignElt *m_hash_assign; + /// Mask assignment. + MaskAssignElt *m_mask_assign; + + /// Buffer for serialization. + MsgBuffer m_buffer; + }; + + namespace endpoint { + /// Common service group data. + struct GroupData { + typedef GroupData self; ///< Self reference type. + + ServiceGroup m_svc; ///< The service definition. + uint32_t m_generation; ///< Generation value (change number). + time_t m_generation_time; ///< Time of last view change. + + bool m_use_security_opt; ///< Use group local security. + SecurityComp::Option m_security_opt; ///< Type of security. + bool m_use_security_key; ///< Use group local key. + SecurityComp::Key m_security_key; ///< MD5 key. + + /** Group assignment data. + This is used as a place to generate an assignment or + store one received from an extern source. + */ + detail::Assignment m_assign_info; + + /// Default constructor. + GroupData(); + /// Use @a key instead of global default. + self& setKey( + char const* key ///< Shared key. + ); + /// Use security @a style instead of global default. + self& setSecurity( + SecurityOption style ///< Security style to use. + ); + }; + } +} +// ------------------------------------------------------ +/** Base class for all messages. + */ +class BaseMsg { +public: + /// Default constructor. + BaseMsg(); + /// Destructor. + virtual ~BaseMsg() {} + + /// Set the message @a buffer. + void setBuffer( + MsgBuffer const& buffer ///< Storage for message. + ); + /// Get the current buffer. + MsgBuffer const& buffer() const; + /// Invoke once all components have been filled. + /// Sets the length and updates security data if needed. + virtual void finalize(); + /// Get available buffer space. + size_t getSpace() const; + /// Get the message size. + size_t getCount() const; + + /// Validate security option. + /// @note This presumes a sublcass has already successfully parsed. + bool validateSecurity() const; + + // Common starting components for all messages. + MsgHeaderComp m_header; ///< Message header. + SecurityComp m_security; ///< Security component. + ServiceComp m_service; ///< Service provided. + +protected: + MsgBuffer m_buffer; ///< Raw storage for message data. +}; + +/// Sect 5.1: Layout and control for @c WCCP2_HERE_I_AM +class HereIAmMsg + : public BaseMsg { +public: + typedef HereIAmMsg self; ///< Self reference type. + + /** Fill in the basic message structure. + This expects @c setBuffer to have already been called + with an appropriate buffer. + The actual router and cache data must be filled in + after this call, which will allocate the appropriate spaces + in the message layou. + */ + void fill( + detail::cache::GroupData const& group, ///< Service group for message. + CacheIdBox const& cache_id, ///< ID to use for this cache. + SecurityOption sec_opt ///< Security option to use. + ); + /** Fill in optional capabilities. + The capabilities component is added only if the @a router + is set to send them. + */ + void fill_caps( + detail::cache::RouterData const& router ///< Target router. + ); + /// Parse message data, presumed to be of this type. + int parse( + ts::Buffer const& buffer ///< Raw message data. + ); + + CacheIdComp m_cache_id; ///< Web cache identity info. + CacheViewComp m_cache_view; ///< Web cache view. + CapComp m_capabilities; ///< Capabilities data. + CmdComp m_command; ///< Command extension. +}; + +/// Sect 5.2: 'I See You' Message +class ISeeYouMsg + : public BaseMsg { +public: + typedef ISeeYouMsg self; ///< Self reference type. + + /// Fill out message structure. + /// Router ID and view data must be filled in seperately. + void fill( + detail::router::GroupData const& group, ///< Service groupc context. + SecurityOption sec_opt, ///< Security option. + detail::Assignment& assign, ///< Cache assignment data. + size_t to_caches, ///< # of target caches for message. + size_t n_routers, ///< Routers in view. + size_t n_caches, ///< Caches in view. + bool send_capabilities = false ///< Send capabilities. + ); + + /// Parse message data, presumed to be of this type. + int parse( + ts::Buffer const& buffer ///< Raw message data. + ); + + RouterIdComp m_router_id; ///< Router ID. + RouterViewComp m_router_view; ///< Router view data. + // The rest of these are optional. The spec says we should get + // an assignment or map, but in practice that doesn't happen with + // actual Cisco routers in the hash case. Perhaps it happens with + // a map. + AssignInfoComp m_assignment; ///< Assignment data. + AssignMapComp m_map; ///< Assignment map. + CapComp m_capabilities; ///< Capabilities data. + CmdComp m_command; ///< Command extension. +}; + +/// Sect 5.1: Layout and control for @c WCCP2_REDIRECT_ASSIGN +class RedirectAssignMsg + : public BaseMsg { +public: + typedef RedirectAssignMsg self; ///< Self reference type. + + /** Fill in the basic message structure. + This expects @c setBuffer to have already been called + with an appropriate buffer. + The actual router and cache data must be filled in + after this call, which will allocate the appropriate spaces + in the message layou. + */ + void fill( + detail::cache::GroupData const& group, ///< Service group for message. + SecurityOption sec_opt ///< Security option to use. + ); + + /// Parse message data, presumed to be of this type. + int parse( + ts::Buffer const& buffer ///< Raw message data. + ); + + // Only one of these should be present in an instance. + AssignInfoComp m_hash_assign; ///< Primary (hash) assignment. + AltHashAssignComp m_alt_hash_assign; ///< Alternate (hash) assignment. + AltMaskAssignComp m_alt_mask_assign; ///< Alternate (mask) assignment. +}; + +/// Sect 5.4: @c WCCP_REMOVAL_QUERY +class RemovalQueryMsg + : public BaseMsg { +public: + typedef RemovalQueryMsg self; ///< Self reference type. + + /** Fill in the basic message structure. + This expects @c setBuffer to have already been called + with an appropriate buffer. + The actual router and cache data must be filled in + after this call, which will allocate the appropriate spaces + in the message layou. + */ + void fill( + detail::cache::GroupData const& group, ///< Service group for message. + SecurityOption sec_opt, ///< Security option to use. + AssignmentKeyElt const& key, ///< Assignment key. + int n_routers, ///< Number of routers expected. + int n_caches ///< Number of caches expected. + ); + + /// Parse message data, presumed to be of this type. + int parse( + ts::Buffer const& buffer ///< Raw message data. + ); + + QueryComp m_query; ///< Router Removal Query component. +}; + +// ------------------------------------------------------ +/// Last packet information. +struct PacketStamp { + typedef PacketStamp self; ///< Self reference type. + + PacketStamp(); ///< Default constructor (zero elements). + /// Set the @a time and @a generation. + self& set(time_t time, uint32_t generation); + + time_t m_time; ///< Time when packet was sent/received. + uint32_t m_sn; ///< Sequence # of packet. +}; + +/** Implementation class for EndPoint. + All of the WCCP structures are defined in this class. + + A note on the component classes - these are designed to reside in + a side buffer which then points in to the actual message + buffer. This is done because the WCCP designers were not too + bright. Rather than packing the fixed sized elements in front and + using offsets to point at variables sized data, it's intermixed, + so it's not possible to declare C++ structures that map on to the + actual message data in all cases. And because mixed styles are + worse than a consistent mediocre style, we go with the latter and + put all the message structures on the side. This also means having + to use accessor methods. + */ +class Impl : public ts::IntrusivePtrCounter { + friend class EndPoint; +public: + typedef Impl self; ///< Self reference type. + + /// Import detail struct. + typedef detail::endpoint::GroupData GroupData; + + /// Default constructor. + Impl(); + /** Set the local address used for this endpoint. + If not set, an arbitrary local address will be + @note This can only be called once, and must be called before + @c open. + */ + /// Force virtual destructor. + virtual ~Impl(); + + /// Open a socket for communications. + /// @return 0 on success, -ERRNO on failure. + virtual int open( + uint32_t addr ///< Local IP address. + ); + + /// Use MD5 security. + void useMD5Security( + ts::ConstBuffer const& key ///< Shared key. + ); + + /// Perform all scheduled housekeeping functions. + /// @return 0 for success, -errno on error. + virtual int housekeeping() = 0; + + /// Recieve and process a message. + /// @return 0 for success, -ERRNO on system error. + virtual ts::Rv handleMessage(); + + /// Check if endpoint is configured. + /// @return @c true if ready to operate, @c false otherwise. + virtual bool isConfigured() const = 0; + + /* These handlers simply generate an error message and return. The + base @c handleMessage will read the data from the socket and + validate the message header. It then calls the appropriate one of + these specialized message handlers. Subclasses should override + to process relevant messages. + */ + /// Process HERE_I_AM message. + virtual ts::Errata handleHereIAm( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Buffer with message data. + ); + /// Process I_SEE_YOU message. + virtual ts::Errata handleISeeYou( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Buffer with message data. + ); + /// Process REDIRECT_ASSIGN message. + virtual ts::Errata handleRedirectAssign( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Buffer with message data. + ); + /// Process REMOVAL_QUERY message. + virtual ts::Errata handleRemovalQuery( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Buffer with message data. + ); + +protected: + /** Local address for this end point. + This is set only when the socket is open. + */ + uint32_t m_addr; + int m_fd; ///< Our socket. + + bool m_use_security_opt; ///< Use group local security. + SecurityComp::Option m_security_opt; ///< Type of security. + bool m_use_security_key; ///< Use group local key. + SecurityComp::Key m_security_key; ///< MD5 key. + + /// Close the socket. + void close(); + /// Set security options in a message. + /// @return Security option to use during message fill. + SecurityOption setSecurity( + BaseMsg& msg, ///< Message. + GroupData const& group ///< Group data used to control fill. + ) const; + /// Validate a security component. + bool validateSecurity( + BaseMsg& msg, ///< Message data (including security component). + GroupData const& group ///< Group data for message. + ); +}; +// ------------------------------------------------------ +namespace detail { + namespace cache { + /// Caches's view of caches. + struct CacheData { + /// Get the identifying IP address for this cache. + uint32_t idAddr() const; + /// Cache identity data. + CacheIdBox m_id; + /// Last time this cache was mentioned by the routers. + /// Indexed in parallel to the routers. + std::vector m_src; + }; + + /// Cache's view of routers. + struct RouterData { + /// Default constructor, no member initialization. + RouterData(); + /// Construct with address. + RouterData( + uint32_t addr ///< Router identifying address. + ); + + /// Time until next packet. + /// @return Seconds until a packet should be sent. + time_t waitTime( + time_t now ///< Current time. + ) const; + /// Time till next ping. + /// @return Seconds until a HERE_I_AM should be sent. + time_t pingTime( + time_t now ///< Current time. + ) const; + + uint32_t m_addr; ///< Router identifying IP address. + uint32_t m_generation; ///< Router's view change number. + /** Most recent packet received from router. + * The sequence number @a m_sn is the receive ID of the router. + */ + PacketStamp m_recv; + /** Most recent packet sent to router. + * The sequence number @a m_sn is the view generation of this cache. + */ + PacketStamp m_xmit; + /// Cache ID of this cache as reflected by this router. + CacheIdBox m_local_cache_id; + int m_rapid; ///< Rapid replies to send. + bool m_assign; ///< Send a REDIRECT_ASSIGN. + bool m_send_caps; ///< Send capabilities. + /// Packet forwarding method selected. + ServiceGroup::PacketStyle m_packet_forward; + /// Packet return method selected. + ServiceGroup::PacketStyle m_packet_return; + /// Cache assignment method selected. + ServiceGroup::CacheAssignmentStyle m_cache_assign; + + }; + + /// Data for a seeded router. + struct SeedRouter { + SeedRouter(); ///< Default constructor, no member initialization. + /// Construct with address @a addr. + /// Other members are zero initialized. + SeedRouter( + uint32_t addr + ); + uint32_t m_addr; ///< Address of router. + uint32_t m_count; ///< # of packets sent w/o response. + time_t m_xmit; ///< Time of last packet sent. + }; + + /// Storage type for known caches. + typedef std::vector CacheBag; + /// Storage type for known routers. + typedef std::vector RouterBag; + + /** Cache's view of a service group. + This stores the internal accounting information, it is not the + serialized form. + */ + struct GroupData : public endpoint::GroupData { + typedef GroupData self; ///< Self reference type. + typedef endpoint::GroupData super; ///< Parent type. + + /// Cache identity of this cache. + CacheIdBox m_id; + + /// Packet forwarding methods supported. + ServiceGroup::PacketStyle m_packet_forward; + /// Packet return methods supported. + ServiceGroup::PacketStyle m_packet_return; + /// Cache assignment methods supported. + ServiceGroup::CacheAssignmentStyle m_cache_assign; + + /// Known caches. + CacheBag m_caches; + /// Known routers. + RouterBag m_routers; + + /// Set if there an assignment should be computed and sent. + /// This is before checking for being a designated cache + /// (that check is part of the assignment generation). + bool m_assignment_pending; + + /// Seed routers. + std::vector m_seed_routers; + + GroupData(); ///< Default constructor. + + /// Find a router by IP @a addr. + /// @return A pointer to the router, or @c NULL if not found. + RouterBag::iterator findRouter( + uint32_t addr ///< IP address of cache. + ); + + /// Set an intial router for a service group. + self& seedRouter( + uint32_t addr ///< IP address for router. + ); + /// Remove a seed router. + /// @return The last time a packet was sent to the router. + time_t removeSeedRouter( + uint32_t addr ///< Identifying router address. + ); + + /// Find a cache by IP @a addr. + /// @return An iterator to the cache, or @c NULL if not found. + CacheBag::iterator findCache( + uint32_t addr ///< IP address of cache. + ); + /// Adjust packet stamp vectors to track routers. + void resizeCacheSources(); + + /// Time until next event. + /// @return The number of seconds until the next event of interest. + time_t waitTime( + time_t now ///< Current time. + ) const; + + /** Cull routers. + Routers that have not replied recently are moved from the + active router list to the seed router list. + + @return @c true if any routers were culled, @c false otherwise. + */ + bool cullRouters( + time_t now ///< Current time. + ); + + /// Update state to reflect a view change. + self& viewChanged(time_t now); + + /// Use @a key instead of global default. + self& setKey( + char const* key ///< Shared key. + ); + /// Use security @a style instead of global default. + self& setSecurity( + SecurityOption style ///< Security style to use. + ); + }; + } +} + +/** Implementation class for Cache Endpoint. + */ +class CacheImpl : public Impl { +public: + typedef CacheImpl self; ///< Self reference type. + typedef Impl super; ///< Parent type. + + // Import details + typedef detail::cache::SeedRouter SeedRouter; + typedef detail::cache::CacheData CacheData; + typedef detail::cache::RouterData RouterData; + typedef detail::cache::GroupData GroupData; + typedef detail::cache::CacheBag CacheBag; + typedef detail::cache::RouterBag RouterBag; + + /** Define a service group. + If no service is defined for the ID in @a svc, it is created. + If @a result is not @c NULL then it is set to + - @c ServiceGroup::DEFINED if the service was created. + - @c ServiceGroup::EXISTS if the service matches the existing service. + - @c ServiceGroup::CONFLICT if the service doesn't match the existing service. + + @return The data for the service group. + */ + virtual GroupData& defineServiceGroup( + ServiceGroup const& svc, ///< [in] Service to define. + ServiceGroup::Result* result = 0 ///< [out] Result for service creation. + ); + + /** Set an intial router for a service group. + This is needed to bootstrap the protocol. + If the router is already seeded, this call is silently ignored. + */ + self& seedRouter( + uint8_t id, ///< Service group ID. + uint32_t addr ///< IP address for router. + ); + + /// Define services from a configuration file. + ts::Errata loadServicesFromFile( + char const* path ///< Path to file. + ); + + /// Override. + int open(uint32_t addr); + + /// Time until next scheduled event. + time_t waitTime() const; + + /// Check for configuration. + bool isConfigured() const; + + /// Perform all scheduled housekeeping functions. + /// @return 0 for success, -errno on error. + virtual int housekeeping(); + + /** Check cache assignment reported by a router against internal assign. + @return @c true if they are the same, @c false otherwise. + */ + virtual ts::Errata checkRouterAssignment( + GroupData const& group, ///< Group with assignment. + RouterViewComp const& comp ///< Assignment reported by router. + ) const; +protected: + /// Generate contents in HERE_I_AM @a msg for seed router. + void generateHereIAm( + HereIAmMsg& msg, ///< Message with allocated buffer. + GroupData& group ///< Group with data for message. + ); + /// Generate contents in HERE_I_AM @a msg for active @a router. + void generateHereIAm( + HereIAmMsg& msg, ///< Message with allocated buffer. + GroupData& group, ///< Group with data for message. + RouterData& router ///< Target router. + ); + /// Generate contents in REDIRECT_ASSIGN @a msg for a service @a group. + void generateRedirectAssign( + RedirectAssignMsg& msg, ///< Message with allocated buffer. + GroupData& group ///< Group with data for message. + ); + /// Process HERE_I_AM message. + virtual ts::Errata handleISeeYou( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Buffer with message data. + ); + /// Process REMOVAL_QUERY message. + virtual ts::Errata handleRemovalQuery( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Message data. + ); + + /// Map Service Group ID to Service Group Data. + typedef std::map GroupMap; + /// Active service groups. + GroupMap m_groups; +}; +// ------------------------------------------------------ +namespace detail { + namespace router { + /** Router's view of a cache. + @a m_count tracks the number of packets received from this particular + cache. The RFC is unclear but it looks like this should be tracked + independently for each target address (which can be different than + caches if multicasting). A response is pending if @a m_count is + different than @ m_xmit.m_gen which is the received count last time + this router sent this cache a response. + */ + struct CacheData { + /// Get the identifying IP address for this cache. + uint32_t idAddr() const; + + /// Received count for this cache. + uint32_t m_recv_count; + /// Change number of last received message. + uint32_t m_generation; + /// Need to send a response to this cache. + bool m_pending; + /// Address used by cache to send to this router. + uint32_t m_to_addr; + /// Stamp for last pack transmitted to this cache. + PacketStamp m_xmit; + //// Stamp for last packet received from this cache. + PacketStamp m_recv; + + CacheIdBox m_id; ///< Transmitted cache descriptor. + uint32_t m_target_addr; ///< Target address of last packet. + }; + + /// Router's view of other routers. + struct RouterData { + typedef RouterData self; ///< Self reference type. + + /// Identifying IP address of router. + uint32_t m_addr; + /** Stamp for last mention of this router from a cache. + Indexed in parallel with the Caches. + The sequence number @a m_sn is the cache's change #. + */ + std::vector m_src; + /// Resize the packet stamp vector. + self& resize(size_t); + }; + + /// Storage type for known caches. + typedef std::vector CacheBag; + /// Storage type for known routers. + typedef std::vector RouterBag; + + /** A router's view of a service group. + + This stores the internal accounting information, it is not the + serialized form. + */ + struct GroupData : public detail::endpoint::GroupData { + typedef GroupData self; ///< Self reference type. + typedef detail::endpoint::GroupData super; ///< Parent type. + + GroupData(); ///< Default constructor. + + /// Known caches. + CacheBag m_caches; + /// Known (other) routers. + RouterBag m_routers; + + /// Find a cache by IP @a addr. + /// @return An iterator to the cache, or @c NULL if not found. + CacheBag::iterator findCache( + uint32_t addr ///< IP address of cache. + ); + /// Adjust packet stamp vectors to track caches. + void resizeRouterSources(); + }; + } +} + +/** Implementation class for Router Endpoint. + */ +class RouterImpl : public Impl { +public: + typedef RouterImpl self; ///< Self reference type. + typedef Impl super; ///< Parent type. + // Import details + typedef detail::router::CacheData CacheData; + typedef detail::router::RouterData RouterData; + typedef detail::router::GroupData GroupData; + typedef detail::router::CacheBag CacheBag; + typedef detail::router::RouterBag RouterBag; + + /// Process HERE_I_AM message. + virtual ts::Errata handleHereIAm( + IpHeader const& header, ///< IP packet data. + ts::Buffer const& data ///< Buffer with message data. + ); + /// Perform all scheduled housekeeping functions. + int housekeeping(); + /// Send pending I_SEE_YOU messages. + int xmitISeeYou(); + /// Check for configuration. + bool isConfigured() const; +protected: + + /** Find or create a service group record. + If no service is defined for the ID, it is created. + If @a result is not @c NULL then it is set to + - @c ServiceGroup::DEFINED if the service was created. + - @c ServiceGroup::EXISTS if the service matches the existing service. + - @c ServiceGroup::CONFLICT if the service doesn't match the existing service. + + @return The data for the service group. + */ + GroupData& defineServiceGroup( + ServiceGroup const& svc, + ServiceGroup::Result* result + ); + /// Fill out message data. + void generateISeeYou( + ISeeYouMsg& msg, ///< Message structure to fill. + GroupData& group, ///< Group data for message. + CacheData& cache ///< Target cache. + ); + + /// Map Service Group ID to Service Group Data. + typedef std::map GroupMap; + /// Active service groups. + GroupMap m_groups; +}; +// ------------------------------------------------------ +inline RouterId::RouterId() : m_addr(0), m_recv_id(0) { } +inline RouterId::RouterId(uint32_t addr, uint32_t recv_id) + : m_addr(addr) + , m_recv_id(recv_id) { +} + +inline RouterIdElt::RouterIdElt(uint32_t addr, uint32_t recv_id) + : super(addr, htonl(recv_id)) { +} +inline uint32_t RouterIdElt::getAddr() const { return m_addr; } +inline RouterIdElt& +RouterIdElt::setAddr(uint32_t addr) { + m_addr = addr; + return *this; +} +inline uint32_t RouterIdElt::getRecvId() const { return ntohl(m_recv_id); } +inline RouterIdElt& +RouterIdElt::setRecvId(uint32_t recv_id) { + m_recv_id = htonl(recv_id); + return *this; +} +inline RouterIdElt& +RouterIdElt::operator = (super const& that) { + return this->setAddr(that.m_addr).setRecvId(that.m_recv_id); +} + +inline MaskElt::MaskElt() { } + +inline MaskElt::MaskElt( + uint32_t srcAddr, + uint32_t dstAddr, + uint16_t srcPort, + uint16_t dstPort +) : m_src_addr(srcAddr) + , m_dst_addr(dstAddr) + , m_src_port(srcPort) + , m_dst_port(dstPort) { +} + +inline uint32_t MaskElt::getSrcAddr() const { return ntohl(m_src_addr); } +inline MaskElt& MaskElt::setSrcAddr(uint32_t mask) { m_src_addr = htonl(mask); return *this; } +inline uint32_t MaskElt::getDstAddr() const { return ntohl(m_dst_addr); } +inline MaskElt& MaskElt::setDstAddr(uint32_t mask) { m_dst_addr = htonl(mask); return *this; } +inline uint16_t MaskElt::getSrcPort() const { return ntohs(m_src_port); } +inline MaskElt& MaskElt::setSrcPort(uint16_t mask) { m_src_port = htons(mask); return *this; } +inline uint16_t MaskElt::getDstPort() const { return ntohs(m_dst_port);} +inline MaskElt& MaskElt::setDstPort(uint16_t mask) { m_dst_port = htons(mask); return *this; } + +inline ValueElt::ValueElt() { } + +inline ValueElt::ValueElt( + uint32_t cacheAddr, + uint32_t srcAddr, + uint32_t dstAddr, + uint16_t srcPort, + uint16_t dstPort +) : m_src_addr(srcAddr) + , m_dst_addr(dstAddr) + , m_src_port(srcPort) + , m_dst_port(dstPort) + , m_cache_addr(cacheAddr) { +} + +inline MaskValueSetElt::MaskValueSetElt() { } +inline MaskValueSetElt::MaskValueSetElt(uint32_t count) : m_count(count) { } +inline MaskElt& MaskValueSetElt::maskElt() { return m_mask; } +inline uint32_t MaskValueSetElt::getCount() const { return ntohl(m_count); } + +inline uint32_t +MaskValueSetElt::getSrcAddrMask() const { + return m_mask.getSrcAddr(); +} +inline MaskValueSetElt& +MaskValueSetElt::setSrcAddrMask(uint32_t mask) { + m_mask.setSrcAddr(mask); + return *this; +} +inline uint32_t +MaskValueSetElt::getDstAddrMask() const { + return m_mask.getDstAddr(); +} +inline MaskValueSetElt& +MaskValueSetElt::setDstAddrMask(uint32_t mask) { + m_mask.setDstAddr(mask); + return *this; +} +inline uint16_t +MaskValueSetElt::getSrcPortMask() const { + return m_mask.getSrcPort(); +} +inline MaskValueSetElt& +MaskValueSetElt::setSrcPortMask(uint16_t mask) { + m_mask.setSrcPort(mask); + return *this; +} +inline uint16_t +MaskValueSetElt::getDstPortMask() const { + return m_mask.getDstPort(); +} +inline MaskValueSetElt& +MaskValueSetElt::setDstPortMask(uint16_t mask) { + m_mask.setDstPort(mask); + return *this; +} +inline ValueElt* +MaskValueSetElt::values() { + return reinterpret_cast(this+1); +} +inline ValueElt const* +MaskValueSetElt::values() const { + return const_cast(this)->values(); +} +inline size_t +MaskValueSetElt::calcSize(uint32_t n) { + return sizeof(self) + n * sizeof(ValueElt); +} +inline size_t +MaskValueSetElt::getSize() const { + return self::calcSize(ntohl(m_count)); +} + +inline size_t + MaskAssignElt::getSize() const { return sizeof(self) + this->getVarSize(); } + +inline uint32_t CacheIdElt::getAddr() const { return m_addr; } +inline CacheIdElt& +CacheIdElt::setAddr(uint32_t addr) { + m_addr = addr; + return *this; +} +inline uint16_t CacheIdElt::getHashRev() const { return ntohs(m_hash_rev); } +inline CacheIdElt& +CacheIdElt::setHashRev(uint16_t addr) { + m_hash_rev = htons(addr); + return *this; +} +inline CacheIdElt& +CacheIdElt::initHashRev() { + this->setHashRev(HASH_REVISION); + return *this; +} +inline bool CacheIdElt::getUnassigned() const { return 1 == m_unassigned; } +inline CacheIdElt& +CacheIdElt::setUnassigned(bool state) { + m_unassigned = state ? 1 : 0; + return *this; +} +inline CacheIdElt& +CacheIdElt::clearReserved() { + m_reserved_0 = 0; + m_reserved_1 = 0; + m_reserved_2 = 0; + return *this; +} +inline bool CacheIdElt::isMask() const { return 1 == m_is_mask; } +inline CacheIdElt& +CacheIdElt::setMask(bool state) { + m_is_mask = state ? 1 : 0; + return *this; +} + +# if 0 +inline uint16_t CacheIdElt::getWeight() const { return ntohs(m_weight); } +inline CacheIdElt& +CacheIdElt::setWeight(uint16_t w) { + m_weight = htons(w); + return *this; +} +inline uint16_t CacheIdElt::getStatus() const { return ntohs(m_status); } +inline CacheIdElt& +CacheIdElt::setStatus(uint16_t s) { + m_status = htons(s); + return *this; +} +# endif + +inline CacheIdElt::Tail* +CacheHashIdElt::getTailPtr() { + return &m_tail; +} + +# if 0 +inline bool +CacheHashIdElt::getBucket(int idx) const { + return 0 != (m_buckets[idx>>3] & (1<<(idx & 7))); +} +# endif + +inline uint32_t +CacheMaskIdElt::getCount() const { + return m_assign.getCount(); +} + +inline size_t +CacheMaskIdElt::getSize() const { + return sizeof(self) + sizeof(Tail) + m_assign.getVarSize(); +} + +inline CacheIdElt::Tail* +CacheMaskIdElt::getTailPtr() { + return reinterpret_cast( + reinterpret_cast(this) + sizeof(self) + m_assign.getVarSize() + ); +} + +inline uint32_t +CacheIdBox::getAddr() const { + return m_base->getAddr(); +} + +inline CacheIdBox& +CacheIdBox::setAddr(uint32_t addr) { + m_base->setAddr(addr); + return *this; +} + +inline CacheIdBox& +CacheIdBox::setUnassigned(bool state) { + m_base->setUnassigned(state); + return *this; +} + +inline AssignmentKeyElt::AssignmentKeyElt( + uint32_t addr, + uint32_t n +) + : m_addr(addr) + , m_change_number(htonl(n)) { +} +inline uint32_t AssignmentKeyElt::getAddr() const { return m_addr; } +inline AssignmentKeyElt& +AssignmentKeyElt::setAddr(uint32_t addr) { + m_addr = addr; + return *this; +} +inline uint32_t +AssignmentKeyElt::getChangeNumber() const { + return ntohl(m_change_number); +} +inline AssignmentKeyElt& +AssignmentKeyElt::setChangeNumber(uint32_t n) { + m_change_number = htonl(n); + return *this; +} + +inline RouterAssignElt::RouterAssignElt( + uint32_t addr, + uint32_t recv_id, + uint32_t change_number +) + : super(addr, recv_id) + , m_change_number(htonl(change_number)) { +} +inline uint32_t +RouterAssignElt::getChangeNumber() const { + return ntohl(m_change_number); +} +inline RouterAssignElt& +RouterAssignElt::setChangeNumber(uint32_t n) { + m_change_number = htonl(n); + return *this; +} + +inline SecurityComp::SecurityComp() : m_local_key(false) { } +inline void SecurityComp::setDefaultOption(Option opt) { + m_default_opt = opt; +} +inline size_t +SecurityComp::calcSize(Option opt) { + return SECURITY_NONE == opt ? sizeof(RawNone) : sizeof(RawMD5); +} + +inline ServiceComp::ServiceComp () : m_port_count(0) { } +inline ServiceComp::raw_t* +ServiceComp::access() { + return reinterpret_cast(m_base); +} +inline ServiceComp::raw_t const* +ServiceComp::access() const { + return reinterpret_cast(m_base); +} +inline ServiceGroup::Type +ServiceComp::getSvcType() const { + return this->access()->getSvcType(); +} +inline ServiceComp& +ServiceComp::setSvcType(ServiceGroup::Type t) { + this->access()->setSvcType(t); + return *this; +} +inline uint8_t +ServiceComp::getSvcId() const { + return this->access()->getSvcId(); +} +inline ServiceComp& +ServiceComp::setSvcId(uint8_t id) { + this->access()->setSvcId(id); + return *this; +} +inline uint8_t +ServiceComp::getPriority() const { + return this->access()->getPriority(); +} +inline ServiceComp& +ServiceComp::setPriority(uint8_t pri) { + this->access()->setPriority(pri); + return *this; +} +inline uint8_t +ServiceComp::getProtocol() const { + return this->access()->getProtocol(); +} +inline ServiceComp& +ServiceComp::setProtocol(uint8_t proto) { + this->access()->setProtocol(proto); + return *this; +} +inline uint32_t +ServiceComp::getFlags() const { + return this->access()->getFlags(); +} +inline ServiceComp& +ServiceComp::setFlags(uint32_t flags) { + this->access()->setFlags(flags); + return *this; +} +inline ServiceComp& +ServiceComp::enableFlags(uint32_t flags) { + this->access()->enableFlags(flags); + return *this; +} +inline ServiceComp& +ServiceComp::disableFlags(uint32_t flags) { + this->access()->disableFlags(flags); + return *this; +} +inline uint16_t +ServiceComp::getPort (int idx) const { + return this->access()->getPort(idx); +} +inline size_t ServiceComp::calcSize() { return sizeof(raw_t); } +inline +ServiceComp::operator ServiceGroup const& () const { + return *static_cast(this->access()); +} + +inline size_t +RouterIdComp::calcSize(int n) { + return sizeof(raw_t) + n * sizeof(uint32_t); +} + +inline uint32_t +RouterViewComp::getKeyAddr() const { + return this->keyElt().getAddr(); +} +inline RouterViewComp& +RouterViewComp::setKeyAddr(uint32_t addr) { + this->keyElt().setAddr(addr); + return *this; +} +inline uint32_t +RouterViewComp::getKeyChangeNumber() const { + return this->keyElt().getChangeNumber(); +} +inline RouterViewComp& +RouterViewComp::setKeyChangeNumber(uint32_t change_number) { + this->keyElt().setChangeNumber(change_number); + return *this; +} +inline CacheIdBox const& +RouterViewComp::cacheId(int idx) const { + return const_cast(this)->cacheId(idx); +} + +inline CacheIdBox& CacheIdComp::cacheId() { return m_box; } +inline CacheIdBox const& CacheIdComp::cacheId() const { return m_box; } +inline uint32_t +CacheIdComp::getAddr() const { + return this->cacheId().getAddr(); +} +inline CacheIdComp& +CacheIdComp::setAddr(uint32_t addr) { + this->cacheId().setAddr(addr); + return *this; +} +inline uint16_t +CacheIdComp::getHashRev() const { + return this->cacheId().getHashRev(); +} +inline CacheIdComp& +CacheIdComp::setHashRev(uint16_t rev) { + this->cacheId().setHashRev(rev); + return *this; +} +inline bool +CacheIdComp::getUnassigned() const { + return this->cacheId().getUnassigned(); +} +inline CacheIdComp& +CacheIdComp::setUnassigned(bool state) { + this->cacheId().setUnassigned(state); + return *this; +} +# if 0 +inline uint16_t +CacheIdComp::getWeight() const { + return this->idElt().getWeight(); +} +inline CacheIdComp& +CacheIdComp::setWeight(uint16_t w) { + this->idElt().setWeight(w); + return *this; +} +inline uint16_t +CacheIdComp::getStatus() const { + return this->idElt().getStatus(); +} +inline CacheIdComp& +CacheIdComp::setStatus(uint16_t s) { + this->idElt().setStatus(s); + return *this; +} +inline bool +CacheIdComp::getBucket(int idx) const { + return this->idElt().getBucket(idx); +} +inline CacheIdComp& +CacheIdComp::setBucket(int idx, bool state) { + this->idElt().setBucket(idx, state); + return *this; +} +inline CacheIdComp& +CacheIdComp::setBuckets(bool state) { + this->idElt().setBuckets(state); + return *this; +} +inline size_t CacheIdComp::calcSize() { return sizeof(raw_t); } +# endif + +inline bool detail::Assignment::isActive() const { return m_active; } +inline detail::Assignment& +detail::Assignment::setActive(bool state) { + m_active = state; + return *this; +} +inline detail::Assignment& +detail::Assignment::updateRouterId(uint32_t addr, uint32_t rcvid, uint32_t cno) { + if (m_router_list) m_router_list->updateRouterId(addr, rcvid, cno); + return *this; +} +inline AssignmentKeyElt::AssignmentKeyElt() { } +inline AssignmentKeyElt const& +detail::Assignment::getKey() const { + return m_key; +} +inline RouterAssignListElt const& +detail::Assignment::getRouterList() const { + assert(m_router_list); + return *m_router_list; +} +inline HashAssignElt const& +detail::Assignment::getHash() const { + assert(m_hash_assign); + return *m_hash_assign; +} +inline MaskAssignElt const& +detail::Assignment::getMask() const { + assert(m_mask_assign); + return *m_mask_assign; +} + +inline MsgBuffer::MsgBuffer() : super(0,0), _count(0) { } +inline MsgBuffer::MsgBuffer(super const& that) : super(that), _count(0) { } +inline MsgBuffer::MsgBuffer(void* p, size_t n) + : super(static_cast(p),n) + , _count(0) { +} + +inline size_t MsgBuffer::getSize() const { return _size; } +inline size_t MsgBuffer::getCount() const { return _count; } +inline char* MsgBuffer::getBase() { return _ptr; } +inline char const* MsgBuffer::getBase() const { return _ptr; } +inline char* MsgBuffer::getTail() { return _ptr + _count; } +inline size_t MsgBuffer::getSpace() const { return _size - _count; } +inline MsgBuffer& MsgBuffer::reset() { _count = 0; return *this; } + +inline MsgBuffer& MsgBuffer::set(void *ptr, size_t n) { + _ptr = static_cast(ptr); + _size = n; + _count = 0; + return *this; +} + +inline MsgBuffer::operator MsgBuffer::super const& () const { + return *this; +} + +inline MsgBuffer& +MsgBuffer::use(size_t n) { + _count += std::min(n, this->getSpace()); + return *this; +} + +inline MsgBuffer& MsgBuffer::zero() { + memset(_ptr, 0, _size); + _count = 0; + return *this; +} + +inline PacketStamp::PacketStamp() + : m_time(0) + , m_sn(0) { +} + +inline PacketStamp& PacketStamp::set(time_t time, uint32_t sn) { + m_time = time; + m_sn = sn; + return *this; +} + +inline ServiceGroup::ServiceGroup() { +} + +inline RouterIdElt::RouterIdElt() { } +inline RouterAssignElt::RouterAssignElt() : m_change_number(0) { } + +inline RouterAssignListElt::RouterAssignListElt() {} +inline RouterAssignListElt::RouterAssignListElt(int n) : m_count(htonl(n)) {} +inline RouterAssignElt& +RouterAssignListElt::elt(int n) { + return access_array(this + 1)[n]; +} +inline RouterAssignElt const& +RouterAssignListElt::elt(int n) const { + return const_cast(this)->elt(n); +} +inline size_t +RouterAssignListElt::calcVarSize(int n) { + return n * sizeof(RouterAssignElt); +} +inline size_t +RouterAssignListElt::calcSize(int n) { + return sizeof(self) + self::calcVarSize(n); +} +inline size_t +RouterAssignListElt::getSize() const { + return this->calcSize(this->getCount()); +} +inline size_t +RouterAssignListElt::getVarSize() const { + return this->getSize() - sizeof(self); +} +inline uint32_t RouterAssignListElt::getCount() const { return ntohl(m_count); } + +inline HashAssignElt::HashAssignElt () { } +inline HashAssignElt::HashAssignElt (int n) : m_count(htonl(n)) { } +inline uint32_t HashAssignElt::getCount() const { return ntohl(m_count); } +inline size_t +HashAssignElt::calcSize(int n) { + return sizeof(self) + n * sizeof(uint32_t) + sizeof(Bucket) * N_BUCKETS; +} +inline size_t +HashAssignElt::getSize() const { + return self::calcSize(this->getCount()); +} +inline uint32_t +HashAssignElt::getAddr(int idx) const { + return (&m_count)[idx+1]; +} +inline HashAssignElt& +HashAssignElt::setAddr(int idx, uint32_t addr) { + (&m_count)[idx+1] = addr; + return *this; +} +inline HashAssignElt::Bucket* +HashAssignElt::getBucketBase() { + return reinterpret_cast((&m_count + 1 + this->getCount())); +} +inline HashAssignElt::Bucket& +HashAssignElt::operator [] (size_t idx) { + return this->getBucketBase()[idx]; +} +inline HashAssignElt::Bucket const& +HashAssignElt::operator [] (size_t idx) const { + return (*(const_cast(this)))[idx]; +} + +inline MaskAssignElt::MaskAssignElt() {} +inline uint32_t MaskAssignElt::getCount() const { return ntohl(m_count); } +inline MaskValueSetElt* MaskAssignElt::appender::operator -> () { + return m_set; +} +inline MaskValueSetElt* MaskAssignElt::appender::initSet( + uint32_t srcAddr, + uint32_t dstAddr, + uint16_t srcPort, + uint16_t dstPort +) { + (*(new (m_set) MaskValueSetElt(0))) + .setSrcAddrMask(srcAddr) + .setDstAddrMask(dstAddr) + .setSrcPortMask(srcPort) + .setDstPortMask(dstPort) + ; + return m_set; +} +inline MaskValueSetElt* MaskAssignElt::appender::mask( + uint32_t srcAddr, + uint32_t dstAddr, + uint16_t srcPort, + uint16_t dstPort +) { + m_set = reinterpret_cast( + reinterpret_cast(m_set) + m_set->getSize() + ); + m_elt->m_count = htonl(1 + m_elt->getCount()); // bump set count. + this->initSet(srcAddr, dstAddr, srcPort, dstPort); + return m_set; +} +inline MaskAssignElt::appender +MaskAssignElt::init( + uint32_t srcAddr, + uint32_t dstAddr, + uint16_t srcPort, + uint16_t dstPort +) { + appender zret; + m_count = htonl(1); + zret.m_set = reinterpret_cast(this+1); + zret.m_elt = this; + zret.initSet(srcAddr, dstAddr, srcPort, dstPort); + return zret; +} + +inline ComponentBase::ComponentBase() : m_base(0) { } +inline bool ComponentBase::isEmpty() const { return 0 == m_base; } + +inline message_type_t MsgHeaderComp::toMsgType(int t) { + return HERE_I_AM != t + && I_SEE_YOU != t + && REDIRECT_ASSIGN != t + && REMOVAL_QUERY != t + ? INVALID_MSG_TYPE + : static_cast(t) + ; +} + +template < typename T > CompType +CompWithHeader::getType() const { + return static_cast( + ntohs(reinterpret_cast(m_base)->m_type) + ); +} + +template < typename T > T& +CompWithHeader::setType(CompType t) { + reinterpret_cast(m_base)->m_type = htons(t); + return static_cast(*this); +} + +template < typename T > uint16_t +CompWithHeader::getLength() const { + return ntohs( + reinterpret_cast(m_base)->m_length + ); +} + +template < typename T > T& +CompWithHeader::setLength(uint16_t length) { + reinterpret_cast(m_base)->m_length = htons(length); + return static_cast(*this); +} + +template < typename T > int +CompWithHeader::checkHeader(MsgBuffer const& buffer, CompType ect) { + CompType act = this->getType(); + if (act != ect) + return (act < COMP_TYPE_MIN || COMP_TYPE_MAX < act) + ? PARSE_COMP_TYPE_INVALID + : PARSE_COMP_OTHER_TYPE + ; + if (this->getLength() + sizeof(raw_t) > buffer.getSpace()) + return PARSE_COMP_TOO_BIG; + return PARSE_SUCCESS; +} + +inline AssignInfoComp::Bucket& AssignInfoComp::bucket(int idx) { return m_buckets[idx]; } +inline AssignInfoComp::Bucket const& AssignInfoComp::bucket(int idx) const{ return m_buckets[idx]; } +inline bool AssignInfoComp::compare(Bucket const buckets[N_BUCKETS]) const { + return 0 == memcmp(buckets, m_buckets, sizeof(buckets)); +} + +inline RouterViewComp::RouterViewComp() + : m_cache_count(0) { + memset(m_cache_ids, 0, sizeof(m_cache_ids)); +} + +inline CapComp::CapComp() : m_count(0), m_cached(false) { } +inline CapComp& CapComp::invalidate() { m_cached = false; return *this; } +inline uint32_t CapComp::getEltCount() const { return this->m_count; } +inline size_t CapComp::calcSize(int n) { return sizeof(super::raw_t) + n * sizeof(CapabilityElt); } +inline ServiceGroup::PacketStyle +CapComp::getPacketForwardStyle() const { + if (!m_cached) this->cache(); + return m_packet_forward; +} +inline ServiceGroup::PacketStyle +CapComp::getPacketReturnStyle() const { + if (!m_cached) this->cache(); + return m_packet_return; +} +inline ServiceGroup::CacheAssignmentStyle +CapComp::getCacheAssignmentStyle() const { + if (!m_cached) this->cache(); + return m_cache_assign; +} + +inline AssignMapComp::AssignMapComp() { } + +/* Implementation note: Due to a bug in gcc, we have to be + careful with these fields. If we use the field access templates + directly, we get bad results because the pointer to member matching + is done incorrectly (it uses a super type, not @c raw_t). We work + around this by putting the pointer to member in a static variable. +*/ +inline uint16_t +AltAssignComp::getAssignType() const { + static uint16_t raw_t::*mptr = &raw_t::m_assign_type; + return get_field(mptr, m_base); +} +inline AltAssignComp& +AltAssignComp::setAssignType(uint16_t t) { + static uint16_t raw_t::*mptr = &raw_t::m_assign_type; + set_field(mptr, m_base, t); + return *this; +} +inline uint16_t +AltAssignComp::getAssignLength() const { + static uint16_t raw_t::*mptr = &raw_t::m_assign_length; + return get_field(mptr, m_base); +} +inline AltAssignComp& +AltAssignComp::setAssignLength(uint16_t length) { + static uint16_t raw_t::*mptr = &raw_t::m_assign_length; + set_field(mptr, m_base, length); + return *this; +} + +inline uint32_t QueryComp::getRouterAddr() const { + return access_field(&raw_t::m_router_addr, m_base); +} +inline QueryComp& QueryComp::setRouterAddr(uint32_t addr) { + access_field(&raw_t::m_router_addr, m_base) = addr; + return *this; +} +inline uint32_t QueryComp::getToAddr() const { + return access_field(&raw_t::m_to_addr, m_base); +} +inline QueryComp& QueryComp::setToAddr(uint32_t addr) { + access_field(&raw_t::m_to_addr, m_base) = addr; + return *this; +} +inline uint32_t QueryComp::getCacheAddr() const { + return access_field(&raw_t::m_cache_addr, m_base); +} +inline QueryComp& QueryComp::setCacheAddr(uint32_t addr) { + access_field(&raw_t::m_cache_addr, m_base) = addr; + return *this; +} +inline uint32_t QueryComp::getRecvId() const { + return get_field(&raw_t::m_recv_id, m_base); +} +inline QueryComp& QueryComp::setRecvId(uint32_t data) { + set_field(&raw_t::m_recv_id, m_base, data); + return *this; +} +inline size_t QueryComp::calcSize() { return sizeof(raw_t); } + +inline detail::cache::SeedRouter::SeedRouter() { } + +inline detail::cache::SeedRouter::SeedRouter(uint32_t addr) + : m_addr(addr) + , m_count(0) + , m_xmit(0) { +} + +inline BaseMsg::BaseMsg() : m_buffer(0,0) { } +inline MsgBuffer const& BaseMsg::buffer() const { return m_buffer; } +inline size_t BaseMsg::getSpace() const { return m_buffer.getSpace(); } +inline size_t BaseMsg::getCount() const { return m_buffer.getCount(); } + +inline RouterImpl::RouterData& +RouterImpl::RouterData::resize(size_t n) { + m_src.resize(n); + return *this; +} +// ------------------------------------------------------ + +} // namespace wccp + +# endif // TS_WCCP_LOCAL_HEADER diff --git a/lib/wccp/WccpMeta.h b/lib/wccp/WccpMeta.h new file mode 100644 index 00000000..be85c93f --- /dev/null +++ b/lib/wccp/WccpMeta.h @@ -0,0 +1,203 @@ +# if !defined(TS_WCCP_META_HEADER) +# define TS_WCCP_META_HEADER + +/** @file + Meta programming support for WCCP. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include + +// Various meta programming efforts. Experimental at present. + +namespace ts { + +// Some support templates so we can fail to compile if the +// compile time check fails. + +// This creates the actual error, depending on whether X has a valid +// nest type Result. +template < typename X > struct TEST_RESULT { typedef typename X::Result type; }; + +// Bool checking - a base template then specializations to succeed or +// fail. +template < bool VALUE > struct TEST_BOOL { }; +// Successful test defines Result. +template <> struct TEST_BOOL { typedef int Result; }; +// Failing test does not define Result. +template <> struct TEST_BOOL { }; + +// Fail to compile if VALUE is not true. +template < bool VALUE > struct TEST_IF_TRUE + : public TEST_RESULT< TEST_BOOL< VALUE > > { +}; + +// Helper for assigning a value to all instances in a container. +template < typename T , typename R, typename A1 > +struct TsAssignMember : public std::binary_function { + R T::*_m; + A1 _arg1; + TsAssignMember(R T::*m, A1 const& arg1) : _m(m), _arg1(arg1) { } + R operator () (T& t) const { return t.*_m = _arg1; } +}; + +// Helper function to compute types for TsAssignMember. +template < typename T, typename R, typename A1 > struct TsAssignMember assign_member(R T::*m, A1 const& arg1) { return TsAssignMember(m,arg1); } + +// Overload for_each to operate on a container. +template < typename C, typename F > void for_each(C& c, F const& f) { std::for_each(c.begin(), c.end(), f); } + +/** Calc minimal value over a direct type container. + This handles an accessor that takes a argument. +*/ +template < typename C, typename V, typename ARG1 > V +minima(C const& c, V (C::value_type::*ex)(ARG1) const, ARG1 const& arg1) { + V v = std::numeric_limits::max(); + for ( typename C::const_iterator spot = c.begin(), limit = c.end(); + spot != limit; + ++spot + ) { + v = std::min(v, ((*spot).*ex)(arg1) ); + } + return v; +} + +/** Calc minimal value over a paired type container. + This handles an accessor that takes a argument. +*/ +template < typename C, typename V, typename ARG1 > V +minima(C const& c, V (C::value_type::second_type::*ex)(ARG1) const, ARG1 const& arg1) { + V v = std::numeric_limits::max(); + for ( typename C::const_iterator spot = c.begin(), limit = c.end(); + spot != limit; + ++spot + ) { + v = std::min(v, ((spot->second).*ex)(arg1) ); + } + return v; +} + +/** Apply a unary method to every object in a direct container. +*/ +template < typename C, typename V, typename ARG1 > void +for_each(C& c, V (C::value_type::*ex)(ARG1), ARG1 const& arg1) { + for ( typename C::iterator spot = c.begin(), limit = c.end(); + spot != limit; + ++spot + ) ((*spot).*ex)(arg1); +} + +/** Apply a unary method to every object in a paired container. +*/ +template < typename C, typename V, typename ARG1 > void +for_each(C& c, V (C::value_type::second_type::*ex)(ARG1) const, ARG1 const& arg1) { + for ( typename C::iterator spot = c.begin(), limit = c.end(); + spot != limit; + ++spot + ) ((spot->second).*ex)(arg1); +} + +template < + typename Elt, ///< Element type. + typename Value ///< Member value type. +> struct MemberPredicate { + Value const& m_value; ///< Value to test against. + Value Elt::*m_mptr; ///< Pointer to member to test. + MemberPredicate(Value Elt::*mptr, Value const& v) + : m_value(v) + , m_mptr(mptr) { + } + bool operator () (Elt const& elt) const { + return elt.*m_mptr == m_value; + } +}; + +template < typename T, typename V > MemberPredicate +predicate(V T::*m, V const& v) { + return MemberPredicate(m, v); +} + +template < + typename Elt, ///< Element type. + typename Value ///< Member value type. +> struct MethodPredicate { + typedef Value (Elt::*MethodPtr)() const; + Value const& m_value; ///< Value to test against. + MethodPtr m_mptr; ///< Pointer to method returning value. + MethodPredicate(MethodPtr mptr , Value const& v) + : m_value(v) + , m_mptr(mptr) { + } + bool operator () (Elt const& elt) const { + return (elt.*m_mptr)() == m_value; + } +}; + +template < typename T, typename V > MethodPredicate +predicate(V (T::*m)() const, V const& v) { + return MethodPredicate(m, v); +} + +# if 0 + +/// Accumulate a minimum value when called repeated on different objects. +template < + typename V, ///< Value type. + typename T, ///< Object type + typename F ///< Extractor type. +> struct MinimaFunctor : public std::unary_function { + V& m_result; ///< Result value. + F m_extractor; ///< Extraction functor. + /// Constructor. +MinimaFunctor(F const& f, V& v) : m_result(v), m_extractor(f) { } + /// Extract a value and accumulate the minimum. + void operator () (T const& obj) const { + m_result = std::min(m_result, m_extractor(obj)); + } +}; + +// Working on a more general mechanism by starting with more specific +// ones to see the pattern. + +template < + typename R, ///< Return type. + typename T, ///< Object type. + typename ARG1 ///< Bound argument type. +> struct BinderConstMethodArg1ToNullary : std::unary_function { + typedef R (T::*F)(ARG1) const; /// Method type. + F m_method; ///< The actual method. + ARG1 m_arg1; ///< Bound argument. + /// Constructor. + BinderConstMethodArg1ToNullary( + F const& f, ///< Pointer to method. + ARG1 const& arg1 ///< Argument to bind. + ) : m_method(f), m_arg1(arg1) { + } + /// Call the method. + R operator () (T const& obj) const { + return (obj.*m_method)(m_arg1); + } +}; + +# endif + +} // namespace ts + +# endif // TS_WCCP_META_HEADER diff --git a/lib/wccp/WccpMsg.cc b/lib/wccp/WccpMsg.cc new file mode 100644 index 00000000..c2624fc4 --- /dev/null +++ b/lib/wccp/WccpMsg.cc @@ -0,0 +1,1783 @@ +/** @file + WCCP Message parsing and generation. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +# include "WccpLocal.h" +# include +# include +# include + +namespace wccp { +// ------------------------------------------------------ +// ------------------------------------------------------ +ServiceGroup& +ServiceGroup::setSvcType(ServiceGroup::Type t) { + if (STANDARD == t) { + // For standard service, everything past ID must be zero. + memset(&m_priority, 0, + sizeof(this) - ( + reinterpret_cast(&m_priority) - reinterpret_cast(this) + ) + ); + } + m_svc_type = t; // store actual type. + return *this; +} + +bool +ServiceGroup::operator == (self const& that) const { + if (m_svc_type == STANDARD) { + // If type are different, fail, else if both are STANDARD + // then we need only match on the ID. + return that.m_svc_type == STANDARD && m_svc_id == that.m_svc_id; + } else if (that.m_svc_type != DYNAMIC) { + return false; + } else { + // Both services are DYNAMIC, check the properties. + // Port check is technically too strict -- should ignore + // ports beyond the terminating null port. Oh well. + return m_svc_id == that.m_svc_id + && m_protocol == that.m_protocol + && m_flags == that.m_flags + && m_priority == that.m_priority + && 0 == memcmp(m_ports, that.m_ports, sizeof(m_ports)) + ; + } +} +// ------------------------------------------------------ +// ------------------------------------------------------ +CacheHashIdElt& +CacheHashIdElt::setBucket(int idx, bool state) { + uint8_t& bucket = m_buckets[idx>>3]; + uint8_t mask = 1 << (idx & 7); + if (state) bucket |= mask; + else bucket &= !mask; + return *this; +} + +CacheHashIdElt& +CacheHashIdElt::setBuckets(bool state) { + memset(m_buckets, state ? 0xFF : 0, sizeof(m_buckets)); + return *this; +} + +CacheIdBox::CacheIdBox() + : m_base(0) + , m_tail(0) + , m_size(0) + , m_cap(0) { +} + +size_t CacheIdBox::getSize() const { return m_size; } + +CacheIdBox& +CacheIdBox::require(size_t n) { + if (m_cap < n) { + if (m_base && m_cap) free(m_base); + m_base = static_cast(malloc(n)); + m_cap = n; + } + memset(m_base, 0, m_cap); + m_size = 0; + return *this; +} + +CacheIdBox& +CacheIdBox::initDefaultHash(uint32_t addr) { + this->require(sizeof(CacheHashIdElt)); + m_size = sizeof(CacheHashIdElt); + m_base->initHashRev().setUnassigned(true).setMask(false).setAddr(addr); + m_tail = static_cast(m_base)->getTailPtr(); + m_tail->m_weight = htons(0); + m_tail->m_status = htons(0); + return *this; +} + +CacheIdBox& +CacheIdBox::initDefaultMask(uint32_t addr) { + // Base element plus set with 1 value plus tail. + this->require(sizeof(CacheMaskIdElt) + MaskValueSetElt::calcSize(1) + sizeof(CacheIdElt::Tail)); + CacheMaskIdElt* mid = static_cast(m_base); + mid->initHashRev().setUnassigned(true).setMask(true).setAddr(addr); + mid->m_assign.init(0,0,0,0)->addValue(addr, 0, 0, 0, 0); + m_size = mid->getSize(); + m_tail = mid->getTailPtr(); + m_tail->m_weight = htons(0); + m_tail->m_status = htons(0); + return *this; +} + +CacheIdBox& +CacheIdBox::fill(self const& src) { + size_t n = src.getSize(); + this->require(src.getSize()); + memcpy(m_base, src.m_base, n); + m_size = src.m_size; + // If tail is set in src, use the same offset here. + if (src.m_tail) + m_tail = reinterpret_cast( + reinterpret_cast(m_base) + ( + reinterpret_cast(src.m_tail) + - reinterpret_cast(src.m_base) + )); + else m_tail = 0; + return *this; +} + +CacheIdBox& +CacheIdBox::fill(void* base, self const& src) { + m_size = src.getSize(); + m_cap = 0; + m_base = static_cast(base); + memcpy(m_base, src.m_base, m_size); + return *this; +} + +int +CacheIdBox::parse(MsgBuffer base) { + int zret = PARSE_SUCCESS; + CacheIdElt* ptr = reinterpret_cast(base.getTail()); + size_t n = base.getSpace(); + m_cap = 0; + if (ptr->isMask()) { + CacheMaskIdElt* mptr = static_cast(ptr); + size_t size = sizeof(CacheMaskIdElt); + // Sanity check - verify enough room for empty elements. + if (n < size + || n < size + MaskValueSetElt::calcSize(0) * mptr->getCount()) { + zret = PARSE_BUFFER_TOO_SMALL; + } else { + m_size = mptr->getSize(); + if (n < m_size) { + zret = PARSE_BUFFER_TOO_SMALL; + logf(LVL_DEBUG, "I_SEE_YOU Cache Mask ID too small: %lu < %lu", n, m_size); + } else { + m_tail = mptr->getTailPtr(); + } + } + } else { + if (n < sizeof(CacheHashIdElt)) { + zret = PARSE_BUFFER_TOO_SMALL; + logf(LVL_DEBUG, "I_SEE_YOU Cache Hash ID too small: %lu < %lu", n, sizeof(CacheHashIdElt)); + } else { + m_size = sizeof(CacheHashIdElt); + m_tail = static_cast(m_base)->getTailPtr(); + } + } + if (PARSE_SUCCESS == zret) m_base = ptr; + return zret; +} +// ------------------------------------------------------ +inline CapabilityElt::Type +CapabilityElt::getCapType() const { + return static_cast(ntohs(m_cap_type)); +} + +inline CapabilityElt& +CapabilityElt::setCapType(Type cap) { + m_cap_type = htons(cap); + return *this; +} + +inline uint32_t +CapabilityElt::getCapData() const { + return ntohl(m_cap_data); +} + +inline CapabilityElt& +CapabilityElt::setCapData(uint32_t data) { + m_cap_data = htonl(data); + return *this; +} + +CapabilityElt::CapabilityElt() { +} + +CapabilityElt::CapabilityElt(Type cap, uint32_t data) { + this->setCapType(cap); + this->setCapData(data); + m_cap_length = htons(sizeof(uint32_t)); +} +// ------------------------------------------------------ +inline uint32_t +ValueElt::getf_src_addr() const { + return ntohl(m_src_addr); +} + +inline ValueElt& +ValueElt::setf_src_addr(uint32_t addr) { + m_src_addr = htonl(addr); + return *this; +} + +inline uint32_t +ValueElt::getDstAddr() const { + return ntohl(m_dst_addr); +} + +inline ValueElt& +ValueElt::setf_dst_addr(uint32_t addr) { + m_dst_addr = htonl(addr); + return *this; +} + +inline uint16_t +ValueElt::getf_src_port() const { + return ntohs(m_src_port); +} + +inline ValueElt& +ValueElt::setf_src_port(uint16_t port) { + m_src_port = htons(port); + return *this; +} + +inline uint16_t +ValueElt::getDstPort() const { + return ntohs(m_dst_port); +} + +inline ValueElt& +ValueElt::setf_dst_port(uint16_t port) { + m_dst_port = htons(port); + return *this; +} + +inline uint32_t +ValueElt::getCacheAddr() const { + return ntohl(m_cache_addr); +} + +inline ValueElt& +ValueElt::setCacheAddr(uint32_t addr) { + m_cache_addr = htonl(addr); + return *this; +} +// ------------------------------------------------------ +MaskValueSetElt& +MaskValueSetElt::addValue( + uint32_t cacheAddr, + uint32_t srcAddr, + uint32_t dstAddr, + uint16_t srcPort, + uint16_t dstPort +) { + uint32_t idx = ntohl(m_count); + new (this->values() + idx) ValueElt(cacheAddr, srcAddr, dstAddr, srcPort, dstPort); + m_count = htonl(idx + 1); + return *this; +} + +size_t +MaskAssignElt::getVarSize() const { + size_t zret = 0; + int n = this->getCount(); + + MaskValueSetElt const* set = reinterpret_cast(this+1); + while (n--) { + size_t k = set->getSize(); + zret += k; + set = reinterpret_cast( + reinterpret_cast(set) + k + ); + } + return zret; +} + +HashAssignElt& +HashAssignElt::round_robin_assign() { + uint32_t v_caches = this->getCount(); + Bucket* buckets = this->getBucketBase(); + if (1 == v_caches) memset(buckets, 0, sizeof(Bucket) * N_BUCKETS); + else { // Assign round robin. + size_t x = 0; + for ( Bucket *spot = buckets, *limit = spot + N_BUCKETS; + spot < limit; + ++spot + ) { + spot->m_idx = x; + spot->m_alt = 0; + x = ( x + 1 ) % v_caches; + } + } + return *this; +} + +RouterAssignListElt& +RouterAssignListElt::updateRouterId(uint32_t addr, uint32_t rcvid, uint32_t cno) { + uint32_t n = this->getCount(); + RouterAssignElt* elt = access_array(this+1); + for ( uint32_t i = 0 ; i < n ; ++i, ++elt ) { + if (addr == elt->getAddr()) { + elt->setChangeNumber(cno).setRecvId(rcvid); + break; + } + } + return *this; +} +// ------------------------------------------------------ +message_type_t +MsgHeaderComp::getType() { + return static_cast(get_field(&raw_t::m_type, m_base)); +} + +uint16_t +MsgHeaderComp::getVersion() { + return get_field(&raw_t::m_version, m_base); +} + +uint16_t +MsgHeaderComp::getLength() { + return get_field(&raw_t::m_length, m_base); +} + +MsgHeaderComp& +MsgHeaderComp::setType(message_type_t type) { + set_field(&raw_t::m_type, m_base, type); + return *this; +} + +MsgHeaderComp& +MsgHeaderComp::setVersion(uint16_t version) { + set_field(&raw_t::m_version, m_base, version); + return *this; +} + +MsgHeaderComp& +MsgHeaderComp::setLength(uint16_t length) { + set_field(&raw_t::m_length, m_base, length); + return *this; +} + +size_t +MsgHeaderComp::calcSize() { + return sizeof(raw_t); +} + +MsgHeaderComp& +MsgHeaderComp::fill(MsgBuffer& buffer, message_type_t t) { + size_t comp_size = this->calcSize(); + if (buffer.getSpace() < comp_size) + throw ts::Exception(BUFFER_TOO_SMALL_FOR_COMP_TEXT); + m_base = buffer.getTail(); + buffer.use(comp_size); + this->setType(t).setVersion(VERSION).setLength(0); + return *this; +} + +int +MsgHeaderComp::parse(MsgBuffer& base) { + int zret = PARSE_SUCCESS; + size_t comp_size = this->calcSize(); + if (base.getSpace() < comp_size) { + zret = PARSE_BUFFER_TOO_SMALL; + } else { + m_base = base.getTail(); + // Length field puts end of message past end of buffer. + if (this->getLength() + comp_size > base.getSpace()) { + zret = PARSE_MSG_TOO_BIG; + } else if (INVALID_MSG_TYPE == this->toMsgType(get_field(&raw_t::m_type, m_base)) + ) { + zret = PARSE_COMP_TYPE_INVALID; + } else { + base.use(comp_size); + } + } + return zret; +} +// ------------------------------------------------------ +SecurityComp::Key SecurityComp::m_default_key; +SecurityComp::Option SecurityComp::m_default_opt = SECURITY_NONE; + +SecurityComp::Option +SecurityComp::getOption() const { + return static_cast
\ngetNumEntries(); + + if (numOptions > 0) { + output->copyFrom(formOpen, strlen(formOpen)); + addSelectOptions(output, options); + output->copyFrom(hiddenInput, strlen(hiddenInput)); + output->copyFrom(action, strlen(action)); + output->copyFrom(">\n", 2); + output->copyFrom(submitButton, strlen(submitButton)); + output->copyFrom(action, strlen(action)); + output->copyFrom("\">\n", 3); + output->copyFrom(formEnd, strlen(formEnd)); + } +} + + +// bool checkValidName(const char* name) +// +// if the string is invalid, ie. all white spaces or contains "irregular" chars, +// returns 0 ; returns 1 if valid string +// +bool +FileManager::checkValidName(const char *name) +{ + int length = strlen(name); + + for (int i = 0; i < length; i++) { + if (!isprint(name[i])) + return false; // invalid - unprintable char + if (!isspace(name[i])) + return true; // has non-white space that is printable + } + + return false; // all white spaces +} + + +// int snapEntryCmpFunc(void* e1, void* e2) +// +// a cmp function for snapshot structs that can +// used with qsort +// +// compares c_time +// +int +snapEntryCmpFunc(const void *e1, const void *e2) +{ + snapshot *entry1 = (snapshot *) * (void **) e1; + snapshot *entry2 = (snapshot *) * (void **) e2; + + if (entry1->c_time > entry2->c_time) { + return 1; + } else if (entry1->c_time < entry2->c_time) { + return -1; + } else { + return 0; + } +} diff --git a/mgmt/FileManager.h b/mgmt/FileManager.h new file mode 100644 index 00000000..b516cb73 --- /dev/null +++ b/mgmt/FileManager.h @@ -0,0 +1,152 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _FILE_MANAGER_H_ +#define _FILE_MANAGER_H_ + +/**************************************************************************** + * + * FileManager.h - Interface for class to manage configuration updates + * + * + ****************************************************************************/ + +#include + +#include "ink_hash_table.h" +#include "List.h" +#include "WebGlobals.h" +#include "MultiFile.h" +#include "WebHttpMessage.h" + +class Rollback; + +typedef void (*FileCallbackFunc) (char *); + +struct callbackListable +{ +public: + FileCallbackFunc func; + LINK(callbackListable, link); +}; + +struct fileBinding +{ + Rollback *rb; +}; + +// MUST match the ordering MFresult so that we can cast +// MFresult to SnapResult +enum SnapResult +{ SNAP_OK, SNAP_NO_DIR, SNAP_NOT_FOUND, SNAP_DIR_CREATE_FAILED, + SNAP_FILE_CREATE_FAILED, SNAP_FILE_ACCESS_FAILED, + SNAP_WRITE_FAILED, SNAP_REMOVE_FAILED, + SNAP_INVALID_SUBMISSION, SNAP_NO_NAME_GIVEN, + SNAP_ILLEGAL_NAME +}; + +enum lockAction_t +{ ACQUIRE_LOCK, RELEASE_LOCK }; +class ExpandingArray; + +// class FileManager +// +// public functions: +// +// addFile(char*, configFileInfo*) - adds a new config file to be +// managed. A rollback object is created for the file. +// if the file_info ptr is not NULL, a WebFileEdit object +// is also created +// +// getRollbckObj(char* , RollbackPtr**) - sets *rbPtr to Rollback +// object bound to baseFileName. Returns true if there is +// a binding and false otherwise +// +// getWFEObj(char*, WebFileEdit**) - sets *wfePtr to WebFileEdit +// object bound to baseFileName. Returns true if there is +// a binding and false otherwise +// +// registerCallback(FileCallbackFunc) - registers a callback function +// which will get called everytime a managed file changes. The +// callback function should NOT use the calling thread to +// access any Rollback objects or block for a long time +// +// fileChanged(const char* baseFileName) - called by Rollback objects +// when their contents change. Triggers callbacks to FileCallbackFuncs +// +// filesManaged() - returns a textBuffer that contains a new line separated +// list of call files being managed by the FileManager. CALLEE +// is responsible for deleting the returned object +// +// takeSnap(const char* snapName) - creates a new snapshot with +// passed in name +// +// restoreSnap(const char* snapName) - restores the specified snap +// shot +// +// rereadConfig() - Checks all managed files to see if they have been +// updated +// +class FileManager:public MultiFile +{ +public: + FileManager(); + ~FileManager(); + void addFile(const char *baseFileName, bool root_access_needed); + bool getRollbackObj(const char *baseFileName, Rollback ** rbPtr); + void registerCallback(FileCallbackFunc func); + void fileChanged(const char *baseFileName); + textBuffer *filesManaged(); + void rereadConfig(); + //SnapResult takeSnap(const char* snapName); + SnapResult takeSnap(const char *snapName, const char *snapDir); + //SnapResult restoreSnap(const char* snapName); + SnapResult restoreSnap(const char *snapName, const char *snapDir); + //SnapResult removeSnap(const char* snapName); + SnapResult removeSnap(const char *snapName, const char *snapDir); + void displaySnapOption(textBuffer * output); + SnapResult WalkSnaps(ExpandingArray * snapList); + +private: + void doRollbackLocks(lockAction_t action); + ink_mutex accessLock; // Protects bindings hashtable + ink_mutex cbListLock; // Protects the CallBack List + DLL cblist; + InkHashTable *bindings; + //InkHashTable* g_snapshot_directory_ht; + char *snapshotDir; + SnapResult copyFile(Rollback * rb, const char *snapPath); + SnapResult readFile(const char *filePath, textBuffer * contents); + void abortRestore(const char *abortTo); + void createSelect(char *action, textBuffer * output, ExpandingArray * options); + void snapErrorResponse(char *action, SnapResult error, textBuffer * output); + void snapSuccessResponse(char *action, textBuffer * output); + void generateRestoreConfirm(char *snapName, textBuffer * output); + bool checkValidName(const char *name); +}; + +int snapEntryCmpFunc(const void *e1, const void *e2); + +void initializeRegistry(); // implemented in AddConfigFilesHere.cc + +#endif diff --git a/mgmt/LocalManager.cc b/mgmt/LocalManager.cc new file mode 100644 index 00000000..68f4bbc8 --- /dev/null +++ b/mgmt/LocalManager.cc @@ -0,0 +1,1356 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * + * LocalManager.cc + * - The Local Manager process of the management system. + * - The main loop has been migrated to Main.cc + * + * + */ + +#include "libts.h" +#include "ink_platform.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "MgmtUtils.h" +#include "I_Layout.h" +#include "Compatability.h" +#include "LocalManager.h" +#include "MgmtSocket.h" + +#if TS_USE_POSIX_CAP +#include +#endif + +int bindProxyPort(int, char*, int, bool, int); + +bool +LocalManager::SetForDup(void *hIOCPort, long lTProcId, void *hTh) +{ + NOWARN_UNUSED(hIOCPort); + NOWARN_UNUSED(lTProcId); + NOWARN_UNUSED(hTh); + return true; +} + +void +LocalManager::mgmtCleanup() +{ + close_socket(process_server_sockfd); + + // fix me for librecords + + if (virt_map) { + virt_map->rl_downAddrs(); // We are bailing done need to worry about table + } +#ifdef MGMT_USE_SYSLOG + closelog(); +#endif /* MGMT_USE_SYSLOG */ + return; +} + + +void +LocalManager::mgmtShutdown(int status, bool mainThread) +{ + if (mainThread) { + mgmt_log("[LocalManager::mgmtShutdown] Executing shutdown request.\n"); + processShutdown(mainThread); + // WCCP TBD: Send a shutdown message to routers. + + if (processRunning()) { + waitpid(watched_process_pid, &status, 0); +#if defined(linux) + /* Avert race condition, wait for the thread to complete, + before getting one more restart process */ + /* Workaround for bugid INKqa10060 */ + mgmt_sleep_msec(1); +#endif + } + + mgmtCleanup(); + _exit(status); + } else { + mgmt_shutdown_outstanding = true; + } + return; +} + + +void +LocalManager::processShutdown(bool mainThread) +{ + mgmt_log("[LocalManager::processShutdown] Executing process shutdown request.\n"); + if (mainThread) { + sendMgmtMsgToProcesses(MGMT_EVENT_SHUTDOWN, "processShutdown[main]"); + } else { + signalEvent(MGMT_EVENT_SHUTDOWN, "processShutdown"); + } + return; +} + + +void +LocalManager::processRestart() +{ + mgmt_log("[LocalManager::processRestart] Executing process restart request.\n"); + signalEvent(MGMT_EVENT_RESTART, "processRestart"); + return; +} + + +void +LocalManager::processBounce() +{ + mgmt_log("[LocalManager::processBounce] Executing process bounce request.\n"); + signalEvent(MGMT_EVENT_BOUNCE, "processBounce"); + return; +} + +void +LocalManager::rollLogFiles() +{ + mgmt_log("[LocalManager::rollLogFiles] Log files are being rolled.\n"); + signalEvent(MGMT_EVENT_ROLL_LOG_FILES, "rollLogs"); + return; +} + +void +LocalManager::clearStats() +{ + char *statsPath; + + // Clear our records and then send the signal. There is a race condition + // here where our stats could get re-updated from the proxy + // before the proxy clears them, but this should be rare. + // + // Doing things in the opposite order prevents that race + // but excerbates the race between the node and cluster + // stats getting cleared by progation of clearing the + // cluster stats + // + RecResetStatRecord(RECT_NULL, true); + + // If the proxy is not running, sending the signal does + // not do anything. Remove the stats file to make sure + // that operation works even when the proxy is off + // + if (this->proxy_running == 0) { + statsPath = Layout::relative_to(Layout::get()->runtimedir, REC_RAW_STATS_FILE); + if (unlink(statsPath) < 0) { + if (errno != ENOENT) { + mgmt_log(stderr, "[LocalManager::clearStats] Unlink of %s failed : %s\n", REC_RAW_STATS_FILE, strerror(errno)); + } + } + xfree(statsPath); + } +} + +// void LocalManager::syslogThrInit() +// +// On the DEC, syslog is per thread. This function +// allows a thread to init syslog with the appropriate +// configuration +// +void +LocalManager::syslogThrInit() +{ +} + +// bool LocalManager::clusterOk() +// +// Returns false if the proxy has been up for more than +// 30 seconds but is not reporting that it has clustered +// with all the nodes in cluster.config +// +// Otherwise returns true +// +bool +LocalManager::clusterOk() +{ + bool found = true; + bool result = true; + + if (processRunning() == true && time(NULL) > (this->proxy_started_at + 30) + && this->ccom->alive_peers_count + 1 != REC_readInteger("proxy.process.cluster.nodes", &found)) { + result = false; + } + + ink_assert(found); + return result; +} + +bool +LocalManager::processRunning() +{ + if (watched_process_fd != -1 && watched_process_pid != -1) { + return true; + } else { + return false; + } +} + +LocalManager::LocalManager(char *mpath, bool proxy_on) + : BaseManager(), run_proxy(proxy_on) +{ + NOWARN_UNUSED(mpath); + bool found; +#ifdef MGMT_USE_SYSLOG + syslog_facility = 0; +#endif + + ccom = NULL; + proxy_started_at = -1; + proxy_launch_count = 0; + manager_started_at = time(NULL); + proxy_launch_outstanding = false; + mgmt_shutdown_outstanding = false; + proxy_running = 0; + RecSetRecordInt("proxy.node.proxy_running", 0); + mgmt_sync_key = REC_readInteger("proxy.config.lm.sem_id", &found); + if (!found || mgmt_sync_key <= 0) { + mgmt_log("Bad or missing proxy.config.lm.sem_id value; using default id %d\n", MGMT_SEMID_DEFAULT); + mgmt_sync_key = MGMT_SEMID_DEFAULT; + } + ink_strncpy(pserver_path, system_runtime_dir, sizeof(pserver_path)); + + virt_map = NULL; + + + for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) { + proxy_server_port[i] = proxy_server_fd[i] = -1; + memset((void *) proxy_server_port_attributes[i], 0, MAX_ATTR_LEN); + } + + int pnum = 0; + RecInt http_enabled = REC_readInteger("proxy.config.http.enabled", &found); + ink_debug_assert(found); + if (http_enabled && found) { + int port = (int) REC_readInteger("proxy.config.http.server_port", &found); + if (found) { + proxy_server_port[pnum] = port; + char *main_server_port_attributes = (char *) REC_readString("proxy.config.http.server_port_attr", &found); + ink_strncpy((char *) proxy_server_port_attributes[pnum], + main_server_port_attributes, sizeof(proxy_server_port_attributes[pnum])); + xfree(main_server_port_attributes); + pnum++; + } + } + + // Check to see if we are running SSL term + RecInt ssl_term_enabled = REC_readInteger("proxy.config.ssl.enabled", &found); + ink_assert(found); + if (found && ssl_term_enabled) { + // Get the SSL port + RecInt ssl_term_port = REC_readInteger("proxy.config.ssl.server_port", &found); + ink_assert(found); + if (found) { + proxy_server_port[pnum] = ssl_term_port; + ink_strncpy((char *) proxy_server_port_attributes[pnum], "S", sizeof(proxy_server_port_attributes[pnum])); + pnum++; + } + } + + // Read other ports to be listened on + char *proxy_server_other_ports = REC_readString("proxy.config.http.server_other_ports", &found); + if (proxy_server_other_ports) { + char *last, *cport; + + cport = ink_strtok_r(proxy_server_other_ports, " ", &last); + for (; pnum < MAX_PROXY_SERVER_PORTS && cport; pnum++) { + const char *attr = "X"; + + for (int j = 0; cport[j]; j++) { + if (cport[j] == ':') { + cport[j] = '\0'; + attr = &cport[j + 1]; + } + } + + int port_no = atoi(cport); + + proxy_server_port[pnum] = port_no; + ink_strncpy((char *) proxy_server_port_attributes[pnum], attr, sizeof(proxy_server_port_attributes[pnum])); + + Debug("lm", "[LocalManager::LocalManager] Adding port (%s, %d, '%s')\n", cport, port_no, attr); + cport = ink_strtok_r(NULL, " ", &last); + } + + if (pnum == MAX_PROXY_SERVER_PORTS && cport) { + Debug("lm", "[LocalManager::LocalManager] Unable to listen on all other ports," + " max number of other ports exceeded(max == %d)\n", MAX_PROXY_SERVER_PORTS); + } + xfree(proxy_server_other_ports); + } + // Bind proxy ports to incoming_ip_to_bind + char *incoming_ip_to_bind_str = REC_readString("proxy.local.incoming_ip_to_bind", &found); + if (found && incoming_ip_to_bind_str != NULL) { + proxy_server_incoming_ip_to_bind_str = incoming_ip_to_bind_str; + } else { + proxy_server_incoming_ip_to_bind_str = NULL; + } + config_path = REC_readString("proxy.config.config_dir", &found); + char *absolute_config_path = Layout::get()->relative(config_path); + xfree(config_path); + if (access(absolute_config_path, R_OK) == -1) { + config_path = xstrdup(system_config_directory); + if (access(config_path, R_OK) == -1) { + mgmt_elog("[LocalManager::LocalManager] unable to access() directory '%s': %d, %s\n", + config_path, errno, strerror(errno)); + mgmt_fatal("[LocalManager::LocalManager] please set config path via command line '-path ' or 'proxy.config.config_dir' \n"); + } + } else { + config_path = absolute_config_path; + } + +#if TS_HAS_WCCP + // Bind the WCCP address if present. + xptr wccp_addr_str(REC_readString("proxy.config.wccp.addr", &found)); + if (found && wccp_addr_str && *wccp_addr_str) { + wccp_cache.setAddr(inet_addr(wccp_addr_str)); + mgmt_log("[LocalManager::LocalManager] WCCP identifying address set to %s.\n", static_cast(wccp_addr_str)); + } + + xptr wccp_config_str(REC_readString("proxy.config.wccp.services", &found)); + if (found && wccp_config_str && *wccp_config_str) { + bool located = true; + if (access(wccp_config_str, R_OK) == -1) { + wccp_config_str = Layout::relative_to(Layout::get()->sysconfdir, wccp_config_str); + if (access(wccp_config_str, R_OK) == -1 ) { + located = false; + } + } + if (located) { + wccp_cache.loadServicesFromFile(wccp_config_str); + } else { // not located + mgmt_log("[LocalManager::LocalManager] WCCP service configuration file '%s' was specified but could not be found in the file system.\n", static_cast(wccp_config_str)); + } + } +#endif + + bin_path = REC_readString("proxy.config.bin_path", &found); + process_server_timeout_secs = REC_readInteger("proxy.config.lm.pserver_timeout_secs", &found); + process_server_timeout_msecs = REC_readInteger("proxy.config.lm.pserver_timeout_msecs", &found); + proxy_name = REC_readString("proxy.config.proxy_name", &found); + proxy_binary = REC_readString("proxy.config.proxy_binary", &found); + proxy_options = REC_readString("proxy.config.proxy_binary_opts", &found); + env_prep = REC_readString("proxy.config.env_prep", &found); + // Calculate configured bin_path from the prefix + char *absolute_bin_path = Layout::get()->relative(bin_path); + xfree(bin_path); + bin_path = absolute_bin_path; + // Calculate proxy_binary from the absolute bin_path + absolute_proxy_binary = Layout::relative_to(absolute_bin_path, proxy_binary); + + if (access(absolute_proxy_binary, R_OK | X_OK) == -1) { + // Try 'Layout::bindir' directory + xfree(absolute_proxy_binary); + absolute_proxy_binary = Layout::relative_to(Layout::get()->bindir, proxy_binary); + // coverity[fs_check_call] + if (access(absolute_proxy_binary, R_OK | X_OK) == -1) { + mgmt_elog("[LocalManager::LocalManager] Unable to access() '%s': %d, %s\n", + absolute_proxy_binary, errno, strerror(errno)); + mgmt_fatal("[LocalManager::LocalManager] please set bin path 'proxy.config.bin_path' \n"); + } + } + + internal_ticker = 0; + + watched_process_pid = -1; + + process_server_sockfd = -1; + watched_process_fd = -1; + proxy_launch_pid = -1; + + return; +} + +void +LocalManager::initAlarm() +{ + alarm_keeper = new Alarms(); +} + +/* + * initCCom(...) + * Function initializes cluster communication structure held by local manager. + */ +void +LocalManager::initCCom(int port, char *addr, int sport) +{ + bool found; + struct in_addr cluster_addr; // ip addr of the cluster interface + char *clusterAddrStr; // cluster ip addr as a String + char *intrName; // Name of the interface we are to use + char hostname[1024]; // hostname of this machine + const char envVar[] = "PROXY_CLUSTER_ADDR="; + char *envBuf; + + if (gethostname(hostname, 1024) < 0) { + mgmt_fatal(stderr, "[LocalManager::initCCom] gethostname failed\n"); + } + // Fetch which interface we are using for clustering + intrName = REC_readString("proxy.config.cluster.ethernet_interface", &found); + ink_assert(intrName != NULL); + + found = mgmt_getAddrForIntr(intrName, &cluster_addr); + if (found == false) { + mgmt_fatal(stderr, "[LocalManager::initCCom] Unable to find network interface %s. Exiting...\n", intrName); + } + + clusterAddrStr = inet_ntoa(cluster_addr); + Debug("ccom", "Cluster Interconnect is %s : %s\n", intrName, clusterAddrStr); + + // This an awful hack but I could not come up with a better way to + // pass the cluster address to the proxy + // Set an environment variable so the proxy can find out + // what the cluster address is. The reason we need this awful + // hack is that the proxy needs this info immediately at startup + // and it is different for every machine in the cluster so using + // a config variable will not work. + // The other options are to pass it on the command line to the proxy + // which would require a fair bit of code modification since + // what is passed right now is assumed to be static. The other + // is to write it to a separate file but that seems like a + // lot of trouble for a 16 character string + // Set the cluster ip addr variable so that proxy can read it + // and flush it to disk + const size_t envBuf_size = strlen(envVar) + strlen(clusterAddrStr) + 1; + envBuf = (char *) xmalloc(envBuf_size); + ink_strncpy(envBuf, envVar, envBuf_size); + strncat(envBuf, clusterAddrStr, envBuf_size - strlen(envBuf) - 1); + ink_release_assert(putenv(envBuf) == 0); + + ccom = new ClusterCom(cluster_addr.s_addr, hostname, port, addr, sport, pserver_path); + virt_map = new VMap(intrName, cluster_addr.s_addr, &lmgmt->ccom->mutex); + virt_map->downAddrs(); // Just to be safe + ccom->establishChannels(); + + if (intrName) { + xfree(intrName); + } + return; +} + +/* + * initMgmtProcessServer() + * - On UNIX, this function sets up the server socket that proxy processes connect to. + * - On WIN32, named pipes are used instead. + */ +void +LocalManager::initMgmtProcessServer() +{ + char fpath[1024]; + int servlen, one = 1; + struct sockaddr_un serv_addr; + +#if TS_HAS_WCCP + if (wccp_cache.isConfigured()) { + if (0 > wccp_cache.open()) mgmt_log("Failed to open WCCP socket\n"); + } +#endif + + snprintf(fpath, sizeof(fpath), "%s/%s", pserver_path, LM_CONNECTION_SERVER); + unlink(fpath); + if ((process_server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to open socket exiting\n"); + } + + if (fcntl(process_server_sockfd, F_SETFD, 1) < 0) { + mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to set close-on-exec\n"); + } + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + ink_strncpy(serv_addr.sun_path, fpath, sizeof(serv_addr.sun_path)); +#if defined(darwin) || defined(freebsd) + servlen = sizeof(struct sockaddr_un); +#else + servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); +#endif + if (setsockopt(process_server_sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) { + mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to set socket options.\n"); + } + + if ((bind(process_server_sockfd, (struct sockaddr *) &serv_addr, servlen)) < 0) { + mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to bind '%s' socket exiting\n", fpath); + } + + if ((listen(process_server_sockfd, 5)) < 0) { + mgmt_fatal(stderr, "[LocalManager::initMgmtProcessServer] Unable to listen on socket exiting\n"); + } + + RecSetRecordInt("proxy.node.restarts.manager.start_time", manager_started_at); +} + +/* + * pollMgmtProcessServer() + * - Function checks the mgmt process server for new processes + * and any requests sent from processes. It handles processes sent. + */ +void +LocalManager::pollMgmtProcessServer() +{ + int num; + struct timeval timeout; + struct sockaddr_in clientAddr; + fd_set fdlist; +#if TS_HAS_WCCP + int wccp_fd = wccp_cache.getSocket(); +#endif + + while (1) { + // poll only + timeout.tv_sec = process_server_timeout_secs; + timeout.tv_usec = process_server_timeout_msecs * 1000; + FD_ZERO(&fdlist); + FD_SET(process_server_sockfd, &fdlist); + if (watched_process_fd != -1) FD_SET(watched_process_fd, &fdlist); + +#if TS_HAS_WCCP + // Only run WCCP housekeeping while we have a server process. + // Note: The WCCP socket is opened iff WCCP is configured. + if (wccp_fd != ts::NO_FD && watched_process_fd != ts::NO_FD) { + wccp_cache.housekeeping(); + time_t wccp_wait = wccp_cache.waitTime(); + if (wccp_wait < process_server_timeout_secs) timeout.tv_sec = wccp_wait; + FD_SET(wccp_cache.getSocket(), &fdlist); + } +#endif + + num = mgmt_select(FD_SETSIZE, &fdlist, NULL, NULL, &timeout); + if (num == 0) { /* Have nothing */ + break; + } else if (num > 0) { /* Have something */ +#if TS_HAS_WCCP + if (wccp_fd != ts::NO_FD && FD_ISSET(wccp_fd, &fdlist)) { + wccp_cache.handleMessage(); + --num; + } +#endif + if (FD_ISSET(process_server_sockfd, &fdlist)) { /* New connection */ + int clientLen = sizeof(clientAddr); + int new_sockfd = mgmt_accept(process_server_sockfd, + (struct sockaddr *) &clientAddr, + &clientLen); + MgmtMessageHdr *mh; + int data_len; + + mgmt_log(stderr, "[LocalManager::pollMgmtProcessServer] New process connecting fd '%d'\n", new_sockfd); + + if (new_sockfd < 0) { + mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] ==> "); + } else if (!processRunning()) { + watched_process_fd = new_sockfd; + data_len = sizeof(mgmt_sync_key); + mh = (MgmtMessageHdr *) alloca(sizeof(MgmtMessageHdr) + data_len); + mh->msg_id = MGMT_EVENT_SYNC_KEY; + mh->data_len = data_len; + memcpy((char *) mh + sizeof(MgmtMessageHdr), &mgmt_sync_key, data_len); + if (mgmt_write_pipe(new_sockfd, (char *) mh, sizeof(MgmtMessageHdr) + data_len) <= 0) { + mgmt_elog("[LocalManager::pollMgmtProcessServer] Error writing sync key message!\n"); + close_socket(new_sockfd); + watched_process_fd = watched_process_pid = -1; + } + } else { + close_socket(new_sockfd); + } + --num; + } + + if (ts::NO_FD != watched_process_fd && FD_ISSET(watched_process_fd, &fdlist)) { + int res; + MgmtMessageHdr mh_hdr; + MgmtMessageHdr *mh_full; + char *data_raw; + + // read the message + if ((res = mgmt_read_pipe(watched_process_fd, (char *) &mh_hdr, sizeof(MgmtMessageHdr))) > 0) { + mh_full = (MgmtMessageHdr *) alloca(sizeof(MgmtMessageHdr) + mh_hdr.data_len); + memcpy(mh_full, &mh_hdr, sizeof(MgmtMessageHdr)); + data_raw = (char *) mh_full + sizeof(MgmtMessageHdr); + if ((res = mgmt_read_pipe(watched_process_fd, data_raw, mh_hdr.data_len)) > 0) { + handleMgmtMsgFromProcesses(mh_full); + } else if (res < 0) { + mgmt_fatal("[LocalManager::pollMgmtProcessServer] Error in read (errno: %d)\n", -res); + } + } else if (res < 0) { + mgmt_fatal("[LocalManager::pollMgmtProcessServer] Error in read (errno: %d)\n", -res); + } + // handle EOF + if (res == 0) { + int estatus; + pid_t tmp_pid = watched_process_pid; + + Debug("lm", "[LocalManager::pollMgmtProcessServer] Lost process EOF!\n"); + + close_socket(watched_process_fd); + + waitpid(watched_process_pid, &estatus, 0); /* Reap child */ + if (WIFSIGNALED(estatus)) { + int sig = WTERMSIG(estatus); + mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] " + "Server Process terminated due to Sig %d: %s\n", sig, strsignal(sig)); + } + + if (lmgmt->run_proxy) { + mgmt_elog("[Alarms::signalAlarm] Server Process was reset\n"); + lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PROCESS_DIED); + } else { + mgmt_log("[TrafficManager] Server process shutdown\n"); + } + + watched_process_fd = watched_process_pid = -1; + if (tmp_pid != -1) { /* Incremented after a pid: message is sent */ + proxy_running--; + } + proxy_started_at = -1; + RecSetRecordInt("proxy.node.proxy_running", 0); + } + + num--; + + } + ink_assert(num == 0); /* Invariant */ + + } else if (num < 0) { /* Error */ + mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] select failed or was interrupted (%d)\n", errno); + } + + } +} + + +void +LocalManager::handleMgmtMsgFromProcesses(MgmtMessageHdr * mh) +{ + char *data_raw = (char *) mh + sizeof(MgmtMessageHdr); + switch (mh->msg_id) { + case MGMT_SIGNAL_PID: + watched_process_pid = *((pid_t *) data_raw); + lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PROCESS_BORN); + proxy_running++; + proxy_launch_pid = -1; + proxy_launch_outstanding = false; + RecSetRecordInt("proxy.node.proxy_running", 1); + break; + + case MGMT_SIGNAL_MACHINE_UP: + /* + { + struct in_addr addr; + addr.s_addr = *((unsigned int*)data_raw); + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PEER_BORN, inet_ntoa(addr)); + } + */ + break; + case MGMT_SIGNAL_MACHINE_DOWN: + /* + { + struct in_addr addr; + addr.s_addr = *((unsigned int*)data_raw); + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PEER_DIED, inet_ntoa(addr)); + } + */ + break; + + // FIX: This is very messy need to correlate mgmt signals and + // alarms better + case MGMT_SIGNAL_CONFIG_ERROR: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_CONFIG_ERROR, data_raw); + break; + case MGMT_SIGNAL_SYSTEM_ERROR: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_SYSTEM_ERROR, data_raw); + break; + case MGMT_SIGNAL_LOG_SPACE_CRISIS: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_LOG_SPACE_CRISIS, data_raw); + break; + case MGMT_SIGNAL_CACHE_ERROR: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_CACHE_ERROR, data_raw); + break; + case MGMT_SIGNAL_CACHE_WARNING: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_CACHE_WARNING, data_raw); + break; + case MGMT_SIGNAL_LOGGING_ERROR: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_LOGGING_ERROR, data_raw); + break; + case MGMT_SIGNAL_LOGGING_WARNING: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_LOGGING_WARNING, data_raw); + break; + case MGMT_SIGNAL_CONFIG_FILE_READ: + mgmt_log(stderr, "[LocalManager::handleMgmtMsgFromProcesses] File done '%d'\n", data_raw); + break; + case MGMT_SIGNAL_PLUGIN_ADD_REC: + { + char var_name[256]; + char var_value[256]; + RecDataT data_type; + // data_type is an enum type, so cast to an int* to avoid warnings. /leif + // coverity[secure_coding] + if (sscanf(data_raw, "%255s %d %255s", var_name, (int *) &data_type, var_value) != 3) { + Debug("lm", "Warning: Bad data_type: %s", (char *) data_raw); + data_type = RECD_MAX; + } + switch (data_type) { + case RECD_COUNTER: + RecRegisterStatCounter(RECT_PLUGIN, var_name, ink_atoi64(var_value), RECP_NULL); + break; + case RECD_INT: + RecRegisterStatInt(RECT_PLUGIN, var_name, ink_atoi64(var_value), RECP_NULL); + break; + case RECD_FLOAT: + RecRegisterStatFloat(RECT_PLUGIN, var_name, atof(var_value), RECP_NULL); + break; + case RECD_STRING: + RecRegisterStatString(RECT_PLUGIN, var_name, var_value, RECP_NULL); + break; + default: + break; + } + break; + } + case MGMT_SIGNAL_PLUGIN_SET_CONFIG: + { + char var_name[256]; + char var_value[256]; + MgmtType stype; + // stype is an enum type, so cast to an int* to avoid warnings. /leif + int tokens = sscanf(data_raw, "%255s %d %255s", var_name, (int *) &stype, var_value); + if (tokens != 3) { + stype = INVALID; + } + switch (stype) { + case INK_INT: + RecSetRecordInt(var_name, ink_atoi64(var_value)); + break; + case INK_COUNTER: + case INK_FLOAT: + case INK_STRING: + case INVALID: + default: + mgmt_elog(stderr, + "[LocalManager::handleMgmtMsgFromProcesses] " "Invalid plugin set-config msg '%s'\n", data_raw); + break; + } + } + case MGMT_SIGNAL_LOG_FILES_ROLLED: + { + Debug("lm", "Rolling logs %s", (char *) data_raw); + break; + } + case MGMT_SIGNAL_LIBRECORDS: + if (mh->data_len > 0) { + executeMgmtCallback(MGMT_SIGNAL_LIBRECORDS, data_raw, mh->data_len); + } else { + executeMgmtCallback(MGMT_SIGNAL_LIBRECORDS, NULL, 0); + } + break; + // Congestion Control - begin + case MGMT_SIGNAL_HTTP_CONGESTED_SERVER: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_HTTP_CONGESTED_SERVER, data_raw); + break; + case MGMT_SIGNAL_HTTP_ALLEVIATED_SERVER: + alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_HTTP_ALLEVIATED_SERVER, data_raw); + break; + // Congestion Control - end + case INK_MGMT_SIGNAL_WDA_BILLING_CONNECTION_DIED: + alarm_keeper->signalAlarm(MGMT_ALARM_WDA_BILLING_CONNECTION_DIED, data_raw); + break; + case INK_MGMT_SIGNAL_WDA_BILLING_CORRUPTED_DATA: + alarm_keeper->signalAlarm(MGMT_ALARM_WDA_BILLING_CORRUPTED_DATA, data_raw); + break; + case INK_MGMT_SIGNAL_WDA_XF_ENGINE_DOWN: + alarm_keeper->signalAlarm(MGMT_ALARM_WDA_XF_ENGINE_DOWN, data_raw); + break; + // Wireless plugin signal - end + case INK_MGMT_SIGNAL_SAC_SERVER_DOWN: + alarm_keeper->signalAlarm(MGMT_ALARM_SAC_SERVER_DOWN, data_raw); + break; + + default: + break; + } + + // #define MGMT_ALARM_ACC_ALARMS_START 200 + // #define MGMT_ALARM_ACC_ALARMS_END 299 + + if (mh->msg_id >= INK_MGMT_SIGNAL_ACC_ALARMS_START && mh->msg_id <= INK_MGMT_SIGNAL_ACC_ALARMS_END) { + alarm_keeper->signalAlarm(mh->msg_id, data_raw); + } +} + + +void +LocalManager::sendMgmtMsgToProcesses(int msg_id, const char *data_str) +{ + sendMgmtMsgToProcesses(msg_id, data_str, strlen(data_str) + 1); + return; +} + + +void +LocalManager::sendMgmtMsgToProcesses(int msg_id, const char *data_raw, int data_len) +{ + MgmtMessageHdr *mh; + + mh = (MgmtMessageHdr *) alloca(sizeof(MgmtMessageHdr) + data_len); + mh->msg_id = msg_id; + mh->data_len = data_len; + memcpy((char *) mh + sizeof(MgmtMessageHdr), data_raw, data_len); + sendMgmtMsgToProcesses(mh); + return; +} + + +void +LocalManager::sendMgmtMsgToProcesses(MgmtMessageHdr * mh) +{ + switch (mh->msg_id) { + case MGMT_EVENT_SHUTDOWN:{ + run_proxy = false; + if (lmgmt->virt_map) { + lmgmt->virt_map->downAddrs(); /* Down all known addrs to be safe */ + } + for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) { + if (proxy_server_fd[i] != -1) { // Close the socket + close_socket(proxy_server_fd[i]); + proxy_server_fd[i] = -1; + } + } + break; + } + case MGMT_EVENT_RESTART: + run_proxy = true; + listenForProxy(); + return; + case MGMT_EVENT_BOUNCE: /* Just bouncing the cluster, have it exit well restart */ + mh->msg_id = MGMT_EVENT_SHUTDOWN; + break; + case MGMT_EVENT_ROLL_LOG_FILES: + mgmt_log("[LocalManager::SendMgmtMsgsToProcesses]Event is being constructed .\n"); + break; + case MGMT_EVENT_CONFIG_FILE_UPDATE: + bool found; + char *fname; + Rollback *rb; + char *data_raw; + + data_raw = (char *) mh + sizeof(MgmtMessageHdr); + fname = REC_readString(data_raw, &found); + + RecT rec_type; + if (RecGetRecordType(data_raw, &rec_type) == REC_ERR_OKAY && rec_type == RECT_CONFIG) { + RecSetSyncRequired(data_raw); + } else { + mgmt_elog(stderr, "[LocalManager:sendMgmtMsgToProcesses] Unknown file change: '%s'\n", data_raw); + } + ink_assert(found); + if (!(configFiles->getRollbackObj(fname, &rb)) && + (strcmp(data_raw, "proxy.config.cluster.cluster_configuration") != 0) && + (strcmp(data_raw, "proxy.config.arm.acl_filename_master") != 0) && + (strcmp(data_raw, "proxy.config.body_factory.template_sets_dir") != 0)) { + mgmt_elog(stderr, "[LocalManager::sendMgmtMsgToProcesses] " + "Invalid 'data_raw' for MGMT_EVENT_CONFIG_FILE_UPDATE\n"); + ink_assert(false); + } + xfree(fname); + break; + } + + if (watched_process_fd != -1) { + if (mgmt_write_pipe(watched_process_fd, (char *) mh, sizeof(MgmtMessageHdr) + mh->data_len) <= 0) { + // In case of Linux, sometimes when the TS dies, the connection between TS and TM + // is not closed properly. the socket does not receive an EOF. So, the TM does + // not detect that the connection and hence TS has gone down. Hence it still + // tries to send a message to TS, but encounters an error and enters here + // Also, ensure that this whole thing is done only once because there will be a + // deluge of message in the traffic.log otherwise + + static pid_t check_prev_pid = watched_process_pid; + static pid_t check_current_pid = watched_process_pid; + if (check_prev_pid != watched_process_pid) { + check_prev_pid = watched_process_pid; + check_current_pid = watched_process_pid; + } + + if (check_prev_pid == check_current_pid) { + check_current_pid = -1; + int lerrno = errno; + mgmt_elog(stderr, "[LocalManager::sendMgmtMsgToProcesses] Error writing message\n"); + if (lerrno == ECONNRESET || lerrno == EPIPE) { // Connection closed by peer or Broken pipe + if ((kill(watched_process_pid, 0) < 0) && (errno == ESRCH)) { + // TS is down + pid_t tmp_pid = watched_process_pid; + close_socket(watched_process_fd); + mgmt_elog(stderr, "[LocalManager::pollMgmtProcessServer] " "Server Process has been terminated\n"); + if (lmgmt->run_proxy) { + mgmt_elog("[Alarms::signalAlarm] Server Process was reset\n"); + lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_PROCESS_DIED); + } else { + mgmt_log("[TrafficManager] Server process shutdown\n"); + } + watched_process_fd = watched_process_pid = -1; + if (tmp_pid != -1) { /* Incremented after a pid: message is sent */ + proxy_running--; + } + proxy_started_at = -1; + RecSetRecordInt("proxy.node.proxy_running", 0); + // End of TS down + } else { + // TS is still up, but the connection is lost + const char *err_msg = + "The TS-TM connection is broken for some reason. Either restart TS and TM or correct this error for TM to display TS statistics correctly"; + lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_SYSTEM_ERROR, err_msg); + } + + // check if the TS is down, by checking the pid + // if TS is down, then, + // raise an alarm + // set the variables so that TS is restarted later + // else (TS is still up) + // raise an alarm stating the problem + } + } + } + } +} + + +void +LocalManager::signalFileChange(const char *var_name) +{ + signalEvent(MGMT_EVENT_CONFIG_FILE_UPDATE, var_name); + return; +} + + +void +LocalManager::signalEvent(int msg_id, const char *data_str) +{ + signalEvent(msg_id, data_str, strlen(data_str) + 1); + return; +} + + +void +LocalManager::signalEvent(int msg_id, const char *data_raw, int data_len) +{ + MgmtMessageHdr *mh; + + mh = (MgmtMessageHdr *) xmalloc(sizeof(MgmtMessageHdr) + data_len); + mh->msg_id = msg_id; + mh->data_len = data_len; + memcpy((char *) mh + sizeof(MgmtMessageHdr), data_raw, data_len); + ink_assert(enqueue(mgmt_event_queue, mh)); + + return; +} + + +/* + * processEventQueue() + * Function drains and processes the mgmt event queue + * notifying any registered callback functions and performing + * any mgmt tasks for each event. + */ +void +LocalManager::processEventQueue() +{ + bool handled_by_mgmt; + + while (!queue_is_empty(mgmt_event_queue)) { + handled_by_mgmt = false; + + MgmtMessageHdr *mh = (MgmtMessageHdr *) dequeue(mgmt_event_queue); + char *data_raw = (char *) mh + sizeof(MgmtMessageHdr); + + // check if we have a local file update + if (mh->msg_id == MGMT_EVENT_CONFIG_FILE_UPDATE) { + // records.config + if (!(strcmp(data_raw, "records.config"))) { + if (RecReadConfigFile() != REC_ERR_OKAY) { + mgmt_elog(stderr, "[fileUpdated] Config update failed for records.config\n"); + } + handled_by_mgmt = true; + } + } + + if (!handled_by_mgmt) { + if (processRunning() == false) { + // Fix INKqa04984 + // If traffic server hasn't completely come up yet, + // we will hold off until next round. + ink_assert(enqueue(mgmt_event_queue, mh)); + return; + } + Debug("lm", "[TrafficManager] ==> Sending signal event '%d'\n", mh->msg_id); + lmgmt->sendMgmtMsgToProcesses(mh); + } + + xfree(mh); + } +} + + +/* + * startProxy() + * Function fires up a proxy process. + */ +bool +LocalManager::startProxy() +{ + if (proxy_launch_outstanding) { + return false; + } + mgmt_log(stderr, "[LocalManager::startProxy] Launching ts process\n"); + + pid_t pid; + + // Before we do anything lets check for the existence of + // the traffic server binary along with it's execute permmissions + if (access(absolute_proxy_binary, F_OK) < 0) { + // Error can't find traffic_server + mgmt_elog(stderr, "[LocalManager::startProxy] Unable to find traffic server at %s\n", absolute_proxy_binary); + return false; + } + // traffic server binary exists, check permissions + else if (access(absolute_proxy_binary, R_OK | X_OK) < 0) { + // Error don't have proper permissions + mgmt_elog(stderr, "[LocalManager::startProxy] Unable to access %s due to bad permisssions \n", + absolute_proxy_binary); + return false; + } + + if (env_prep) { +#ifdef POSIX_THREAD + if ((pid = fork()) < 0) +#else + if ((pid = fork1()) < 0) +#endif + { + mgmt_elog(stderr, "[LocalManager::startProxy] Unable to fork1 prep process\n"); + return false; + } else if (pid > 0) { + int estatus; + waitpid(pid, &estatus, 0); + } else { + int res; + char env_prep_bin[1024]; + + snprintf(env_prep_bin, sizeof(env_prep_bin), "%s/%s", bin_path, env_prep); + res = execl(env_prep_bin, env_prep, (char*)NULL); + _exit(res); + } + } +#ifdef POSIX_THREAD + if ((pid = fork()) < 0) +#else + if ((pid = fork1()) < 0) +#endif + { + mgmt_elog(stderr, "[LocalManager::startProxy] Unable to fork1 process\n"); + return false; + } else if (pid > 0) { /* Parent */ + proxy_launch_pid = pid; + proxy_launch_outstanding = true; + proxy_started_at = time(NULL); + ++proxy_launch_count; + RecSetRecordInt("proxy.node.restarts.proxy.start_time", proxy_started_at); + RecSetRecordInt("proxy.node.restarts.proxy.restart_count", proxy_launch_count); + } else { + int res, i = 0, n; + char real_proxy_options[2048], *options[32], *last, *tok; + + snprintf(real_proxy_options, sizeof(real_proxy_options), "%s", proxy_options); + n = strlen(real_proxy_options); + + // Check if we need to pass down port/fd information to + // traffic_server + if (proxy_server_fd[0] != -1) { + snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, " -A"); + n = strlen(real_proxy_options); + // Handle some syntax issues + if (proxy_server_fd[0] != -1) { + snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, ","); + n = strlen(real_proxy_options); + } + // Fill in the rest of the fd's + if (proxy_server_fd[0] != -1) { + snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, + "%d:%s", proxy_server_fd[0], (char*)proxy_server_port_attributes[0]); + n = strlen(real_proxy_options); + for (i = 1; i 0; i++) { + snprintf(&real_proxy_options[n], sizeof(real_proxy_options) - n, + ",%d:%s", proxy_server_fd[i], (char*)proxy_server_port_attributes[i]); + n = strlen(real_proxy_options); + } + } + } + + Debug("lm", "[LocalManager::startProxy] Launching %s with options '%s'\n", + absolute_proxy_binary, real_proxy_options); + + for (i = 0; i < 32; i++) + options[i] = NULL; + options[0] = absolute_proxy_binary; + i = 1; + tok = ink_strtok_r(real_proxy_options, " ", &last); + options[i++] = tok; + while (i < 32 && (tok = ink_strtok_r(NULL, " ", &last))) { + options[i++] = tok; + } + + if (!strstr(proxy_options, "-M")) { // Make sure we're starting the proxy in mgmt mode + mgmt_fatal(stderr, "[LocalManager::startProxy] ts options must contain -M"); + } + + res = execv(absolute_proxy_binary, options); + mgmt_elog(stderr, "[LocalManager::startProxy] Exec of %s failed\n", absolute_proxy_binary); + _exit(res); + } + return true; +} + + +/* + * listenForProxy() + * Function listens on the accept port of the proxy, so users aren't dropped. + */ +void +LocalManager::listenForProxy() +{ + if (!run_proxy) + return; + + // We are not already bound, bind the port + for (int i = 0; i < MAX_PROXY_SERVER_PORTS; i++) { + if (proxy_server_port[i] != -1) { + if (proxy_server_fd[i] < 0) { + int domain = AF_INET; + int type = SOCK_STREAM; + bool transparent = false; + + switch (*proxy_server_port_attributes[i]) { + case 'D': + // D is for DNS proxy, udp only + type = SOCK_DGRAM; + break; + case '>': // in-bound (client side) transparent + case '=': // fully transparent + transparent = true; + break; + default: + type = SOCK_STREAM; + } + + switch (*(proxy_server_port_attributes[i] + 1)) { + case '6': + domain = AF_INET6; + break; + default: + domain = AF_INET; + } + + proxy_server_fd[i] = bindProxyPort(proxy_server_port[i], proxy_server_incoming_ip_to_bind_str, domain, transparent, type); + } + + if (*proxy_server_port_attributes[i] != 'D') { + if ((listen(proxy_server_fd[i], 1024)) < 0) { + mgmt_fatal(stderr, "[LocalManager::listenForProxy] Unable to listen on socket: %d\n", proxy_server_port[i]); + } + mgmt_log(stderr, "[LocalManager::listenForProxy] Listening on port: %d\n", proxy_server_port[i]); + } else { + break; + } + } + } + return; +} + +#if TS_USE_POSIX_CAP +/** Control file access privileges to bypass DAC. + @parm state Use @c true to enable elevated privileges, + @c false to disable. + @return @c true if successful, @c false otherwise. + + @internal After some pondering I decided that the file access + privilege was worth the effort of restricting. Unlike the network + privileges this can protect a host system from programming errors + by not (usually) permitting such errors to access arbitrary + files. This is particularly true since none of the config files + current enable this feature so it's not actually called. Still, + best to program defensively and have it available. + */ +bool +elevateFileAccess(bool state) +{ + bool zret = false; // return value. + cap_t cap_state = cap_get_proc(); // current capabilities + // Make a list of the capabilities we changed. + cap_value_t cap_list[] = { CAP_DAC_OVERRIDE }; + static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); + + cap_set_flag(cap_state, CAP_EFFECTIVE, CAP_COUNT, cap_list, state ? CAP_SET : CAP_CLEAR); + zret = (0 == cap_set_proc(cap_state)); + cap_free(cap_state); + return zret; +} +#else +// bool removeRootPriv() +// +// - Returns true on success +// and false on failure +// - no-op on WIN32 +bool +removeRootPriv(uid_t euid) +{ + if (seteuid(euid) < 0) { + Debug("lm", "[removeRootPriv] seteuid failed : %s\n", strerror(errno)); + return false; + } + + Debug("lm", "[removeRootPriv] removed root privileges. Euid is %d\n", euid); + return true; +} + +// bool restoreRootPriv() +// +// - Returns true on success +// and false on failure +// - no-op on WIN32 +bool +restoreRootPriv(uid_t *old_euid) +{ + if (old_euid) + *old_euid = geteuid(); + if (seteuid(0) < 0) { + Debug("lm", "[restoreRootPriv] seteuid root failed : %s\n", strerror(errno)); + return false; + } + + Debug("lm", "[restoreRootPriv] restored root privileges. Euid is %d\n", 0); + + return true; +} +#endif + +/* + * bindProxyPort() + * Function binds the accept port of the proxy + * Also, type specifies udp or tcp + */ +int +bindProxyPort(int proxy_port, char *incoming_ip_to_bind_str, int domain, bool transparent, int type) +{ + int one = 1; + int proxy_port_fd = -1; + struct addrinfo hints; + struct addrinfo *result = NULL; + char proxy_port_str[8] = {'\0'}; + int err = 0; + +#if !TS_USE_POSIX_CAP + bool privBoost = false; + uid_t euid = geteuid(); + uid_t saved_euid = 0; + + if (proxy_port < 1024 && euid != 0) { + if (restoreRootPriv(&saved_euid) == false) { + mgmt_elog(stderr, "[bindProxyPort] Unable to get root priviledges to bind port %d. euid is %d. Exiting\n", + proxy_port, euid); + _exit(0); + } else { + privBoost = true; + } + } +#endif + + /* Setup reliable connection, for large config changes */ + if ((proxy_port_fd = socket(domain, type, 0)) < 0) { + mgmt_elog(stderr, "[bindProxyPort] Unable to create socket : %s\n", strerror(errno)); + _exit(1); + } + if (domain == AF_INET6) { + if (setsockopt(proxy_port_fd, IPPROTO_IPV6, IPV6_V6ONLY, ON, sizeof(int)) < 0) { + mgmt_elog(stderr, "[bindProxyPort] Unable to set socket options: %d : %s\n", proxy_port, strerror(errno)); + } + } + if (setsockopt(proxy_port_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int)) < 0) { + mgmt_elog(stderr, "[bindProxyPort] Unable to set socket options: %d : %s\n", proxy_port, strerror(errno)); + _exit(1); + } + + if (transparent) { +#if TS_USE_TPROXY + int transparent_value = 1; + Debug("http_tproxy", "Listen port %d inbound transparency enabled.\n", proxy_port); + if (setsockopt(proxy_port_fd, SOL_IP, TS_IP_TRANSPARENT, &transparent_value, sizeof(transparent_value)) == -1) { + mgmt_elog(stderr, "[bindProxyPort] Unable to set transparent socket option [%d] %s\n", errno, strerror(errno)); + _exit(1); + } +#else + Debug("lm", "[bindProxyPort] Transparency requested but TPROXY not configured\n"); +#endif + } + + snprintf(proxy_port_str, sizeof(proxy_port_str), "%d", proxy_port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = domain; + hints.ai_socktype = type; + hints.ai_flags = AI_PASSIVE; + + err = getaddrinfo(incoming_ip_to_bind_str, proxy_port_str, &hints, &result); + if (err != 0) { + mgmt_elog(stderr, "[bindProxyPort] Unable to get address info: %s : %s\n", incoming_ip_to_bind_str, gai_strerror(err)); + _exit(1); + } + + if((bind(proxy_port_fd, result->ai_addr, result->ai_addrlen)) < 0) { + mgmt_elog(stderr, "[bindProxyPort] Unable to bind socket: %d : %s\n", proxy_port, strerror(errno)); + _exit(1); + } + + freeaddrinfo(result); + + Debug("lm", "[bindProxyPort] Successfully bound proxy port %d\n", proxy_port); + +#if !TS_USE_POSIX_CAP + if (proxy_port < 1024 && euid != 0) { + if (privBoost == true) { + if (removeRootPriv(saved_euid) == false) { + mgmt_elog(stderr, "[bindProxyPort] Unable to reset permissions to euid %d. Exiting...\n", getuid()); + _exit(1); + } + } + } +#endif + return proxy_port_fd; +} + +void +LocalManager::signalAlarm(int alarm_id, const char *desc, const char *ip) +{ + if (alarm_keeper) + alarm_keeper->signalAlarm((alarm_t) alarm_id, desc, ip); +} diff --git a/mgmt/LocalManager.h b/mgmt/LocalManager.h new file mode 100644 index 00000000..a8de6489 --- /dev/null +++ b/mgmt/LocalManager.h @@ -0,0 +1,194 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * + * LocalManager.h + * Definitions for the LocalManager class. + * + * $Date: 2007-10-05 16:56:44 $ + * + * + */ + +#ifndef _LOCAL_MANAGER_H +#define _LOCAL_MANAGER_H + +#include "Main.h" +#include "Alarms.h" +#include "BaseManager.h" +#include "ClusterCom.h" +#include "VMap.h" +#if TS_HAS_WCCP +#include +#endif + +#if !defined(WIN32) +#define ink_get_hrtime ink_get_hrtime_internal +#define ink_get_based_hrtime ink_get_based_hrtime_internal +#endif + +class LocalManager: public BaseManager +{ +public: + LocalManager(char *mpath, bool proxy_on); + + ~LocalManager() + { + delete alarm_keeper; + delete virt_map; + delete ccom; + if (config_path) + { + xfree(config_path); + } + if (bin_path) + { + xfree(bin_path); + } + if (absolute_proxy_binary) { + xfree(absolute_proxy_binary); + } + if (proxy_name) { + xfree(proxy_name); + } + if (proxy_binary) { + xfree(proxy_binary); + } + if (proxy_options) { + xfree(proxy_options); + } + if (env_prep) { + xfree(env_prep); + } + }; + + void initAlarm(); + void initCCom(int port, char *addr, int sport); + void initMgmtProcessServer(); + void pollMgmtProcessServer(); + void handleMgmtMsgFromProcesses(MgmtMessageHdr * mh); + void sendMgmtMsgToProcesses(int msg_id, const char *data_str); + void sendMgmtMsgToProcesses(int msg_id, const char *data_raw, int data_len); + void sendMgmtMsgToProcesses(MgmtMessageHdr * mh); + + void signalFileChange(const char *var_name); + void signalEvent(int msg_id, const char *data_str); + void signalEvent(int msg_id, const char *data_raw, int data_len); + void signalAlarm(int alarm_id, const char *desc = NULL, const char *ip = NULL); + + void processEventQueue(); + bool startProxy(); + void listenForProxy(); + + void mgmtCleanup(); + void mgmtShutdown(int status, bool mainThread = false); + void processShutdown(bool mainThread = false); + void processRestart(); + void processBounce(); + void rollLogFiles(); + void clearStats(); + + bool processRunning(); + bool clusterOk(); + bool SetForDup(void *hIOCPort, long lTProcId, void *hTh); + + void tick() + { + ++internal_ticker; + }; + void resetTicker() + { + internal_ticker = 0; + } + + void syslogThrInit(); + + volatile bool run_proxy; + volatile time_t manager_started_at; + volatile time_t proxy_started_at; + volatile int proxy_launch_count; + volatile bool proxy_launch_outstanding; + volatile bool mgmt_shutdown_outstanding; + volatile int proxy_running; + volatile int proxy_server_port[MAX_PROXY_SERVER_PORTS]; + volatile char proxy_server_port_attributes[MAX_PROXY_SERVER_PORTS][MAX_ATTR_LEN]; + volatile int proxy_server_fd[MAX_PROXY_SERVER_PORTS]; + in_addr_t proxy_server_incoming_ip_to_bind; + char *proxy_server_incoming_ip_to_bind_str; + + int process_server_timeout_secs; + int process_server_timeout_msecs; + + char pserver_path[PATH_NAME_MAX]; + char *config_path; + char *bin_path; + char *absolute_proxy_binary; + char *proxy_name; + char *proxy_binary; + char *proxy_options; + char *env_prep; + +#ifndef _WIN32 + int process_server_sockfd; + volatile int watched_process_fd; + volatile pid_t proxy_launch_pid; +#else + bool process_server_connected; + int proxy_valid_server_ports; + HANDLE process_server_hpipe; + HANDLE process_connect_hevent; + HANDLE proxy_launch_hproc; + HANDLE proxy_IOCPort; +#endif + + int mgmt_sync_key; + + Alarms *alarm_keeper; + VMap *virt_map; + + ClusterCom *ccom; + + volatile int internal_ticker; + volatile pid_t watched_process_pid; + +#ifdef MGMT_USE_SYSLOG + int syslog_facility; +#endif + +#if TS_HAS_WCCP + wccp::Cache wccp_cache; +# endif +private: +}; /* End class LocalManager */ + +extern LocalManager *lmgmt; + +#if TS_USE_POSIX_CAP +bool elevateFileAccess(bool); +#else +bool restoreRootPriv(uid_t *old_euid = NULL); +bool removeRootPriv(uid_t euid); +#endif + +#endif /* _LOCAL_MANAGER_H */ diff --git a/mgmt/Main.cc b/mgmt/Main.cc new file mode 100644 index 00000000..d4ab3ef9 --- /dev/null +++ b/mgmt/Main.cc @@ -0,0 +1,1330 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * + * Main.cc + * - Entry point to the traffic manager. + * - Splitted off from LocalManager.cc on 10/23/98. + * + * + */ + +#include "ink_config.h" +#include "ink_platform.h" +#include "ink_sys_control.h" + +#include "Main.h" +#include "MgmtUtils.h" +#include "MgmtSchema.h" +#include "WebMgmtUtils.h" +#include "WebIntrMain.h" +#include "WebOverview.h" +#include "FileManager.h" +#include "I_Layout.h" +#include "I_Version.h" +#include "ink_syslog.h" +#include "ink_lockfile.h" +#include "Diags.h" +#include "DiagsConfig.h" +#include "URL.h" +#include "MIME.h" +#include "HTTP.h" + +// Needs LibRecordsConfigInit() +#include "RecordsConfig.h" + +#if defined(MGMT_API) +#include "TSControlMain.h" +#endif + + +#include "StatProcessor.h" +#include "P_RecLocal.h" +#include "P_RecCore.h" + +#if TS_USE_POSIX_CAP +#include +#endif + +#define FD_THROTTLE_HEADROOM (128 + 64) // TODO: consolidate with THROTTLE_FD_HEADROOM + +// TODO: Use positive instead negative selection +#if !defined(linux) && !defined(darwin) && !defined(freebsd) && !defined(solaris) +extern "C" +{ + int gethostname(char *name, int namelen); +} +#endif + +#if defined(freebsd) +extern "C" int getpwnam_r(const char *name, struct passwd *result, char *buffer, size_t buflen, struct passwd **resptr); +#endif + +LocalManager *lmgmt = NULL; +FileManager *configFiles; + +StatProcessor *statProcessor; // Statistics Processors +AppVersionInfo appVersionInfo; // Build info for this application + +inkcoreapi Diags *diags; +inkcoreapi DiagsConfig *diagsConfig; +char debug_tags[1024] = ""; +char action_tags[1024] = ""; +int diags_init = 0; +bool proxy_on = true; +bool forceProcessRecordsSnap = false; + +bool schema_on = false; +char *schema_path = NULL; + +// TODO: Check if really need those +char system_root_dir[PATH_NAME_MAX + 1]; +char system_runtime_dir[PATH_NAME_MAX + 1]; +char system_config_directory[PATH_NAME_MAX + 1]; +char system_log_dir[PATH_NAME_MAX + 1]; + +char mgmt_path[PATH_NAME_MAX + 1]; + +// By default, set the current directory as base +const char *ts_base_dir = "."; +const char *recs_conf = "records.config"; + +int fds_limit; + +typedef void (*PFV) (int); +// TODO: Use positive instead negative selection +// Thsis should just be #if defined(solaris) +#if !defined(linux) && !defined(freebsd) && !defined(darwin) +void SignalHandler(int sig, siginfo_t * t, void *f); +void SignalAlrmHandler(int sig, siginfo_t * t, void *f); +#else +void SignalHandler(int sig); +void SignalAlrmHandler(int sig); +#endif + +volatile int sigHupNotifier = 0; +volatile int sigUsr2Notifier = 0; +void SigChldHandler(int sig); + +void +check_lockfile() +{ + char lockfile[PATH_MAX]; + int err; + pid_t holding_pid; + + ////////////////////////////////////// + // test for presence of server lock // + ////////////////////////////////////// + Layout::relative_to(lockfile, PATH_MAX, Layout::get()->runtimedir, SERVER_LOCK); + Lockfile server_lockfile(lockfile); + err = server_lockfile.Open(&holding_pid); + if (err == 1) { + server_lockfile.Close(); // no server running + } else { + char *reason = strerror(-err); + if (err == 0) { + // TODO: Add PID_FMT_T instead duplicating code just for printing +#if defined(solaris) + fprintf(stderr, "FATAL: Lockfile '%s' says server already running as PID %d\n", lockfile, (int)holding_pid); +#else + fprintf(stderr, "FATAL: Lockfile '%s' says server already running as PID %d\n", lockfile, holding_pid); +#endif + mgmt_elog(stderr, "FATAL: Lockfile '%s' says server already running as PID %d\n", lockfile, holding_pid); + } else { + fprintf(stderr, "FATAL: Can't open server lockfile '%s' (%s)\n", lockfile, (reason ? reason : "Unknown Reason")); + mgmt_elog(stderr, "FATAL: Can't open server lockfile '%s' (%s)\n", + lockfile, (reason ? reason : "Unknown Reason")); + } + exit(1); + } + + /////////////////////////////////////////// + // try to get the exclusive manager lock // + /////////////////////////////////////////// + Layout::relative_to(lockfile, PATH_MAX, Layout::get()->runtimedir, MANAGER_LOCK); + Lockfile manager_lockfile(lockfile); + err = manager_lockfile.Get(&holding_pid); + if (err != 1) { + char *reason = strerror(-err); + fprintf(stderr, "FATAL: Can't acquire manager lockfile '%s'", lockfile); + mgmt_elog(stderr, "FATAL: Can't acquire manager lockfile '%s'", lockfile); + if (err == 0) { +#if defined(solaris) + fprintf(stderr, " (Lock file held by process ID %d)\n", (int)holding_pid); +#else + fprintf(stderr, " (Lock file held by process ID %d)\n", holding_pid); +#endif + mgmt_elog(stderr, " (Lock file held by process ID %d)\n", holding_pid); + } else if (reason) { + fprintf(stderr, " (%s)\n", reason); + mgmt_elog(stderr, " (%s)\n", reason); + } else { + fprintf(stderr, "\n"); + } + exit(1); + + fprintf(stderr, "unable to acquire manager lock [%d]\n", -err); + exit(1); + } +} + + +void +initSignalHandlers() +{ +#ifndef _WIN32 + struct sigaction sigHandler, sigChldHandler, sigAlrmHandler; + sigset_t sigsToBlock; + + // Set up the signal handler +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + sigHandler.sa_handler = NULL; + sigHandler.sa_sigaction = SignalHandler; +#else + sigHandler.sa_handler = SignalHandler; +#endif + sigemptyset(&sigHandler.sa_mask); + + // We want the handler to remain in place on + // SIGHUP to avoid any races with the signals + // coming too quickly. Also restart systems calls + // after the signal since not all calls are wrapped + // to check errno for EINTR + sigHandler.sa_flags = SA_RESTART; + sigaction(SIGHUP, &sigHandler, NULL); + sigaction(SIGUSR2, &sigHandler, NULL); + + // Don't block the signal on entry to the signal + // handler so we can reissue it and get a core + // file in the appropriate circumstances +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + sigHandler.sa_flags = SA_RESETHAND | SA_SIGINFO; +#else + sigHandler.sa_flags = SA_RESETHAND; +#endif + sigaction(SIGINT, &sigHandler, NULL); + sigaction(SIGQUIT, &sigHandler, NULL); + sigaction(SIGILL, &sigHandler, NULL); + sigaction(SIGBUS, &sigHandler, NULL); + sigaction(SIGSEGV, &sigHandler, NULL); + sigaction(SIGTERM, &sigHandler, NULL); + +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + sigAlrmHandler.sa_handler = NULL; + sigAlrmHandler.sa_sigaction = SignalAlrmHandler; +#else + sigAlrmHandler.sa_handler = SignalAlrmHandler; +#endif + + sigemptyset(&sigAlrmHandler.sa_mask); +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + sigAlrmHandler.sa_flags = SA_SIGINFO; +#else + sigAlrmHandler.sa_flags = 0; +#endif + sigaction(SIGALRM, &sigAlrmHandler, NULL); + + // Block the delivery of any signals we are not catching + // + // except for SIGALARM since we use it + // to break out of deadlock on semaphore + // we share with the proxy + // + sigfillset(&sigsToBlock); + sigdelset(&sigsToBlock, SIGHUP); + sigdelset(&sigsToBlock, SIGUSR2); + sigdelset(&sigsToBlock, SIGINT); + sigdelset(&sigsToBlock, SIGQUIT); + sigdelset(&sigsToBlock, SIGILL); + sigdelset(&sigsToBlock, SIGABRT); + sigdelset(&sigsToBlock, SIGBUS); + sigdelset(&sigsToBlock, SIGSEGV); + sigdelset(&sigsToBlock, SIGTERM); + sigdelset(&sigsToBlock, SIGALRM); + ink_thread_sigsetmask(SIG_SETMASK, &sigsToBlock, NULL); + + // Set up the SIGCHLD handler so we do not get into + // a problem with Solaris 2.6 and strange waitpid() + // behavior + sigChldHandler.sa_handler = SigChldHandler; + sigChldHandler.sa_flags = SA_RESTART; + sigemptyset(&sigChldHandler.sa_mask); + sigaction(SIGCHLD, &sigChldHandler, NULL); +#endif /* !_WIN32 */ +} + +#if defined(linux) +#include +#endif +static int +setup_coredump() +{ +#if defined(linux) +#ifndef PR_SET_DUMPABLE +#define PR_SET_DUMPABLE 4 /* Ugly, but we cannot compile with 2.2.x otherwise. + Should be removed when we compile only on 2.4.x */ +#endif + prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); +#endif // linux check + return 0; +} + +static void +init_dirs(bool use_librecords = true) +{ + char buf[PATH_NAME_MAX + 1]; + + ink_strncpy(system_config_directory, Layout::get()->sysconfdir, PATH_NAME_MAX); + ink_strncpy(system_runtime_dir, Layout::get()->runtimedir, PATH_NAME_MAX); + ink_strncpy(system_log_dir, Layout::get()->logdir, PATH_NAME_MAX); + + if (access(system_config_directory, R_OK) == -1) { + if (use_librecords) { + REC_ReadConfigString(buf, "proxy.config.config_dir", PATH_NAME_MAX); + Layout::get()->relative(system_config_directory, PATH_NAME_MAX, buf); + } + if (access(system_config_directory, R_OK) == -1) { + mgmt_elog("unable to access() config dir '%s': %d, %s\n", + system_config_directory, errno, strerror(errno)); + mgmt_elog("please set config path via 'proxy.config.config_dir' \n"); + _exit(1); + } + } + strcpy(mgmt_path, system_config_directory); + + if (access(system_runtime_dir, W_OK) == -1) { + if (use_librecords) { + REC_ReadConfigString(buf, "proxy.config.local_state_dir", PATH_NAME_MAX); + Layout::get()->relative(system_runtime_dir, PATH_NAME_MAX, buf); + } + if (access(system_runtime_dir, R_OK) == -1) { + mgmt_elog("unable to access() local state dir '%s': %d, %s\n", + system_runtime_dir, errno, strerror(errno)); + mgmt_elog("please set 'proxy.config.local_state_dir'\n"); + _exit(1); + } + } + + if (access(system_log_dir, W_OK) == -1) { + if (use_librecords) { + REC_ReadConfigString(buf, "proxy.config.log.logfile_dir", PATH_NAME_MAX); + Layout::get()->relative(system_log_dir, PATH_NAME_MAX, buf); + } + if (access(system_log_dir, W_OK) == -1) { + mgmt_elog("unable to access() log dir'%s': %d, %s\n", + system_log_dir, errno, strerror(errno)); + mgmt_elog("please set 'proxy.config.log.logfile_dir'\n"); + _exit(1); + } + } + +} + +void +chdir_root() +{ + + if (system_root_dir[0] && (chdir(system_root_dir) < 0)) { + mgmt_elog("unable to change to root directory \"%s\" [%d '%s']\n", system_root_dir, errno, strerror(errno)); + mgmt_elog(" please set correct path in env variable TS_ROOT \n"); + exit(1); + } else { + mgmt_log("[TrafficManager] using root directory '%s'\n",system_root_dir); + } +} + + +static void +set_process_limits(int fds_throttle) +{ + struct rlimit lim; + + // Set needed rlimits (root) + ink_max_out_rlimit(RLIMIT_NOFILE, true, false); + ink_max_out_rlimit(RLIMIT_STACK, true, true); + ink_max_out_rlimit(RLIMIT_DATA, true, true); + ink_max_out_rlimit(RLIMIT_FSIZE, true, false); +#ifdef RLIMIT_RSS + ink_max_out_rlimit(RLIMIT_RSS, true, true); +#endif + + if (!getrlimit(RLIMIT_NOFILE, &lim)) { + if (fds_throttle > (int) (lim.rlim_cur + FD_THROTTLE_HEADROOM)) { + lim.rlim_cur = (lim.rlim_max = (rlim_t) fds_throttle); + if (!setrlimit(RLIMIT_NOFILE, &lim) && !getrlimit(RLIMIT_NOFILE, &lim)) { + fds_limit = (int) lim.rlim_cur; +#ifdef MGMT_USE_SYSLOG + syslog(LOG_NOTICE, "NOTE: RLIMIT_NOFILE(%d):cur(%d),max(%d)",RLIMIT_NOFILE, (int)lim.rlim_cur, (int)lim.rlim_max); +#endif + } + } + } + +} + +#if TS_HAS_WCCP +void +Errata_Logger(ts::Errata const& err) { + size_t n; + static size_t const SIZE = 4096; + char buff[SIZE]; + if (err.size()) { + ts::Errata::Code code = err.top().getCode(); + n = err.write(buff, SIZE, 1, 0, 2, "> "); + // strip trailing newlines. + while (n && (buff[n-1] == '\n' || buff[n-1] == '\r')) + buff[--n] = 0; + // log it. + if (code > 1) mgmt_elog("[WCCP]%s", buff); + else if (code > 0) mgmt_log("[WCCP]%s", buff); + else Debug("WCCP", "%s", buff); + } +} + +void +Init_Errata_Logging() { + ts::Errata::registerSink(&Errata_Logger); +} +#endif + +int +main(int argc, char **argv) +{ + // Before accessing file system initialize Layout engine + Layout::create(); + ink_strncpy(system_root_dir, Layout::get()->prefix, PATH_NAME_MAX); + ink_strncpy(mgmt_path, Layout::get()->sysconfdir, PATH_NAME_MAX); + + // change the directory to the "root" directory + chdir_root(); + + // Line buffer standard output & standard error + int status; + status = setvbuf(stdout, NULL, _IOLBF, 0); + if (status != 0) + perror("WARNING: can't line buffer stdout"); + status = setvbuf(stderr, NULL, _IOLBF, 0); + if (status != 0) + perror("WARNING: can't line buffer stderr"); + + bool found = false; + int just_started = 0; + int cluster_port = -1, cluster_server_port = -1; + // TODO: This seems completely incomplete, disabled for now + // int dump_config = 0, dump_process = 0, dump_node = 0, dump_cluster = 0, dump_local = 0; + int proxy_port = -1, proxy_backdoor = -1; + char *envVar = NULL, *group_addr = NULL, *tsArgs = NULL; + bool log_to_syslog = true; + char userToRunAs[80]; + int fds_throttle = -1; + time_t ticker; + ink_thread webThrId; + + + // Set up the application version info + appVersionInfo.setup(PACKAGE_NAME,"traffic_manager", PACKAGE_VERSION, + __DATE__, __TIME__, BUILD_MACHINE, BUILD_PERSON, ""); + initSignalHandlers(); + + // Process Environment Variables + if ((envVar = getenv("MGMT_ACONF_PORT")) != NULL) { + aconf_port_arg = atoi(envVar); + } + + if ((envVar = getenv("MGMT_CLUSTER_PORT")) != NULL) { + cluster_port = atoi(envVar); + } + + if ((envVar = getenv("MGMT_CLUSTER_RS_PORT")) != NULL) { + cluster_server_port = atoi(envVar); + } + + if ((envVar = getenv("MGMT_GROUP_ADDR")) != NULL) { + group_addr = envVar; + } + + for (int i = 1; i < argc; i++) { /* Process command line args */ + + if (argv[i][0] == '-') { + if ((strcmp(argv[i], "-version") == 0) || (strcmp(argv[i], "-V") == 0)) { + fprintf(stderr, "%s\n", appVersionInfo.FullVersionInfoStr); + exit(0); + } else if (strcmp(argv[i], "-proxyOff") == 0) { + proxy_on = false; + } else if (strcmp(argv[i], "-nosyslog") == 0) { + log_to_syslog = false; + } else { + // The rest of the options require an argument in the form of - + if ((i + 1) < argc) { + + if (strcmp(argv[i], "-aconfPort") == 0) { + ++i; + aconf_port_arg = atoi(argv[i]); + } else if (strcmp(argv[i], "-clusterPort") == 0) { + ++i; + cluster_port = atoi(argv[i]); + } else if (strcmp(argv[i], "-groupAddr") == 0) { + ++i; + group_addr = argv[i]; + } else if (strcmp(argv[i], "-clusterRSPort") == 0) { + ++i; + cluster_server_port = atoi(argv[i]); +#if TS_USE_DIAGS + } else if (strcmp(argv[i], "-debug") == 0) { + ++i; + strncpy(debug_tags, argv[i], 1023); + debug_tags[1023] = '\0'; + } else if (strcmp(argv[i], "-action") == 0) { + ++i; + strncpy(action_tags, argv[i], 1023); + action_tags[1023] = '\0'; +#endif + } else if (strcmp(argv[i], "-path") == 0) { + ++i; + //bugfixed by YTS Team, yamsat(id-59703) + if ((strlen(argv[i]) > PATH_NAME_MAX)) { + fprintf(stderr, "\n Path exceeded the maximum allowed characters.\n"); + exit(1); + } + + ink_strncpy(mgmt_path, argv[i], sizeof(mgmt_path)); + /* + } else if(strcmp(argv[i], "-lmConf") == 0) { + ++i; + lm_conf = argv[i]; + */ + } else if (strcmp(argv[i], "-recordsConf") == 0) { + ++i; + recs_conf = argv[i]; + // TODO: This seems completely incomplete, disabled for now +#if 0 + } else if (strcmp(argv[i], "-printRecords") == 0) { + ++i; + while (i < argc && argv[i][0] != '-') { + if (strcasecmp(argv[i], "config") == 0) { + dump_config = 1; + } else if (strcasecmp(argv[i], "process") == 0) { + dump_process = 1; + } else if (strcasecmp(argv[i], "node") == 0) { + dump_node = 1; + } else if (strcasecmp(argv[i], "cluster") == 0) { + dump_cluster = 1; + } else if (strcasecmp(argv[i], "local") == 0) { + dump_local = 1; + } else if (strcasecmp(argv[i], "all") == 0) { + dump_config = dump_node = dump_process = dump_cluster = dump_local = 1; + } + ++i; + } + --i; +#endif + } else if (strcmp(argv[i], "-tsArgs") == 0) { + int size_of_args = 0, j = (++i); + while (j < argc) { + size_of_args += 1; + size_of_args += strlen((argv[j++])); + } + ink_assert((tsArgs = (char *) xmalloc(size_of_args + 1))); + + j = 0; + while (i < argc) { + snprintf(&tsArgs[j], ((size_of_args + 1) - j), " %s", argv[i]); + j += strlen(argv[i]) + 1; + ++i; + } + } else if (strcmp(argv[i], "-proxyPort") == 0) { + ++i; + proxy_port = atoi(argv[i]); + } else if (strcmp(argv[i], "-proxyBackDoor") == 0) { + ++i; + proxy_backdoor = atoi(argv[i]); + } else if (strcmp(argv[i], "-vingid") == 0) { + // smanager/cnp integration, this argument is + // really just a dummy argument used so that + // smanager can find all instances of a + // particular TM process. + ++i; + } else if (strcmp(argv[i], "-schema") == 0) { + // hidden option + ++i; + schema_path = argv[i]; + schema_on = true; + } else { + printUsage(); + } + } else { + printUsage(); + } + } + } + } + + +#ifdef MGMT_USE_SYSLOG + // Bootstrap with LOG_DAEMON until we've read our configuration + if (log_to_syslog) { + openlog("traffic_manager", LOG_PID | LOG_NDELAY | LOG_NOWAIT, LOG_DAEMON); + mgmt_use_syslog(); + syslog(LOG_NOTICE, "NOTE: --- Manager Starting ---"); + syslog(LOG_NOTICE, "NOTE: Manager Version: %s", appVersionInfo.FullVersionInfoStr); + } +#endif /* MGMT_USE_SYSLOG */ + + // Bootstrap the Diags facility so that we can use it while starting + // up the manager + diagsConfig = NEW(new DiagsConfig(debug_tags, action_tags, false)); + diags = diagsConfig->diags; + diags->prefix_str = "Manager "; + + init_dirs(false);// setup directories + + // Get the config info we need while we are still root + extractConfigInfo(mgmt_path, recs_conf, userToRunAs, &fds_throttle); + + set_process_limits(fds_throttle); // as root + runAsUser(userToRunAs); + setup_coredump(); + check_lockfile(); + + url_init(); + mime_init(); + http_init(); + +#if defined(MGMT_API) + // initialize alarm queue + int ret; + + ret = init_mgmt_alarm_q(mgmt_alarm_event_q); + if (ret < 0) + mgmt_alarm_event_q = NULL; + +#endif + + RecLocalInit(); + LibRecordsConfigInit(); +#if TS_HAS_WCCP + Init_Errata_Logging(); +#endif + lmgmt = new LocalManager(mgmt_path, proxy_on); + RecLocalInitMessage(); + lmgmt->initAlarm(); + + if (diags) { + delete diagsConfig; + // diagsConfig->reconfigure_diags(); INKqa11968 + /* + delete diags; + diags = NEW (new Diags(debug_tags,action_tags)); + */ + } + // INKqa11968: need to set up callbacks and diags data structures + // using configuration in records.config + diagsConfig = NEW(new DiagsConfig(debug_tags, action_tags, true)); + diags = diagsConfig->diags; + RecSetDiags(diags); + diags->prefix_str = "Manager "; + + if (is_debug_tag_set("diags")) + diags->dump(); + diags->cleanup_func = mgmt_cleanup; + diags_init = 1; + + // Setup the exported manager version records. + RecSetRecordString("proxy.node.version.manager.short", appVersionInfo.VersionStr); + RecSetRecordString("proxy.node.version.manager.long", appVersionInfo.FullVersionInfoStr); + RecSetRecordString("proxy.node.version.manager.build_number", appVersionInfo.BldNumStr); + RecSetRecordString("proxy.node.version.manager.build_time", appVersionInfo.BldTimeStr); + RecSetRecordString("proxy.node.version.manager.build_date", appVersionInfo.BldDateStr); + RecSetRecordString("proxy.node.version.manager.build_machine", appVersionInfo.BldMachineStr); + RecSetRecordString("proxy.node.version.manager.build_person", appVersionInfo.BldPersonStr); +// RecSetRecordString("proxy.node.version.manager.build_compile_flags", +// appVersionInfo.BldCompileFlagsStr); + +#ifdef MGMT_USE_SYSLOG + if (log_to_syslog) { + char sys_var[] = "proxy.config.syslog_facility"; + char *facility_str = NULL; + int facility_int; + facility_str = REC_readString(sys_var, &found); + ink_assert(found); + + if (!found) { + mgmt_elog("Could not read %s. Defaulting to DAEMON\n", sys_var); + facility_int = LOG_DAEMON; + } else { + facility_int = facility_string_to_int(facility_str); + xfree(facility_str); + if (facility_int < 0) { + mgmt_elog("Bad syslog facility specified. Defaulting to DAEMON\n"); + facility_int = LOG_DAEMON; + } + } + + // NOTE: do NOT call closelog() here. Solaris gets confused + // and some how it hoses later calls to readdir_r. + openlog("traffic_manager", LOG_PID | LOG_NDELAY | LOG_NOWAIT, facility_int); + + lmgmt->syslog_facility = facility_int; + } else { + lmgmt->syslog_facility = -1; + } +#endif /* MGMT_USE_SYSLOG */ + + /**************************** + * Register Alarm Callbacks * + ****************************/ + lmgmt->alarm_keeper->registerCallback(overviewAlarmCallback); + + // Find out our hostname so we can use it as part of the initialization + setHostnameVar(); + + // Create the data structure for overview page + // Do this before the rest of the set up since it needs + // to created to handle any alarms thrown by later + // initialization + overviewGenerator = new overviewPage(); + + // Initialize the Config Object bindings before + // starting any other threads + configFiles = new FileManager(); + initializeRegistry(); + configFiles->registerCallback(fileUpdated); + + // RecLocal's 'sync_thr' depends on 'configFiles', so we can't + // stat the 'sync_thr' until 'configFiles' has been initialized. + RecLocalStart(); + + /* Update cmd line overrides/environmental overrides/etc */ + if (tsArgs) { /* Passed command line args for proxy */ + if (lmgmt->proxy_options) { + xfree(lmgmt->proxy_options); + } + lmgmt->proxy_options = tsArgs; + mgmt_log(stderr, "[main] Traffic Server Args: '%s'\n", lmgmt->proxy_options); + } + if (proxy_port != -1) { + lmgmt->proxy_server_port[0] = proxy_port; + mgmt_log(stderr, "[main] Traffic Server Port: '%d'\n", lmgmt->proxy_server_port[0]); + } + + if (proxy_backdoor != -1) { + RecSetRecordInt("proxy.config.process_manager.mgmt_port", proxy_backdoor); + } + + if (cluster_server_port == -1) { + cluster_server_port = REC_readInteger("proxy.config.cluster.rsport", &found); + ink_assert(found); + } + + if (cluster_port == -1) { + cluster_port = REC_readInteger("proxy.config.cluster.mcport", &found); + ink_assert(found); + } + + if (!group_addr) { + group_addr = REC_readString("proxy.config.cluster.mc_group_addr", &found); + ink_assert(found); + } + + if (schema_on) { + XMLDom schema; + schema.LoadFile(schema_path); + bool validate = validateRecordsConfig(&schema); + ink_release_assert(validate); + } + + + in_addr_t min_ip = inet_network("224.0.0.255"); + in_addr_t max_ip = inet_network("239.255.255.255"); + in_addr_t group_addr_ip = inet_network(group_addr); + + if (!(min_ip < group_addr_ip && group_addr_ip < max_ip)) { + mgmt_fatal("[TrafficManager] Multi-Cast group addr '%s' is not in the permitted range of %s\n", + group_addr, "224.0.1.0 - 239.255.255.255"); + } + + /* TODO: Do we really need to init cluster communication? */ + lmgmt->initCCom(cluster_port, group_addr, cluster_server_port); /* Setup cluster communication */ + + lmgmt->initMgmtProcessServer(); /* Setup p-to-p process server */ + + + // Now that we know our cluster ip address, add the + // UI record for this machine + overviewGenerator->addSelfRecord(); + webThrId = ink_thread_create(webIntr_main, NULL); /* Spin web agent thread */ + Debug("lm", "Created Web Agent thread (%d)", webThrId); + lmgmt->listenForProxy(); + + /* Check the permissions on vip_config */ + if (lmgmt->virt_map->enabled) { + char absolute_vipconf_binary[1024]; + struct stat buf; + + snprintf(absolute_vipconf_binary, sizeof(absolute_vipconf_binary), "%s/vip_config", lmgmt->bin_path); + if (stat(absolute_vipconf_binary, &buf) < 0) { + mgmt_elog(stderr, "[main] Unable to stat vip_config for proper permissions\n"); + } else if (!((buf.st_mode & S_ISUID) && + (buf.st_mode & S_IRWXU) && + (buf.st_mode & S_IRGRP) && + (buf.st_mode & S_IXGRP) && (buf.st_mode & S_IROTH) && (buf.st_mode & S_IXOTH))) { + lmgmt->alarm_keeper->signalAlarm(MGMT_ALARM_PROXY_SYSTEM_ERROR, + "Virtual IP Addressing enabled, but improper permissions on '/inktomi/bin/vip_config'" + "[requires: setuid root and at least a+rx]\n"); + } + } + + ticker = time(NULL); + mgmt_log("[TrafficManager] Setup complete\n"); + + statProcessor = NEW(new StatProcessor()); + + for (;;) { + lmgmt->processEventQueue(); + lmgmt->pollMgmtProcessServer(); + + // Check for a SIGHUP + if (sigHupNotifier != 0) { + mgmt_log(stderr, "[main] Reading Configuration Files due to SIGHUP\n"); + configFiles->rereadConfig(); + lmgmt->signalEvent(MGMT_EVENT_PLUGIN_CONFIG_UPDATE, "*"); + sigHupNotifier = 0; + mgmt_log(stderr, "[main] Reading Configuration Files Reread\n"); + } + // Check for SIGUSR2 + if (sigUsr2Notifier != 0) { + xdump(); + sigUsr2Notifier = 0; + } + + lmgmt->ccom->generateClusterDelta(); + + if (lmgmt->run_proxy && lmgmt->processRunning()) { + lmgmt->ccom->sendSharedData(); + lmgmt->virt_map->lt_runGambit(); + } else { + if (!lmgmt->run_proxy) { /* Down if we are not going to start another immed. */ + /* Proxy is not up, so no addrs should be */ + lmgmt->virt_map->downOurAddrs(); + } + + /* Proxy is not up, but we should still exchange config and alarm info */ + lmgmt->ccom->sendSharedData(false); + } + + lmgmt->ccom->checkPeers(&ticker); + overviewGenerator->checkForUpdates(); + + if (statProcessor) { + statProcessor->processStat(); + } + + if (lmgmt->mgmt_shutdown_outstanding == true) { + lmgmt->mgmtShutdown(0, true); + } + + if (lmgmt->run_proxy && !lmgmt->processRunning()) { /* Make sure we still have a proxy up */ + if (lmgmt->startProxy()) + just_started = 0; + else + just_started++; + } else { /* Give the proxy a chance to fire up */ + just_started++; + } + + /* This will catch the case were the proxy dies before it can connect to manager */ + if (lmgmt->proxy_launch_outstanding && !lmgmt->processRunning() && just_started >= 120) { + just_started = 0; + lmgmt->proxy_launch_outstanding = false; +#ifndef _WIN32 + if (lmgmt->proxy_launch_pid != -1) { + int res; + kill(lmgmt->proxy_launch_pid, 9); + waitpid(lmgmt->proxy_launch_pid, &res, 0); + if (WIFSIGNALED(res)) { + int sig = WTERMSIG(res); +#ifdef NEED_PSIGNAL + mgmt_log(stderr, "[main] Proxy terminated due to Sig %d\n", sig); +#else + mgmt_log(stderr, "[main] Proxy terminated due to Sig %d: %s\n", sig, strsignal(sig)); +#endif /* NEED_PSIGNAL */ + } + } +#else + if (lmgmt->proxy_launch_hproc != INVALID_HANDLE_VALUE) { + TerminateProcess(lmgmt->proxy_launch_hproc, 1); + } +#endif /* !_WIN32 */ + mgmt_log(stderr, "[main] Proxy launch failed, retrying...\n"); + } + + } + + if (statProcessor) { + delete(statProcessor); + } + +#ifndef MGMT_SERVICE + return 0; +#endif + +} /* End main */ + + +#ifndef _WIN32 +#if !defined(linux) && !defined(freebsd) && !defined(darwin) +void +SignalAlrmHandler(int sig, siginfo_t * t, void *c) +#else +void +SignalAlrmHandler(int sig) +#endif +{ + NOWARN_UNUSED(sig); + /* + fprintf(stderr,"[TrafficManager] ==> SIGALRM received\n"); + mgmt_elog(stderr,"[TrafficManager] ==> SIGALRM received\n"); + */ +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + if (t) { + if (t->si_code <= 0) { +#if defined(solaris) + fprintf(stderr, "[TrafficManager] ==> User Alarm from pid: %d uid: %d\n", (int)t->si_pid, t->si_uid); +#else + fprintf(stderr, "[TrafficManager] ==> User Alarm from pid: %d uid: %d\n", t->si_pid, t->si_uid); +#endif + mgmt_elog(stderr, "[TrafficManager] ==> User Alarm from pid: %d uid: %d\n", t->si_pid, t->si_uid); + } else { + fprintf(stderr, "[TrafficManager] ==> Kernel Alarm Reason: %d\n", t->si_code); + mgmt_elog(stderr, "[TrafficManager] ==> Kernel Alarm Reason: %d\n", t->si_code); + } + } +#endif + + return; +} + + +#if !defined(linux) && !defined(freebsd) && !defined(darwin) +void +SignalHandler(int sig, siginfo_t * t, void *c) +#else +void +SignalHandler(int sig) +#endif +{ + static int clean = 0; + int status; + +#if !defined(linux) && !defined(freebsd) && !defined(darwin) + if (t) { + if (t->si_code <= 0) { +#if defined(solaris) + fprintf(stderr, "[TrafficManager] ==> User Sig %d from pid: %d uid: %d\n", sig, (int)t->si_pid, t->si_uid); +#else + fprintf(stderr, "[TrafficManager] ==> User Sig %d from pid: %d uid: %d\n", sig, t->si_pid, t->si_uid); +#endif + mgmt_elog(stderr, "[TrafficManager] ==> User Sig %d from pid: %d uid: %d\n", sig, t->si_pid, t->si_uid); + } else { + fprintf(stderr, "[TrafficManager] ==> Kernel Sig %d; Reason: %d\n", sig, t->si_code); + mgmt_elog(stderr, "[TrafficManager] ==> Kernel Sig %d; Reason: %d\n", sig, t->si_code); + } + } +#endif + + + if (sig == SIGHUP) { + sigHupNotifier = 1; + return; + } + + if (sig == SIGUSR2) { + sigUsr2Notifier = 1; + return; + } + fprintf(stderr, "[TrafficManager] ==> Cleaning up and reissuing signal #%d\n", sig); + mgmt_elog(stderr, "[TrafficManager] ==> Cleaning up and reissuing signal #%d\n", sig); + + if (lmgmt && !clean) { + clean = 1; + if (lmgmt->watched_process_pid != -1) { + + if (sig == SIGTERM || sig == SIGINT) { + kill(lmgmt->watched_process_pid, sig); + waitpid(lmgmt->watched_process_pid, &status, 0); + } + } + lmgmt->mgmtCleanup(); + } + + switch (sig) { + case SIGQUIT: + case SIGILL: + case SIGTRAP: +#if !defined(linux) + case SIGEMT: + case SIGSYS: +#endif + case SIGFPE: + case SIGBUS: + case SIGSEGV: + case SIGXCPU: + case SIGXFSZ: + abort(); + default: + fprintf(stderr, "[TrafficManager] ==> signal #%d\n", sig); + mgmt_elog(stderr, "[TrafficManager] ==> signal #%d\n", sig); + _exit(sig); + } + fprintf(stderr, "[TrafficManager] ==> signal2 #%d\n", sig); + mgmt_elog(stderr, "[TrafficManager] ==> signal2 #%d\n", sig); + _exit(sig); +} /* End SignalHandler */ + + +// void SigChldHandler(int sig) +// +// An empty handler needed so that we catch SIGCHLD +// With Solaris 2.6, ignoring sig child changes the behavior +// of waitpid() so that if there are no unwaited children, +// waitpid() blocks until all child are transformed into +// zombies which is bad for us +// +void +SigChldHandler(int sig) +{ + NOWARN_UNUSED(sig); +} + +// void SigHupHandler(int sig,...) +// +// Records that a sigHup was sent so that we can reread our +// config files on the next run through the main loop +void +SigHupHandler(int sig, ...) +{ + ink_assert(sig == SIGHUP); + Debug("lm", "[SigHupHandler] hup caught\n"); + sigHupNotifier = 1; +} /* End SigHupHandler */ +#endif /* !_WIN32 */ + + +void +printUsage() +{ + fprintf(stderr, "----------------------------------------------------------------------------\n"); + fprintf(stderr, " Traffic Manager Usage: (all args are optional)\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " traffic_manager [options]\n"); + fprintf(stderr, " -proxyPort Port to have proxy listen on, overrides records.config.\n"); + /* Function is currently #ifdef'ed out so no reason to advertise + fprintf(stderr, + " -proxyBackdoor Port to put proxy mgmt port on.\n"); + */ + /* Commented out because this option is used for debugging only. + fprintf(stderr, + " -noProxy Do not launch the proxy process.\n"); + */ + fprintf(stderr, " -tsArgs [...] Args to proxy, everything till eol is passed.\n"); + fprintf(stderr, " -webPort Port for web interface.\n"); + /* + fprintf(stderr, + " -graphPort Port for dynamic graphs.\n"); + */ + fprintf(stderr, " -clusterPort Cluster Multicast port\n"); + fprintf(stderr, " -groupAddr Cluster Multicast group, example: \"225.0.0.37\".\n"); + fprintf(stderr, " -clusterRSPort Cluster Multicast port.\n"); + fprintf(stderr, " -path Root path for config files.\n"); + /* + fprintf(stderr, + " -lmConf Local Management config file.\n"); + */ + fprintf(stderr, " -recordsConf General config file.\n"); + // TODO: This seems completely incomplete, disabled for now + // fprintf(stderr, " -printRecords [...] Print flags, default all are off.\n"); + fprintf(stderr, " -debug Enable the given debug tags\n"); + fprintf(stderr, " -action Enable the given action tags.\n"); + fprintf(stderr, " -version or -V Print version id and exit.\n"); + fprintf(stderr, " -vingid Vingid Flag\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " [...] can be one+ of: [config process node cluster local all]\n"); + fprintf(stderr, "----------------------------------------------------------------------------\n"); + exit(0); +} /* End printUsage */ + +void +fileUpdated(char *fname) +{ + if (strcmp(fname, "cluster.config") == 0) { + lmgmt->signalFileChange("proxy.config.cluster.cluster_configuration"); + + } else if (strcmp(fname, "remap.config") == 0) { + lmgmt->signalFileChange("proxy.config.url_remap.filename"); + + } else if (strcmp(fname, "socks.config") == 0) { + lmgmt->signalFileChange("proxy.config.socks.socks_config_file"); + + } else if (strcmp(fname, "records.config") == 0) { + lmgmt->signalFileChange("records.config"); + + } else if (strcmp(fname, "cache.config") == 0) { + lmgmt->signalFileChange("proxy.config.cache.control.filename"); + + } else if (strcmp(fname, "parent.config") == 0) { + lmgmt->signalFileChange("proxy.config.http.parent_proxy.file"); + + } else if (strcmp(fname, "ip_allow.config") == 0) { + lmgmt->signalFileChange("proxy.config.cache.ip_allow.filename"); + } else if (strcmp(fname, "vaddrs.config") == 0) { + mgmt_log(stderr, "[fileUpdated] vaddrs.config updated\n"); + lmgmt->virt_map->lt_readAListFile(fname); + + } else if (strcmp(fname, "storage.config") == 0) { + mgmt_log(stderr, "[fileUpdated] storage.config changed, need restart auto-rebuild mode\n"); + + } else if (strcmp(fname, "proxy.pac") == 0) { + mgmt_log(stderr, "[fileUpdated] proxy.pac file has been modified\n"); + + } else if (strcmp(fname, "wpad.dat") == 0) { + mgmt_log(stderr, "[fileUpdated] wpad.dat file has been modified\n"); + + } else if (strcmp(fname, "icp.config") == 0) { + lmgmt->signalFileChange("proxy.config.icp.icp_configuration"); + + } else if (strcmp(fname, "update.config") == 0) { + lmgmt->signalFileChange("proxy.config.update.update_configuration"); + + } else if (strcmp(fname, "volume.config") == 0) { + mgmt_log(stderr, "[fileUpdated] volume.config changed, need restart\n"); + + } else if (strcmp(fname, "hosting.config") == 0) { + lmgmt->signalFileChange("proxy.config.cache.hosting_filename"); + + } else if (strcmp(fname, "mgr.cnf") == 0) { + mgmt_log(stderr, "[fileUpdated] mgr.cnf file has been modified\n"); + + } else if (strcmp(fname, "log_hosts.config") == 0) { + lmgmt->signalFileChange("proxy.config.log.hosts_config_file"); + + } else if (strcmp(fname, "logs_xml.config") == 0) { + lmgmt->signalFileChange("proxy.config.log.xml_config_file"); + + } else if (strcmp(fname, "splitdns.config") == 0) { + mgmt_log(stderr, "[fileUpdated] splitdns.config file has been modified\n"); + + } else if (strcmp(fname, "plugin.config") == 0) { + mgmt_log(stderr, "[fileUpdated] plugin.config file has been modified\n"); + + } else if (strcmp(fname, "ssl_multicert.config") == 0) { + mgmt_log(stderr, "[fileUpdated] ssl_multicert.config file has been modified\n"); + + } else if (strcmp(fname, "proxy.config.body_factory.template_sets_dir") == 0) { + lmgmt->signalFileChange("proxy.config.body_factory.template_sets_dir"); + + } else if (strcmp(fname, "stats.config.xml") == 0) { + if (statProcessor) { + statProcessor->rereadConfig(); + } + mgmt_log(stderr, "[fileUpdated] stats.config.xml file has been modified\n"); + } else if (strcmp(fname, "congestion.config") == 0) { + lmgmt->signalFileChange("proxy.config.http.congestion_control.filename"); + } else { + mgmt_elog(stderr, "[fileUpdated] Unknown config file updated '%s'\n", fname); + + } + return; +} /* End fileUpdate */ + +#if TS_USE_POSIX_CAP +/** Restore capabilities after user id change. + This manipulates LINUX capabilities so that this process + can perform certain privileged operations even if it is + no longer running as a privilege user. + + @internal + I tried using + @code + prctl(PR_SET_KEEPCAPS, 1); + @endcode + but that had no effect even though the call reported success. + Only explicit capability manipulation was effective. + + It does not appear to be necessary to set the capabilities on the + executable if originally run as root. That may be needed if + started as a user without that capability. + */ + +int +restoreCapabilities() { + int zret = 0; // return value. + cap_t cap_set = cap_get_proc(); // current capabilities + // Make a list of the capabilities we want turned on. + cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK }; + static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); + + cap_set_flag(cap_set, CAP_EFFECTIVE, CAP_COUNT, cap_list, CAP_SET); + zret = cap_set_proc(cap_set); + cap_free(cap_set); + return zret; +} +#endif + +// void runAsUser(...) +// +// If we are root, switched to user to run as +// specified in records.config +// +// If we are not root, do nothing +// +void +runAsUser(char *userName) +{ + uid_t uid, euid; + struct passwd *result; + const int bufSize = 1024; + char buf[bufSize]; + + uid = getuid(); + euid = geteuid(); + + if (uid == 0 || euid == 0) { + + /* Figure out what user we should run as */ + + Debug("lm", "[runAsUser] Attempting to run as user '%s'\n", userName); + + + if (userName == NULL || userName[0] == '\0') { + mgmt_elog(stderr, "[runAsUser] Fatal Error: proxy.config.admin.user_id is not set\n", userName, strerror(errno)); + _exit(1); + } + +// this is behaving weird. refer to getpwnam(3C) sparc -jcoates +// this looks like the POSIX getpwnam_r + + struct passwd passwdInfo; + struct passwd *ppasswd = NULL; + result = NULL; + int res; + if (*userName == '#') { + int uuid = atoi(userName + 1); + if (uuid == -1) + uuid = (int)uid; + res = getpwuid_r((uid_t)uuid, &passwdInfo, buf, bufSize, &ppasswd); + } + else { + res = getpwnam_r(&userName[0], &passwdInfo, buf, bufSize, &ppasswd); + } + + if (!res && ppasswd) { + result = ppasswd; + } + + if (result == NULL) { + mgmt_elog(stderr, "[runAsUser] Fatal Error: Unable to get info about user %s : %s\n", userName, strerror(errno)); + _exit(1); + } + + if (setegid(result->pw_gid) != 0 || seteuid(result->pw_uid) != 0) { + mgmt_elog(stderr, "[runAsUser] Fatal Error: Unable to switch to user %s : %s\n", userName, strerror(errno)); + _exit(1); + } + + uid = getuid(); + euid = geteuid(); + + + Debug("lm", "[runAsUser] Running with uid: '%d' euid: '%d'\n", uid, euid); + + if (uid != result->pw_uid && euid != result->pw_uid) { + mgmt_elog(stderr, "[runAsUser] Fatal Error: Failed to switch to user %s\n", userName); + _exit(1); + } + +#if TS_USE_POSIX_CAP + if (restoreCapabilities()) { + mgmt_elog(stderr, "[runAsUser] Error: Failed to restore capabilities after switch to user %s.\n", userName); + } +#endif + + } +} /* End runAsUser() */ + + +// void extractConfigInfo(...) +// +// We need to get certain records.config values while we are +// root. We can not use LMRecords to get them because the constructor +// for LMRecords creates the mgmt DBM and we do not want that to +// be owned as root. This function extracts that info from +// records.config +// +// +void +extractConfigInfo(char *mgmt_path, const char *recs_conf, char *userName, int *fds_throttle) +{ + char file[1024]; + bool useridFound = false; + bool throttleFound = false; + + /* Figure out what user we should run as */ + if (mgmt_path && recs_conf) { + FILE *fin; + snprintf(file, sizeof(file), "%s/%s.shadow", mgmt_path, recs_conf); + if (!(fin = fopen(file, "r"))) { + ink_filepath_make(file, sizeof(file), mgmt_path, recs_conf); + if (!(fin = fopen(file, "r"))) { + mgmt_elog(stderr, "[extractConfigInfo] Unable to open config file(%s)\n", file); + _exit(1); + } + } + // Get 'user id' and 'network connections throttle limit' + while (((!useridFound) || (!throttleFound)) && fgets(file, 1024, fin)) { + if (strstr(file, "CONFIG proxy.config.admin.user_id STRING")) { + //coverity[secure_coding] + if ((sscanf(file, "CONFIG proxy.config.admin.user_id STRING %1023s\n", userName) == 1) && + strcmp(userName, "NULL") != 0) { + useridFound = true; + } + } else if (strstr(file, "CONFIG proxy.config.net.connections_throttle INT")) { + if ((sscanf(file, "CONFIG proxy.config.net.connections_throttle INT %d\n", fds_throttle) == 1)) { + throttleFound = true; + } + } + + } + fclose(fin); + } else { + mgmt_elog(stderr, "[extractConfigInfo] Fatal Error: unable to access records file\n"); + _exit(1); + } + + if (useridFound == false) { + mgmt_elog(stderr, "[extractConfigInfo] Fatal Error: proxy.config.admin.user_id is not set\n"); + _exit(1); + } + +} /* End extractConfigInfo() */ diff --git a/mgmt/Main.h b/mgmt/Main.h new file mode 100644 index 00000000..ab5f506d --- /dev/null +++ b/mgmt/Main.h @@ -0,0 +1,63 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#include "FileManager.h" +#include "WebOverview.h" +#include "I_Version.h" + +#define PATH_NAME_MAX 511 // instead of PATH_MAX which is inconsistent + // on various OSs (linux-4096,osx/bsd-1024, + // windows-260,etc) +// TODO: consolidate location of these defaults +#define DEFAULT_ROOT_DIRECTORY PREFIX +#define DEFAULT_LOCAL_STATE_DIRECTORY "var/trafficserver" +#define DEFAULT_SYSTEM_CONFIG_DIRECTORY "etc/trafficserver" +#define DEFAULT_LOG_DIRECTORY "var/log/trafficserver" + +void MgmtShutdown(int status); +void fileUpdated(char *fname); +void runAsUser(char *userName); +void extractConfigInfo(char *mgmt_path, const char *recs_conf, char *userName, int *fds_throttle); +void printUsage(void); + +extern FileManager *configFiles; +extern overviewPage *overviewGenerator; +extern AppVersionInfo appVersionInfo; + +// Global strings +extern char mgmt_path[]; +extern const char *recs_conf; +//extern char *lm_conf; + +// Root of Traffic Server +extern const char *ts_base_dir; + +// Global variable to replace ifdef MGMT_LAUNCH_PROXY so that +// we can turn on/off proxy launch at runtime to facilitate +// manager only testing. +extern bool mgmt_launch_proxy; + +#endif /* _MAIN_H_ */ diff --git a/mgmt/Makefile.am b/mgmt/Makefile.am new file mode 100644 index 00000000..6d08a524 --- /dev/null +++ b/mgmt/Makefile.am @@ -0,0 +1,112 @@ +# +# Makefile.am for the Enterprise Management module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = cluster preparse tools utils web2 stats api cli +DIST_SUBDIRS = $(SUBDIRS) + +# This is for traffic_manager only (local manager) +AM_CPPFLAGS = $(ink_with_modules_local) \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/api/include \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/stats \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/mgmt/web2 \ + -I$(top_srcdir)/lib + +MGMT_DEFS = @MGMT_DEFS@ +DEFS += $(MGMT_DEFS) + +noinst_LIBRARIES = libmgmt_p.a + +bin_PROGRAMS = traffic_manager + +# Compile this for "process manager" +libmgmt_p_a_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/mgmt/api/include \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/mgmt/web2 \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/lib +libmgmt_p_a_SOURCES = \ + BaseManager.cc \ + BaseManager.h \ + MgmtDefs.h \ + ProcessManager.cc \ + ProcessManager.h \ + RecordsConfig.cc \ + RecordsConfig.h + +traffic_manager_SOURCES = \ + $(top_srcdir)/proxy/Error.cc \ + AddConfigFilesHere.cc \ + Alarms.cc \ + Alarms.h \ + BaseManager.cc \ + BaseManager.h \ + FileManager.cc \ + FileManager.h \ + LocalManager.cc \ + LocalManager.h \ + Main.cc \ + Main.h \ + MgmtDefs.h \ + MultiFile.cc \ + MultiFile.h \ + RecordsConfig.cc \ + RecordsConfig.h \ + Rollback.cc \ + Rollback.h + +traffic_manager_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @EXPAT_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +traffic_manager_LDADD = \ + cluster/libcluster.a \ + stats/libstats.a \ + web2/libweb.a \ + api/libmgmtapilocal.a \ + utils/libutils_lm.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/lib/records/libreclocal.a \ + $(top_builddir)/mgmt/tools/libinksysapi.a \ + $(top_builddir)/mgmt/tools/libinkconfigapi.a \ + $(top_builddir)/lib/ts/libtsutil.la \ + @LIBEXPAT@ @LIBPCRE@ \ + @LIBTCL@ @LIBICONV@ \ + -lm @LIBDL@ @LIBSOCKET@ @LIBNSL@ @LIBRESOLV@ \ + @LIBTHREAD@ @LIBRT@ @LIBEXECINFO@ @LIBCAP@ + +# Must do it this way or the dependencies aren't detected. +if BUILD_WCCP +traffic_manager_LDADD += \ + $(top_builddir)/lib/wccp/libwccp.a \ + $(top_builddir)/lib/tsconfig/libtsconfig.la +endif + +traffic_manager_LDADD += @LIBSSL@ + diff --git a/mgmt/Makefile.in b/mgmt/Makefile.in new file mode 100644 index 00000000..040728cb --- /dev/null +++ b/mgmt/Makefile.in @@ -0,0 +1,1062 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Makefile.am for the Enterprise Management module. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = traffic_manager$(EXEEXT) + +# Must do it this way or the dependencies aren't detected. +@BUILD_WCCP_TRUE@am__append_1 = \ +@BUILD_WCCP_TRUE@ $(top_builddir)/lib/wccp/libwccp.a \ +@BUILD_WCCP_TRUE@ $(top_builddir)/lib/tsconfig/libtsconfig.la + +subdir = mgmt +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libmgmt_p_a_AR = $(AR) $(ARFLAGS) +libmgmt_p_a_LIBADD = +am_libmgmt_p_a_OBJECTS = libmgmt_p_a-BaseManager.$(OBJEXT) \ + libmgmt_p_a-ProcessManager.$(OBJEXT) \ + libmgmt_p_a-RecordsConfig.$(OBJEXT) +libmgmt_p_a_OBJECTS = $(am_libmgmt_p_a_OBJECTS) +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_traffic_manager_OBJECTS = Error.$(OBJEXT) \ + AddConfigFilesHere.$(OBJEXT) Alarms.$(OBJEXT) \ + BaseManager.$(OBJEXT) FileManager.$(OBJEXT) \ + LocalManager.$(OBJEXT) Main.$(OBJEXT) MultiFile.$(OBJEXT) \ + RecordsConfig.$(OBJEXT) Rollback.$(OBJEXT) +traffic_manager_OBJECTS = $(am_traffic_manager_OBJECTS) +traffic_manager_DEPENDENCIES = cluster/libcluster.a stats/libstats.a \ + web2/libweb.a api/libmgmtapilocal.a utils/libutils_lm.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/lib/records/libreclocal.a \ + $(top_builddir)/mgmt/tools/libinksysapi.a \ + $(top_builddir)/mgmt/tools/libinkconfigapi.a \ + $(top_builddir)/lib/ts/libtsutil.la $(am__append_1) +traffic_manager_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(traffic_manager_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib/ts +depcomp = $(SHELL) $(top_srcdir)/build/aux/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libmgmt_p_a_SOURCES) $(traffic_manager_SOURCES) +DIST_SOURCES = $(libmgmt_p_a_SOURCES) $(traffic_manager_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ $(MGMT_DEFS) +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +SUBDIRS = cluster preparse tools utils web2 stats api cli +DIST_SUBDIRS = $(SUBDIRS) + +# This is for traffic_manager only (local manager) +AM_CPPFLAGS = $(ink_with_modules_local) \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/mgmt \ + -I$(top_srcdir)/mgmt/api/include \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/stats \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/mgmt/web2 \ + -I$(top_srcdir)/lib + +noinst_LIBRARIES = libmgmt_p.a + +# Compile this for "process manager" +libmgmt_p_a_CPPFLAGS = \ + $(iocore_include_dirs) \ + -I$(top_srcdir)/mgmt/api/include \ + -I$(top_srcdir)/mgmt/cluster \ + -I$(top_srcdir)/mgmt/preparse \ + -I$(top_srcdir)/mgmt/utils \ + -I$(top_srcdir)/mgmt/web2 \ + -I$(top_srcdir)/proxy \ + -I$(top_srcdir)/proxy/hdrs \ + -I$(top_srcdir)/lib/records \ + -I$(top_srcdir)/lib + +libmgmt_p_a_SOURCES = \ + BaseManager.cc \ + BaseManager.h \ + MgmtDefs.h \ + ProcessManager.cc \ + ProcessManager.h \ + RecordsConfig.cc \ + RecordsConfig.h + +traffic_manager_SOURCES = \ + $(top_srcdir)/proxy/Error.cc \ + AddConfigFilesHere.cc \ + Alarms.cc \ + Alarms.h \ + BaseManager.cc \ + BaseManager.h \ + FileManager.cc \ + FileManager.h \ + LocalManager.cc \ + LocalManager.h \ + Main.cc \ + Main.h \ + MgmtDefs.h \ + MultiFile.cc \ + MultiFile.h \ + RecordsConfig.cc \ + RecordsConfig.h \ + Rollback.cc \ + Rollback.h + +traffic_manager_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @EXPAT_LDFLAGS@ @LIBTOOL_LINK_FLAGS@ +traffic_manager_LDADD = cluster/libcluster.a stats/libstats.a \ + web2/libweb.a api/libmgmtapilocal.a utils/libutils_lm.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/lib/records/libreclocal.a \ + $(top_builddir)/mgmt/tools/libinksysapi.a \ + $(top_builddir)/mgmt/tools/libinkconfigapi.a \ + $(top_builddir)/lib/ts/libtsutil.la @LIBEXPAT@ @LIBPCRE@ \ + @LIBTCL@ @LIBICONV@ -lm @LIBDL@ @LIBSOCKET@ @LIBNSL@ \ + @LIBRESOLV@ @LIBTHREAD@ @LIBRT@ @LIBEXECINFO@ @LIBCAP@ \ + $(am__append_1) @LIBSSL@ +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .cc .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign mgmt/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign mgmt/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmgmt_p.a: $(libmgmt_p_a_OBJECTS) $(libmgmt_p_a_DEPENDENCIES) + -rm -f libmgmt_p.a + $(libmgmt_p_a_AR) libmgmt_p.a $(libmgmt_p_a_OBJECTS) $(libmgmt_p_a_LIBADD) + $(RANLIB) libmgmt_p.a +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +traffic_manager$(EXEEXT): $(traffic_manager_OBJECTS) $(traffic_manager_DEPENDENCIES) + @rm -f traffic_manager$(EXEEXT) + $(traffic_manager_LINK) $(traffic_manager_OBJECTS) $(traffic_manager_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AddConfigFilesHere.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Alarms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BaseManager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileManager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LocalManager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiFile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RecordsConfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Rollback.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmgmt_p_a-BaseManager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmgmt_p_a-ProcessManager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmgmt_p_a-RecordsConfig.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +libmgmt_p_a-BaseManager.o: BaseManager.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libmgmt_p_a-BaseManager.o -MD -MP -MF $(DEPDIR)/libmgmt_p_a-BaseManager.Tpo -c -o libmgmt_p_a-BaseManager.o `test -f 'BaseManager.cc' || echo '$(srcdir)/'`BaseManager.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libmgmt_p_a-BaseManager.Tpo $(DEPDIR)/libmgmt_p_a-BaseManager.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='BaseManager.cc' object='libmgmt_p_a-BaseManager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libmgmt_p_a-BaseManager.o `test -f 'BaseManager.cc' || echo '$(srcdir)/'`BaseManager.cc + +libmgmt_p_a-BaseManager.obj: BaseManager.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libmgmt_p_a-BaseManager.obj -MD -MP -MF $(DEPDIR)/libmgmt_p_a-BaseManager.Tpo -c -o libmgmt_p_a-BaseManager.obj `if test -f 'BaseManager.cc'; then $(CYGPATH_W) 'BaseManager.cc'; else $(CYGPATH_W) '$(srcdir)/BaseManager.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libmgmt_p_a-BaseManager.Tpo $(DEPDIR)/libmgmt_p_a-BaseManager.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='BaseManager.cc' object='libmgmt_p_a-BaseManager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libmgmt_p_a-BaseManager.obj `if test -f 'BaseManager.cc'; then $(CYGPATH_W) 'BaseManager.cc'; else $(CYGPATH_W) '$(srcdir)/BaseManager.cc'; fi` + +libmgmt_p_a-ProcessManager.o: ProcessManager.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libmgmt_p_a-ProcessManager.o -MD -MP -MF $(DEPDIR)/libmgmt_p_a-ProcessManager.Tpo -c -o libmgmt_p_a-ProcessManager.o `test -f 'ProcessManager.cc' || echo '$(srcdir)/'`ProcessManager.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libmgmt_p_a-ProcessManager.Tpo $(DEPDIR)/libmgmt_p_a-ProcessManager.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ProcessManager.cc' object='libmgmt_p_a-ProcessManager.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libmgmt_p_a-ProcessManager.o `test -f 'ProcessManager.cc' || echo '$(srcdir)/'`ProcessManager.cc + +libmgmt_p_a-ProcessManager.obj: ProcessManager.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libmgmt_p_a-ProcessManager.obj -MD -MP -MF $(DEPDIR)/libmgmt_p_a-ProcessManager.Tpo -c -o libmgmt_p_a-ProcessManager.obj `if test -f 'ProcessManager.cc'; then $(CYGPATH_W) 'ProcessManager.cc'; else $(CYGPATH_W) '$(srcdir)/ProcessManager.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libmgmt_p_a-ProcessManager.Tpo $(DEPDIR)/libmgmt_p_a-ProcessManager.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ProcessManager.cc' object='libmgmt_p_a-ProcessManager.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libmgmt_p_a-ProcessManager.obj `if test -f 'ProcessManager.cc'; then $(CYGPATH_W) 'ProcessManager.cc'; else $(CYGPATH_W) '$(srcdir)/ProcessManager.cc'; fi` + +libmgmt_p_a-RecordsConfig.o: RecordsConfig.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libmgmt_p_a-RecordsConfig.o -MD -MP -MF $(DEPDIR)/libmgmt_p_a-RecordsConfig.Tpo -c -o libmgmt_p_a-RecordsConfig.o `test -f 'RecordsConfig.cc' || echo '$(srcdir)/'`RecordsConfig.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libmgmt_p_a-RecordsConfig.Tpo $(DEPDIR)/libmgmt_p_a-RecordsConfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecordsConfig.cc' object='libmgmt_p_a-RecordsConfig.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libmgmt_p_a-RecordsConfig.o `test -f 'RecordsConfig.cc' || echo '$(srcdir)/'`RecordsConfig.cc + +libmgmt_p_a-RecordsConfig.obj: RecordsConfig.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libmgmt_p_a-RecordsConfig.obj -MD -MP -MF $(DEPDIR)/libmgmt_p_a-RecordsConfig.Tpo -c -o libmgmt_p_a-RecordsConfig.obj `if test -f 'RecordsConfig.cc'; then $(CYGPATH_W) 'RecordsConfig.cc'; else $(CYGPATH_W) '$(srcdir)/RecordsConfig.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/libmgmt_p_a-RecordsConfig.Tpo $(DEPDIR)/libmgmt_p_a-RecordsConfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='RecordsConfig.cc' object='libmgmt_p_a-RecordsConfig.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmgmt_p_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libmgmt_p_a-RecordsConfig.obj `if test -f 'RecordsConfig.cc'; then $(CYGPATH_W) 'RecordsConfig.cc'; else $(CYGPATH_W) '$(srcdir)/RecordsConfig.cc'; fi` + +Error.o: $(top_srcdir)/proxy/Error.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Error.o -MD -MP -MF $(DEPDIR)/Error.Tpo -c -o Error.o `test -f '$(top_srcdir)/proxy/Error.cc' || echo '$(srcdir)/'`$(top_srcdir)/proxy/Error.cc +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/Error.Tpo $(DEPDIR)/Error.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(top_srcdir)/proxy/Error.cc' object='Error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Error.o `test -f '$(top_srcdir)/proxy/Error.cc' || echo '$(srcdir)/'`$(top_srcdir)/proxy/Error.cc + +Error.obj: $(top_srcdir)/proxy/Error.cc +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT Error.obj -MD -MP -MF $(DEPDIR)/Error.Tpo -c -o Error.obj `if test -f '$(top_srcdir)/proxy/Error.cc'; then $(CYGPATH_W) '$(top_srcdir)/proxy/Error.cc'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/proxy/Error.cc'; fi` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/Error.Tpo $(DEPDIR)/Error.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$(top_srcdir)/proxy/Error.cc' object='Error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o Error.obj `if test -f '$(top_srcdir)/proxy/Error.cc'; then $(CYGPATH_W) '$(top_srcdir)/proxy/Error.cc'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/proxy/Error.cc'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-noinstLIBRARIES ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mgmt/MgmtDefs.h b/mgmt/MgmtDefs.h new file mode 100644 index 00000000..cc66dc5d --- /dev/null +++ b/mgmt/MgmtDefs.h @@ -0,0 +1,108 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + * + * MgmtDef.h + * Some mgmt definitions for relatively general use. + * + * $Date: 2006-03-08 19:40:20 $ + * + * + */ + +#ifndef _MGMT_DEF_H +#define _MGMT_DEF_H + +/* + * Type definitions. + */ +#include "ink_port.h" +#include "ink_hrtime.h" + +typedef int64_t MgmtIntCounter; +typedef int64_t MgmtInt; +typedef int8_t MgmtByte; +typedef float MgmtFloat; +typedef char *MgmtString; + +typedef enum +{ + INVALID = -1, + INK_INT = 0, + INK_FLOAT = 1, + INK_STRING = 2, + INK_COUNTER = 3, + INK_STAT_CONST = 4, // Added for the StatProcessor + INK_STAT_FX = 5, // Added for the StatProcessor + MAX_MGMT_TYPE = 6 +} MgmtType; + +/* + * MgmtCallback + * Management Callback functions. + */ +typedef void *(*MgmtCallback) (void *opaque_cb_data, char *data_raw, int data_len); + +#define MGMT_SEMID_DEFAULT 11452 +#define MGMT_DB_FILENAME "mgmt_db" +#define LM_CONNECTION_SERVER "process_server" + +/* Structs used in Average Statistics calculations */ +struct StatTwoIntSamples +{ + const char *lm_record_name; + ink_hrtime previous_time; + ink_hrtime current_time; + MgmtInt previous_value; + MgmtInt current_value; + + MgmtInt diff_value() + { + return (current_value - previous_value); + } + ink_hrtime diff_time() + { + return (current_time - previous_time); + } +}; + +struct StatTwoFloatSamples +{ + const char *lm_record_name; + ink_hrtime previous_time; + ink_hrtime current_time; + MgmtFloat previous_value; + MgmtFloat current_value; + + MgmtFloat diff_value() + { + return (current_value - previous_value); + } + ink_hrtime diff_time() + { + return (current_time - previous_time); + } +}; + +#endif /* _MGMT_DEF_H */ diff --git a/mgmt/MultiFile.cc b/mgmt/MultiFile.cc new file mode 100644 index 00000000..bf7b76af --- /dev/null +++ b/mgmt/MultiFile.cc @@ -0,0 +1,286 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_platform.h" +#include "ink_port.h" +#include "ink_assert.h" +#include "ink_resource.h" +#include "ink_error.h" +#include "ink_file.h" +#include "ink_string.h" +#include "ink_time.h" +#include "ink_unused.h" + +#include "Compatability.h" +#include "MgmtUtils.h" +#include "MultiFile.h" +#include "ExpandingArray.h" +#include "TextBuffer.h" +#include "WebMgmtUtils.h" + +/**************************************************************************** + * + * MultiFile.cc - base class to handle reading and displaying config + * files and directories + * + * + ****************************************************************************/ + +MultiFile::MultiFile() +{ + managedDir = NULL; + dirDescript = NULL; +} + +// void MultiFile::addTableEntries(ExpandingArray* fileList, textBuffer* output) +// +// Adds table entries to output from the result of WalkFiles +// +void +MultiFile::addTableEntries(ExpandingArray * fileList, textBuffer * output) +{ + int numFiles = fileList->getNumEntries(); + fileEntry *current; + char *safeName; + char dateBuf[64]; + const char dataOpen[] = "\t"; + const char dataClose[] = "\n"; + const int dataOpenLen = strlen(dataOpen); + const int dataCloseLen = strlen(dataClose); + + for (int i = 0; i < numFiles; i++) { + current = (fileEntry *) ((*fileList)[i]); + + output->copyFrom("\n", 5); + output->copyFrom(dataOpen, dataOpenLen); + safeName = substituteForHTMLChars(current->name); + output->copyFrom(safeName, strlen(safeName)); + delete[]safeName; + output->copyFrom(dataClose, dataCloseLen); + output->copyFrom(dataOpen, dataOpenLen); + + if (ink_ctime_r(¤t->c_time, dateBuf) == NULL) { + ink_strncpy(dateBuf, "No time-stamp", sizeof(dateBuf)); + } + output->copyFrom(dateBuf, strlen(dateBuf)); + output->copyFrom(dataClose, dataCloseLen); + output->copyFrom("\n", 6); + } + +} + +// Mfresult MultiFile::WalkFiles(ExpandingArray* fileList) +// +// Iterates through the managed directory and adds every managed file +// into the parameter snapList +// + +MFresult +MultiFile::WalkFiles(ExpandingArray * fileList) +{ +#ifndef _WIN32 + struct dirent *dirEntry; + DIR *dir; +#else + char *searchPattern; + WIN32_FIND_DATA W32FD; +#endif + char *fileName; + char *filePath; + char *records_config_filePath = NULL; + struct stat fileInfo; + struct stat records_config_fileInfo; + fileEntry *fileListEntry; + +#ifndef _WIN32 + if ((dir = opendir(managedDir)) == NULL) { + mgmt_log(stderr, "[MultiFile::WalkFiles] Unable to open %s directory: %s: %s\n", + dirDescript, managedDir, strerror(errno)); + return MF_NO_DIR; + } + // The fun of Solaris - readdir_r requires a buffer passed into it + // The man page says this obscene expression gives us the proper + // size + dirEntry = (struct dirent *) xmalloc(sizeof(struct dirent) + pathconf(".", _PC_NAME_MAX) + 1); + + struct dirent *result; + while (readdir_r(dir, dirEntry, &result) == 0) { + if (!result) + break; + fileName = dirEntry->d_name; + filePath = newPathString(managedDir, fileName); + records_config_filePath = newPathString(filePath, "records.config"); + if (stat(filePath, &fileInfo) < 0) { + mgmt_log(stderr, "[MultiFile::WalkFiles] Stat of a %s failed %s: %s\n", dirDescript, fileName, strerror(errno)); + } else { + if (stat(records_config_filePath, &records_config_fileInfo) < 0) { + delete[]filePath; + continue; + } + // Ignore ., .., and any dot files + if (*fileName != '.' && isManaged(fileName)) { + fileListEntry = (fileEntry *) xmalloc(sizeof(fileEntry)); + fileListEntry->c_time = fileInfo.st_ctime; + ink_strncpy(fileListEntry->name, fileName, sizeof(fileListEntry->name)); + fileList->addEntry(fileListEntry); + } + } + delete[]filePath; + } + + xfree(dirEntry); + closedir(dir); +#else + // Append '\*' as a wildcard for FindFirstFile() + searchPattern = newPathString(managedDir, "*"); + HANDLE hDInfo = FindFirstFile(searchPattern, &W32FD); + + if (INVALID_HANDLE_VALUE == hDInfo) { + mgmt_log(stderr, "[MultiFile::WalkFiles] FindFirstFile failed for %s: %s\n", searchPattern, ink_last_err()); + delete[]searchPattern; + return MF_NO_DIR; + } + delete[]searchPattern; + + while (FindNextFile(hDInfo, &W32FD)) { + fileName = W32FD.cFileName; + filePath = newPathString(managedDir, fileName); + if (stat(filePath, &fileInfo) < 0) { + mgmt_log(stderr, "[MultiFile::WalkFiles] Stat of a %s failed %s: %s\n", dirDescript, fileName, strerror(errno)); + } else { + // Ignore ., .., and any dot files + if (*fileName != '.' && isManaged(fileName)) { + fileListEntry = (fileEntry *) xmalloc(sizeof(fileEntry)); + fileListEntry->c_time = fileInfo.st_ctime; + strcpy(fileListEntry->name, fileName); + fileList->addEntry(fileListEntry); + } + } + delete[]filePath; + } + + FindClose(hDInfo); +#endif + + fileList->sortWithFunction(fileEntryCmpFunc); + delete[]records_config_filePath; + return MF_OK; +} + + +bool +MultiFile::isManaged(const char *fileName) +{ + if (fileName == NULL) { + return false; + } else { + return true; + } +} + +void +MultiFile::addSelectOptions(textBuffer * output, ExpandingArray * options) +{ + const char selectEnd[] = "\n"; + const char option[] = "\t
: + = + = -1 (default) | 0 (single node) | n (n+1 nodes) + = + = list of files, separated by , + = list of subdirectory, followed by filelists in each subdirectory. Subdirectories are separated by ; and file lists are separated by , + +behavior: Write the text IFC file according to the current install status. + + +read Read Update File + syntax: config:read path file + args: = + = + +behavior: Read the upgrade file and display it. For debugging purpose only. + +reset-stats Reset Statistics + syntax: config:reset-stats + args: none + behavior: Reset all statistics. + + ts# config:reset-stats + +OK + ts# + +http HTTP Configuration + (timeout values, headers, authorization) + syntax: config:http status + record: (proxy.config.http.cache.http) + + ts# config:http status on + ts# + + syntax: config:http + args: can be one of the following + keep-alive-timeout-in (proxy.config.http.keep_alive_no_activity_timeout_in) + keep-alive-timeout-out (proxy.config.http.keep_alive_no_activity_timeout_out) + inactive-timeout-in (proxy.config.http.transaction_no_activity_timeout_in) + inactive-timeout-out (proxy.config.http.transaction_no_activity_timeout_out) + active-timeout-in (proxy.config.http.transaction_active_timeout_in) + active-timeout-out (proxy.config.http.transaction_active_timeout_out) + + ts# config:http keep-alive-timeout-in 10 + ts# + + syntax: config:http + behavior: remove the specified header + args: (proxy.config.http.anonymize_remove_from) + (proxy.config.http.anonymize_remove_referer) + (proxy.config.http.anonymize_remove_user_agent) + (remove-cookie> (proxy.config.http.anonymize_remove_cookie) + + ts# config:http remove-from on + ts# + + syntax: config:http remove-header + behavior: remove headers specified in list of headers + args: (proxy.config.http.anonymize_other_header_list) + + ts# config:http remove-header "field1 field2" + ts# + + syntax: config:http + behavior: insert or remove client IP from header + args: (proxy.config.http.anonymize_insert_client_ip) + (proxy.config.http.anonymize_remove_client_ip) + + syntax: config:http proxy + behavior: enable http proxying in fwd/rev/fwd-rev modes + + ts# config:http proxy + fwd + ts# config:http proxy rev + ts# + + +ssl SSL Configuration + (on,off,port) + syntax: config:ssl status + record: (proxy.config.ssl.enabled) + + ts# config:ssl status on + ts# config:ssl status off + + syntax: config:ssl port + record: (proxy.config.ssl.server_port) + + ts# config:ssl port 1234 + ts# + + +icp ICP Configuration + (on/off, rules, port, timeouts) + syntax: config:icp mode + record: (proxy.config.icp.enabled value) + receive = 1, send-receive = 2, disabled = 0 + + ts# config:icp mode receive + ts# + + syntax: config:icp port + record: (proxy.config.icp.icp_port) + + ts# config:icp port 3130 + ts# + + syntax: config:icp multicast + record: (proxy.config.icp.multicast_enabled) + + ts# config:icp multicast on + ts# + + syntax: config:icp query-timeout + record: (proxy.config.icp.query_timeout) + + ts# config:icp query-timeout 2 + ts# + + syntax: config:icp peers + behavior: Retrieve icp.config file from URL. + + ts# config:icp peers http://example.com/icp.config + ts# + +cache Cache Configuration + (active protocols, bypass, storage, freshness, + expires, variable content, rules, clear) + syntax: config:cache + args: = + specifies the given protocol is cached + behavior: Enable/Disable caching of various protocols. + + ts# config:cache http on (proxy.config.http.cache.http) + +OK + ts# + + ts# config:cache http + on + ts# + + syntax: config:cache ignore-bypass + args: turn ignore-bypass on/off. + + ts# config:cache ignore-bypass on (proxy.config.http.cache.ignore_client_no_cache) + +OK + ts# + + ts# config:cache ignore-bypass + on + ts# + + syntax: config:cache max-object-size + args: if bytes=0 then there is no maximum + + ts# config:cache max-object-size 0 (proxy.config.cache.max_doc_size) + +OK + ts# + + ts# config:cache max-object-size + 0 + ts# + + syntax: config:cache max-alternates + args: if num=0 then there is no maximum + + ts# config:cache max-alternates 0 + +OK + ts# + + ts# config:cache max-alternates + 0 + ts# + + syntax: config:cache file [url] + args: [url] = location of remote cache.config file + behavior: Retrieve and install cache.config file from URL. + + ts# config:cache file http://example.com/cache.config + +OK + ts# + + syntax: config:cache freshness verify + records.config: proxy.config.http.cache.when_to_revalidate + args: when-expired = 0, no-date=1, always=2, never=3 + + ts# config:cache freshness verify when-expired + +OK + ts# + + syntax: config:cache freshness minimum + records.config: proxy.config.http.cache.required_headers + args: explicit = 2, last-modified = 1, nothing = 0 + + ts# config:cache freshness minimum explicit + +OK + ts# + + syntax: config:cache freshness no-expire-limit greater-than less-than + records.config: proxy.config.http.cache.heuristic_min_lifetime, heuristic_max_lifetime + args: is an integer + + ts# config:cache freshness no-expire-limit greater-than 900 less-than 7200 + +OK + ts# + + syntax: config:cache dynamic + records: proxy.config.http.cache.cache_urls_that_look_dynamic + + ts# config:cache dynamic on + +OK + ts# + + syntax: config:cache alternates + records: proxy.config.http.cache.enable_default_vary_headers + + ts# config:cache alternates on + +OK + ts# + + syntax: config:cache vary + records: proxy.config.http.cache.vary_default_(text,images,other) + args: is a string + + ts# config:cache vary text Cookie + +OK + ts# + + syntax: config:cache cookies + records: proxy.config.http.cache.cache_responses_to_cookies + args: none = 0, all = 1, images = 2, non-text = 3 + + ts# config:cache cookies none + +OK + ts# + + syntax: config:cache clear (clear cache and start traffic server) + args: none + + ts# config:cache clear + Traffic Server is running. + Clear Cache failed. + ts# config:cache clear + +OK + + +hostdb Host Database Configuration + syntax: config:hostdb lookup-timeout + records: proxy.config.hostdb.lookup_timeout + + ts# config:hostdb lookup-timeout 30 + +OK + ts# + + syntax: config:hostdb foreground-timeout + records: proxy.config.hostdb.timeout (seconds) + + ts# config:hostdb foreground-timeout 12 + +OK + ts# + + syntax: config:hostdb background-timeout + records: proxy.config.hostdb.verify_after 24 + + ts# config:hostdb background-timeout 24 + +OK + ts# + + syntax: config:hostdb invalid-host-timeout + records: proxy.config.hostdb.fail.timeout + + ts# config:hostdb invalid-host-timeout 30 + +OK + ts# + + syntax: config:hostdb re-dns-on-reload + records: proxy.config.hostdb.re_dns_on_reload + + ts# config:hostdb re-dns-on-reload on + +OK + ts# + + syntax: config:hostdb clear (clear hostdb and start traffic server) + args: none + + ts# config:hostdb clear + Traffic Server is running. + Clear HostDB failed. + + ts# config:hostdb clear + +OK + ts# + +dns DNS Configuration + syntax: config:dns resolve-timeout + records: proxy.config.dns.lookup_timeout + + ts# config:dns resolve-timeout 10 + +OK + ts# + + syntax: config:dns retries + records: proxy.config.dns.retries + + ts# config:dns retries 3 + +OK + ts# + +logging Logging Configuration + syntax: config:logging event + records: proxy.config.log.logging_enabled + + ts# config:logging event enabled + +OK + ts# + + ts# config:logging event + enabled + ts# + + syntax: config:logging mgmt-directory + records: proxy.config.log.logfile_dir + + ts# config:logging mgmt-directory /usr/local/var/log/trafficserver + +OK + ts# + + syntax: config:logging space-limit + args: = log space limit (MB) + records: proxy.config.log.max_space_mb_for_logs + + ts# config:logging space-limit 10 + +OK + ts# + + syntax: config:logging space-headroom + args: = log space headroom (MB) + records: proxy.config.log.max_space_mb_headroom + + ts# config:logging space-headroom 100 + +OK + ts# + + syntax: config:logging collation-status + args: inactive = 0, host = 1, send-standard = 2, send-custom = 3, send-all = 4 + records: proxy.local.log.collation_mode + + ts# config:logging collation-status inactive + +OK + ts# + + ts# config:log collation-status send-custom + +OK + ts# + + syntax: config:logging collation-host + args: is a remote collation host + records: proxy.config.log.collation_host + + ts# config:log collation-host config1 + +OK + ts# + + syntax: config:logging collation secret tagged orphan-limit + args: = string + = size in MB + records: = proxy.config.log.collation_port + tagged = proxy.config.log.collation_host_tagged + = proxy.config.log.collation_secret + + ts# config:logging collation secret foobar tagged on orphan-limit 10 + +OK + ts# + + syntax: config:logging format + type file header
+ + squid + args: = proxy.config.log.squid_log_enabled + type = proxy.config.log.squid_log_is_ascii + file = proxy.config.log.squid_log_name + header = proxy.config.log.squid_log_header + netscape-common + args: = proxy.config.log.common_log_enabled + type = proxy.config.log.common_log_is_ascii + file = proxy.config.log.common_log_name + header = proxy.config.log.common_log_header + netscape-ext + args: = proxy.config.log.extended_log_enabled + type = proxy.config.log.extended_log_is_ascii + file = proxy.config.log.extended_log_name + header = proxy.config.log.extended_log_header + netscape-ext2 + args: = proxy.config.log.extended2_log_enabled + type = proxy.config.log.extended2_log_is_ascii + file = proxy.config.log.extended2_log_name + header = proxy.config.log.extended2_log_header + + ts# config:log format squid on type ascii file squid.log + +OK + ts# + + syntax: config:logging splitting + records: proxy.config.log.separate_icp_logs + proxy.config.log.separate_host_logs + + ts# config:log split icp on + +OK + ts# + + syntax: config:logging custom format + records: proxy.config.log.custom_logs_enabled + + ts# config:logging custom on format xml + +OK + ts# + + syntax: config:logging rolling offset interval auto-delete + records: proxy.config.log.rolling_enabled + proxy.config.log.rolling_offset_hr (24hour format) + proxy.config.log.rolling_interval_sec (seconds) + + ts# config:logging rolling on offset 0 interval 1 auto-delete off + +OK + ts# + +ssl SSL Ports + +security Security Configuration + (TS IP allow, MGMT allow, Admin Access) + syntax: config:security ip-allow + + ts# config:security ip-allow http://example.com/ip_allow.config + ts# + + syntax: config:security admin + + ts# config:parent status on + ts# + + ts# config:parent name parent.example.com + ts# + + ts# config:parent rules http://example.com/parent.config + ts# + +remap Remap Rules + syntax: config:remap + args: = retrieve file and use as remap.config + + ts# config:remap http://example.com/remap.config + ts# + +ports Ports used by Traffic Server +*** config:ports command is not implemented or supported *** + (including mgmt port) + syntax: config:ports + args: some variables are single-port while other can be a list of ports + (proxy.config.http.server_port) single + (proxy.config.http.server_other_ports) list + (proxy.config.cluster_port) single + (proxy.config.cluster.rsport) single + (proxy.config.cluster.mcport) single + (proxy.config.http.connect_ports) list + (proxy.config.socks.socks_server_port) single + (proxy.config.icp.icp_port) single + +socks SOCKS Configuration + syntax: config:socks status version default-servers + accept accept-port + args: socks (proxy.config.socks_socks_needed) + version (proxy.config.socks.socks_version) + default-servers (proxy.config.socks.default_servers) + accept (proxy.config.socks.accept_enabled) + accept-port (proxy.config.socks.accept_port) + + ts# config:socks status on + ts# + ts# config:socks version 4 + ts# + ts# config:socks default-servers "s1.example.com:1080;socks2:4080" + ts# + ts# config:socks accept on + ts# + ts# config:socks accept-port 1080 + ts# + +port-tunnels Port Tunnelling Configuration + + syntax: config:port-tunnels server-other-ports + args: other-ports (proxy.config.http.server_other_ports) + + ts# config:port-tunnels + ts# NULL + ts# config:port-tunnels other-ports 5678 + ts# + + + + +scheduled-update Scheduled Update Configuration + syntax: config:scheduled-update status + retry-count + retry-interval + max-concurrent + force-immediate + rules + + args: config update.config file + behavior: Scheduled Update Configuration. + + ts> config:scheduled-update on + ts> + + ts> config:scheduled-update retry-count 10 + ts> + + ts> config:scheduled-update retry-interval 2 + + ts> config:scheduled-update force-immediate off + ts> + + ts> config:scheduled-update rules http://example.com + + ts> config:scheduled-update rules + update.config rules + ------------------- + (Display list of rules from update.config) + ts> + + +Appliance-Specific commands (Linux only) +======================================== + +Normal Mode +----------- + ping Send ICMP ECHO_REQUEST packets to host. + syntax: ping + args: hostname + + ts> ping foo + foo is alive + ts> + + traceroute Display the route packets take to host. + syntax: traceroute + args: hostname + + ts> traceroute foo + Traceroute output appears here... + ts> + +Configure Mode +-------------- + +config:network Make System Network configuration changes + + traffic_shell> config:network + + Command Syntax: + config:network hostname + config:network defaultrouter + config:network search-domain + config:network dns [a.a.a.a] [b.b.b.b] [c.c.c.c] + config:network int + config:network int down + config:network int up + + config:network int + config:network int + config:network int ip + config:network int netmask + config:network int gateway + + traffic_shell> + + hostname Specify appliance hostname + syntax: config:network hostname + ts# config:network hostname xxxx + ts# config:network hostname + xxxx + ts# + + defaultrouter Specify default router + syntax: config:network defaultrouter + + ts# config:network defaultrouter x.x.x.x + ts# config:network defaultrouter + x.x.x.x + ts# + + search-domain Specify DNS search domain + syntax: config:network search-domain + + ts# config:network search-domain example.com + ts# config:network search-domain + example.com + ts# + + dns Specify one or more DNS servers + syntax: config:network dns + + ts# config:network dns "192.168.0.2 192.168.0.3" + ts# config:network dns + 192.168.0.2 192.168.0.3 + ts# + + int Configure Network Interface Card + + config:network int + List network interface cards by name. + + config:network int + Display NIC configuration. + + config:network int down + Bring down the specified interface. + + config:network int up + + Bring up a NIC with the specified parameters. + + config:network int + Change the boot start status of a NIC that is already up. + + config:network int + Change the static/dhcp status of a NIC that is already up. + + config:network int ip + Change the IP address of a NIC that is already up. + + config:network int netmask + Change the netmask of a NIC that is already up. + + config:network int gateway + Change the gateway of a NIC that is already up. + + traffic_shell> config:network int + eth0 + eth1 + traffic_shell> config:network int eth0 + + NIC eth0 + Status -------------- up + Start on Boot ------- onboot + Start Protocol ------ none + IP Address ---------- 192.168.0.10 + Netmask ------------- 255.255.255.0 + Gateway ------------- default + + traffic_shell> + + + date Specify system date. + syntax: config:clock date + args: = mm/dd/yyyy + + ts# config:clock date 01/01/2001 + ts# config:clock date + 01/01/2001 + ts# + + time Specify system time. + syntax: config time " + "%d | %u.%u.%u.%u:%d | %d clients\n", + mux->id, mux->id, ip_ptr[0], ip_ptr[1], ip_ptr[2], ip_ptr[3], port, mux->num_clients); + resp_end_item(); + } + + resp_end(); + handle_callback(EVENT_NONE, NULL); + + return EVENT_DONE; +} + +int +MuxPagesHandler::handle_callback(int event, void *edata) +{ + MUTEX_TRY_LOCK(trylock, action.mutex, this_ethread()); + if (!trylock) { + SET_HANDLER(&MuxPagesHandler::handle_callback); + eventProcessor.schedule_in(this, HRTIME_MSECONDS(10)); + return EVENT_DONE; + } + + if (!action.cancelled) { + if (response) { + StatPageData data; + + data.data = response; + data.type = NULL; + data.length = response_length; + response = NULL; + + action.continuation->handleEvent(STAT_PAGE_SUCCESS, &data); + } else { + action.continuation->handleEvent(STAT_PAGE_FAILURE, NULL); + } + } + + delete this; + return EVENT_DONE; +} + +int32_t +MuxPagesHandler::extract_id(const char *query) +{ + char *p; + int32_t id; + + p = (char *) strstr(query, "id="); + if (!p) { + return -1; + } + p += sizeof("id=") - 1; + + id = ink_atoi(p); + + // Check to see if we found the id + if (id == 0) { + if (*p == '0' && *(p + 1) == '\0') { + return 0; + } else { + return -1; + } + } else { + return id; + } +} + +static Action * +mux_pages_callback(Continuation * cont, HTTPHdr * header) +{ + MuxPagesHandler *handler; + + handler = NEW(new MuxPagesHandler(cont, header)); + eventProcessor.schedule_imm(handler, ET_CALL); + + return &handler->action; +} + +void +mux_pages_init() +{ + statPagesManager.register_http("mux", mux_pages_callback); +} + +/************************************************************* + * + * REGRESSION TEST STUFF + * + **************************************************************/ + +class MUXTestDriver:public NetTestDriver +{ +public: + MUXTestDriver(); + ~MUXTestDriver(); + + void start_tests(RegressionTest * r_arg, int *pstatus_arg); + int main_handler(int event, void *data); + +private: + MuxAcceptor * regress_accept; + Action *pending_action; + + int i; + int completions_received; + RegressionTest *r; + int *pstatus; + + void start_next_test(); + void start_active_side(NetVConnection * p_vc); + void start_passive_side(NetVConnection * p_vc); +}; + +MUXTestDriver::MUXTestDriver(): +regress_accept(NULL), pending_action(NULL), i(0), completions_received(0), r(NULL), pstatus(NULL), NetTestDriver() +{ +} + +MUXTestDriver::~MUXTestDriver() +{ + mutex = NULL; + + if (regress_accept) { + delete regress_accept; + regress_accept = NULL; + } + + if (pending_action) { + pending_action->cancel(); + pending_action = NULL; + } +} + + +void +MUXTestDriver::start_tests(RegressionTest * r_arg, int *pstatus_arg) +{ + mutex = new_ProxyMutex(); + MUTEX_TRY_LOCK(lock, mutex, this_ethread()); + + r = r_arg; + pstatus = pstatus_arg; + + SET_HANDLER(&MUXTestDriver::main_handler); + + regress_accept = NEW(new MuxAcceptor); + regress_accept->init(9555, this); + + start_next_test(); +} + + +void +MUXTestDriver::start_next_test() +{ + + int next_index = i * 2; + if (next_index >= num_netvc_tests) { + // We are done - // FIX - PASS or FAIL? + if (errors == 0) { + *pstatus = REGRESSION_TEST_PASSED; + } else { + *pstatus = REGRESSION_TEST_FAILED; + } + return; + } + + Debug("mux_test", "Starting test %s", netvc_tests_def[next_index].test_name); + completions_received = 0; + + ink_debug_assert(pending_action == NULL); + Action *tmp = muxProcessor.get_mux_re(this, inet_addr("127.0.0.1"), 9555); + + if (tmp != ACTION_RESULT_DONE) { + pending_action = tmp; + } +} + +void +MUXTestDriver::start_active_side(NetVConnection * a_vc) +{ + int a_index = i * 2; + + NetVCTest *a = NEW(new NetVCTest); + a->init_test(NET_VC_TEST_ACTIVE, this, a_vc, r, &netvc_tests_def[a_index], "MuxVC", "mux_test_detail"); + a->start_test(); +} + +void +MUXTestDriver::start_passive_side(NetVConnection * p_vc) +{ + int p_index = (i * 2) + 1; + + NetVCTest *p = NEW(new NetVCTest); + p->init_test(NET_VC_TEST_PASSIVE, this, p_vc, r, &netvc_tests_def[p_index], "MuxVC", "mux_test_detail"); + p->start_test(); +} + + +int +MUXTestDriver::main_handler(int event, void *data) +{ + + Debug("mux_test_detail", "MUXTestDriver::main_handler recevied event %d", event); + + switch (event) { + case NET_EVENT_OPEN: + { + // We opened test mux vc so start testing + pending_action = NULL; + start_active_side((NetVConnection *) data); + break; + } + case NET_EVENT_OPEN_FAILED: + { + // Open of the test vc failed so give up + pending_action = NULL; + Warning("mux regression failed - could not open localhost muxvc"); + *pstatus = REGRESSION_TEST_FAILED; + delete this; + break; + } + case NET_EVENT_ACCEPT: + { + // New test client + start_passive_side((NetVConnection *) data); + break; + } + case EVENT_IMMEDIATE: + { + // Signifies a completion of one side of the test + completions_received++; + + if (completions_received == 2) { + i++; + start_next_test(); + } + break; + } + } + + return 0; +} + +REGRESSION_TEST(MUX) (RegressionTest * t, int atype, int *pstatus) { + MUXTestDriver *driver = NEW(new MUXTestDriver); + driver->start_tests(t, pstatus); +} diff --git a/proxy/MuxVC.h b/proxy/MuxVC.h new file mode 100644 index 00000000..2a3cbe0d --- /dev/null +++ b/proxy/MuxVC.h @@ -0,0 +1,382 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + MuxVC.h + + Description: + + + ****************************************************************************/ + +#ifndef _MUX_VC_H_ +#define _MUX_VC_H_ + +#include "Net.h" + +class MuxVC; +class MuxGetCont; +class MuxProcessor; +class MuxPagesHandler; + +#define MUX_EVENT_OPEN 2040 +#define MUX_EVENT_OPEN_FAILED 2041 + +enum +{ + MUX_VC_CLIENT_MAGIC_ALIVE = 0xdeffc0ff, + MUX_VC_CLIENT_MAGIC_DEAD = 0xdeadc0ff +}; + +enum +{ + INKMUX_PROTO_VERSION_UNKNOWN = 0, + INKMUX_PROTO_VERSION_0_1 = 1 +}; + +enum +{ + INKMUX_MSG_OPEN_CHANNEL = 1, + INKMUX_MSG_CLOSE_CHANNEL = 2, + INKMUX_MSG_SHUTDOWN_WRITE = 3, + INKMUX_MSG_NORMAL_DATA = 4, + INKMUX_MSG_OOB_DATA = 5, + INKMUX_MSG_CHANNEL_RESET = 6, + INKMUX_MSG_FLOW_CONTROL_START = 7, + INKMUX_MSG_FLOW_CONTROL_STOP = 8 +}; + + +#define MUX_OCLOSE_CHANNEL_EVENT 1 +#define MUX_OCLOSE_WRITE_EVENT (1 << 1) +#define MUX_OCLOSE_NEED_READ_NOTIFY (1 << 2) +#define MUX_OCLOSE_NEED_WRITE_NOTIFY (1 << 3) + +#define MUX_OCLOSE_INBOUND_MASK (MUX_OCLOSE_CHANNEL_EVENT | MUX_OCLOSE_WRITE_EVENT) +#define MUX_OCLOSE_OUTBOUND_MASK (MUX_OCLOSE_CHANNEL_EVENT) + +#define MUX_WRITE_SHUTDOWN 1 +#define MUX_WRITE_SHUTUDOWN_SEND_MSG (1 << 1) + +struct MuxMessage +{ + uint8_t version; + uint8_t msg_type; + uint16_t msg_len; + int32_t client_id; +}; + +struct MuxClientState +{ + MuxClientState(); + VIO vio; + int shutdown; + volatile int enabled; + int flow_stopped; // flow control flag +}; + +class MuxClientVC:public NetVConnection +{ + friend class MuxVC; + friend class MuxPagesHandler; +public: + MuxClientVC(); + ~MuxClientVC(); + + void init(MuxVC * mvc, int32_t id); + void kill(); + + virtual VIO *do_io_read(Continuation * c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer * buf = 0); + + virtual VIO *do_io_write(Continuation * c = NULL, int64_t nbytes = INT64_MAX, IOBufferReader * buf = 0, bool owner = false); + + virtual bool is_over_ssl() + { + return (false); + } + + virtual void do_io_close(int lerrno = -1); + virtual void do_io_shutdown(ShutdownHowTo_t howto); + + // Reenable a given vio. The public interface is through VIO::reenable + virtual void reenable(VIO * vio); + virtual void reenable_re(VIO * vio); + + virtual void boost(); + + // Timeouts + void set_active_timeout(ink_hrtime timeout_in); + void set_inactivity_timeout(ink_hrtime timeout_in); + void cancel_active_timeout(); + void cancel_inactivity_timeout(); + ink_hrtime get_active_timeout(); + ink_hrtime get_inactivity_timeout(); + + // Pure virutal functions we need to compile + SOCKET get_socket(); + const struct sockaddr_in &get_local_addr(); + const struct sockaddr_in &get_remote_addr(); + unsigned int get_local_ip(); + int get_local_port(); + unsigned int get_remote_ip(); + int get_remote_port(); + + int main_handler(int event, void *data); + + Link link; + int32_t id; + uint32_t magic; + +private: + + void setup_retry_event(int ms); + void update_inactive_timeout(); + void process_retry_event(); + void process_timeout(int event_to_send); + + void process_read_state(); + int process_byte_bank(); + int process_write(); + void process_channel_close_for_read(); + void process_channel_close_for_write(); + int send_write_shutdown_message(); + + bool closed; + uint32_t other_side_closed; + + int reentrancy_count; + bool need_boost; + + MuxVC *mux_vc; + + MuxClientState read_state; + MuxClientState write_state; + + // The byte bank is used for overflow bytes and is + // under control of the MuxVC's lock + MIOBuffer *read_byte_bank; + IOBufferReader *byte_bank_reader; + + ink_hrtime active_timeout; + ink_hrtime inactive_timeout; + + Event *active_event; + Event *inactive_event; + + // Retry event is used to retry when we can't both + // state machine's lock and the MuxVC's VC's lock + // It's protected under the user of the VC's lock + // (stored in the VIOs in the read & write state) + // + Event *retry_event; +}; + +enum +{ + MUX_VC_MAGIC_ALIVE = 0xdeffb0ff, + MUX_VC_MAGIC_DEAD = 0xdeadb0ff +}; + +enum MuxReadMsgState_t +{ + MUX_READ_MSG_HEADER, + MUX_READ_MSG_BODY +}; + +enum MuxConnectState +{ + MUX_NOT_CONNECTED = 0, + MUX_NET_CONNECT_ISSUED = 1, + MUX_WAIT_FOR_READY = 2, + MUX_CONNECTED_ACTIVE = 3, + MUX_CONNECT_FAILED = 4, + MUX_CONNECTION_DROPPED = 5, + MUX_CONNECTED_IDLE = 6, + MUX_CONNECTED_TEARDOWN = 7 +}; + +class MuxVC:public Continuation +{ + friend class MuxClientVC; + friend class MuxGetCont; + friend class MuxProcessor; + friend class MuxPagesHandler; +public: + MuxVC(); + ~MuxVC(); + + void init(); + void init_from_accept(NetVConnection * nvc, Continuation * acceptc); + void kill(); + + MuxClientVC *new_client(int32_t id = 0); + void remove_client(MuxClientVC * client_vc); + + int state_handle_mux(int event, void *data); + int state_handle_mux_down(int event, void *data); + int state_handle_connect(int event, void *data); + int state_wait_for_ready(int event, void *data); + int state_handle_kill(int event, void *data); + int state_idle(int event, void *data); + int state_remove_from_list(int event, void *data); + int state_teardown(int event, void *data); + + bool write_high_water(); + + // Establishes underlying TCP session + Action *do_connect(Continuation * c, unsigned int ip, int port); + + // Sets accept cont for muxed sessions + Action *set_mux_accept(Continuation * c); + + void process_clients(); + void setup_process_event(int ms); + unsigned int get_remote_ip(); + unsigned int get_remote_port(); + + bool on_list(MuxClientVC * c); // debugging function + + Link link; +private: + + void init_buffers(); + void init_io(); + + void setup_connect_check(); + int state_send_init_response(int event, void *data); + + void process_read_data(); + void process_read_msg_body(); + void reset_read_msg_state(); + + MuxClientVC *find_client(int32_t client_id); + void process_control_message(); + void process_channel_open(); + void process_channel_close(MuxClientVC * client); + void process_channel_inbound_shutdown(MuxClientVC * client); + int enqueue_control_message(int msg_id, int32_t cid, int data_size = 0); + void cleanup_on_error(); + int try_processor_list_remove(); + + uint32_t magic; + int32_t id; + int32_t reentrancy_count; + bool terminate_vc; + bool on_mux_list; + bool clients_notified_of_error; + Event *process_event; + + NetVConnection *net_vc; + VIO *read_vio; + VIO *write_vio; + + // Vars for preventing overflow on the outbound channel + uint64_t write_bytes_added; + bool writes_blocked; + + Action *net_connect_action; + Action return_connect_action; + MuxConnectState connect_state; + Event *retry_event; + + MIOBuffer *read_buffer; + MIOBuffer *write_buffer; + IOBufferReader *read_buffer_reader; + + MuxReadMsgState_t read_msg_state; + int read_msg_size; + int read_msg_ndone; + MuxMessage current_msg_hdr; + bool discard_read_data; + + Action return_accept_action; + + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + + int next_client_id; + int num_clients; + DLL active_clients; +}; + +class MuxAcceptor:public Continuation +{ +public: + MuxAcceptor(); + ~MuxAcceptor(); + void init(int port, Continuation * c); + int accept_handler(int event, void *data); +private: + Action * accept_action; + Continuation *call_cont; +}; + +class MuxGetCont:public Continuation +{ + friend class MuxGetAction; +public: + MuxGetCont(); + ~MuxGetCont(); + Action *init_for_new_mux(Continuation * c, unsigned int ip, int port); + Action *init_for_lock_miss(Continuation * c, unsigned int ip, int port); + int new_mux_handler(int event, void *data); + int lock_miss_handler(int event, void *data); +private: + Action return_action; + Action *mux_action; + MuxVC *mux_vc; + Event *retry_event; + unsigned int ip; + int port; +}; + +class HttpAccept; + +enum MuxFindResult_t +{ + MUX_FIND_FOUND, + MUX_FIND_NOT_FOUND, + MUX_FIND_RETRY +}; + +class MuxProcessor:public Processor +{ + friend class MuxGetCont; + friend class MuxVC; + friend class MuxPagesHandler; +public: + MuxProcessor(); + ~MuxProcessor(); + int start(); + Action *get_mux_re(Continuation * c, unsigned int ip, int port = 0); +private: + MuxFindResult_t find_mux_internal(Continuation * c, unsigned int ip, int port); + + Ptr list_mutex; + DLL mux_list; +}; + +extern MuxProcessor muxProcessor; + +#endif diff --git a/proxy/ParentSelection.cc b/proxy/ParentSelection.cc new file mode 100644 index 00000000..c1598e89 --- /dev/null +++ b/proxy/ParentSelection.cc @@ -0,0 +1,1335 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * ParentSelection.cc - Implementation of Parent Proxy routing + * + ****************************************************************************/ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +#include "libts.h" +#include "P_EventSystem.h" +#include "ParentSelection.h" +#include "ControlMatcher.h" +#include "Main.h" +#include "Error.h" +#include "ProxyConfig.h" +#include "HTTP.h" +#include "HttpTransact.h" + +#define PARENT_RegisterConfigUpdateFunc REC_RegisterConfigUpdateFunc +#define PARENT_ReadConfigInteger REC_ReadConfigInteger +#define PARENT_ReadConfigStringAlloc REC_ReadConfigStringAlloc + +typedef ControlMatcher P_table; + +// Global Vars for Parent Selection +static const char modulePrefix[] = "[ParentSelection]"; +static Ptr reconfig_mutex = NULL; + +// Config var names +static const char *file_var = "proxy.config.http.parent_proxy.file"; +static const char *default_var = "proxy.config.http.parent_proxies"; +static const char *retry_var = "proxy.config.http.parent_proxy.retry_time"; +static const char *enable_var = "proxy.config.http.parent_proxy_routing_enable"; +static const char *threshold_var = "proxy.config.http.parent_proxy.fail_threshold"; +static const char *dns_parent_only_var = "proxy.config.http.no_dns_just_forward_to_parent"; + +static const char *ParentResultStr[] = { + "Parent_Undefined", + "Parent_Direct", + "Parent_Specified", + "Parent_Failed" +}; + +static const char *ParentRRStr[] = { + "false", + "strict", + "true" +}; + +// +// Config Callback Prototypes +// +enum ParentCB_t +{ + PARENT_FILE_CB, PARENT_DEFAULT_CB, + PARENT_RETRY_CB, PARENT_ENABLE_CB, + PARENT_THRESHOLD_CB, PARENT_DNS_ONLY_CB +}; + +// If the parent was set by the external customer api, +// our HttpRequestData structure told us what parent to +// use and we are only called to preserve clean interface +// between HttpTransact & the parent selection code. The following +ParentRecord *const extApiRecord = (ParentRecord *) 0xeeeeffff; + +ParentConfigParams::ParentConfigParams() + : ParentTable(NULL), DefaultParent(NULL), ParentRetryTime(30), ParentEnable(0), FailThreshold(10), DNS_ParentOnly(0) +{ } + +ParentConfigParams::~ParentConfigParams() +{ + if (ParentTable) { + delete ParentTable; + } + + if (DefaultParent) { + delete DefaultParent; + } +} + +int ParentConfig::m_id = 0; + +// +// Begin API functions +// +void +ParentConfig::startup() +{ + reconfig_mutex = new_ProxyMutex(); + + // Load the initial configuration + reconfigure(); + + // Setup the callbacks for reconfiuration + // parent table + PARENT_RegisterConfigUpdateFunc(file_var, parentSelection_CB, (void *) PARENT_FILE_CB); + // default parent + PARENT_RegisterConfigUpdateFunc(default_var, parentSelection_CB, (void *) PARENT_DEFAULT_CB); + // Retry time + PARENT_RegisterConfigUpdateFunc(retry_var, parentSelection_CB, (void *) PARENT_RETRY_CB); + // Enable + PARENT_RegisterConfigUpdateFunc(enable_var, parentSelection_CB, (void *) PARENT_ENABLE_CB); + + // Fail Threshold + PARENT_RegisterConfigUpdateFunc(threshold_var, parentSelection_CB, (void *) PARENT_THRESHOLD_CB); + + // DNS Parent Only + PARENT_RegisterConfigUpdateFunc(dns_parent_only_var, parentSelection_CB, (void *) PARENT_DNS_ONLY_CB); +} + +void +ParentConfig::reconfigure() +{ + char *default_val = NULL; + int retry_time = 30; + int enable = 0; + int fail_threshold; + int dns_parent_only; + + ParentConfigParams *params; + params = NEW(new ParentConfigParams); + + // Allocate parent table + params->ParentTable = NEW(new P_table(file_var, modulePrefix, &http_dest_tags)); + + // Handle default parent + PARENT_ReadConfigStringAlloc(default_val, default_var); + params->DefaultParent = createDefaultParent(default_val); + if (default_val) { + xfree(default_val); + } + // Handle parent timeout + PARENT_ReadConfigInteger(retry_time, retry_var); + params->ParentRetryTime = retry_time; + + // Handle parent enable + PARENT_ReadConfigInteger(enable, enable_var); + params->ParentEnable = enable; + + // Handle the fail threshold + PARENT_ReadConfigInteger(fail_threshold, threshold_var); + params->FailThreshold = fail_threshold; + + // Handle dns parent only + PARENT_ReadConfigInteger(dns_parent_only, dns_parent_only_var); + params->DNS_ParentOnly = dns_parent_only; + + m_id = configProcessor.set(m_id, params); + + if (is_debug_tag_set("parent_config")) { + ParentConfig::print(); + } +} + +// void ParentConfig::print +// +// Debugging function +// +void +ParentConfig::print() +{ + ParentConfigParams *params = ParentConfig::acquire(); + + printf("Parent Selection Config\n"); + printf("\tEnabled %d\tRetryTime %d\tParent DNS Only %d\n", + params->ParentEnable, params->ParentRetryTime, params->DNS_ParentOnly); + if (params->DefaultParent == NULL) { + printf("\tNo Default Parent\n"); + } else { + printf("\tDefault Parent:\n"); + params->DefaultParent->Print(); + } + printf(" "); + params->ParentTable->Print(); + + ParentConfig::release(params); +} + +bool +ParentConfigParams::apiParentExists(HttpRequestData * rdata) +{ + return (rdata->api_info && rdata->api_info->parent_proxy_name != NULL && rdata->api_info->parent_proxy_port > 0); +} + +bool +ParentConfigParams::parentExists(HttpRequestData * rdata) +{ + ParentResult junk; + + findParent(rdata, &junk); + + if (junk.r == PARENT_SPECIFIED) { + return true; + } else { + return false; + } +} + +void +ParentConfigParams::findParent(HttpRequestData * rdata, ParentResult * result) +{ + P_table *tablePtr = ParentTable; + ParentRecord *defaultPtr = DefaultParent; + ParentRecord *rec; + + ink_assert(result->r == PARENT_UNDEFINED); + + // Check to see if we are enabled + if (ParentEnable == 0) { + result->r = PARENT_DIRECT; + return; + } + // Initialize the result structure + result->rec = NULL; + result->epoch = tablePtr; + result->line_number = 0xffffffff; + result->wrap_around = false; + // if this variabel is not set, we have problems: the code in + // FindParent relies on the value of start_parent and when it is not + // initialized, the code in FindParent can get into an infinite loop! + result->start_parent = 0; + result->last_parent = 0; + + // Check to see if the parent was set through the + // api + if (apiParentExists(rdata)) { + result->r = PARENT_SPECIFIED; + result->hostname = rdata->api_info->parent_proxy_name; + result->port = rdata->api_info->parent_proxy_port; + result->rec = extApiRecord; + result->epoch = NULL; + result->start_parent = 0; + result->last_parent = 0; + + Debug("parent_select", "Result for %s was API set parent %s:%d", rdata->get_host(), result->hostname, result->port); + } + + tablePtr->Match(rdata, result); + rec = result->rec; + + if (rec == NULL) { + // No parents were found + // + // If there is a default parent, use it + if (defaultPtr != NULL) { + rec = result->rec = defaultPtr; + } else { + result->r = PARENT_DIRECT; + Debug("cdn", "Returning PARENT_DIRECT (no parents were found)"); + return; + } + } + // Loop through the set of parents to see if any are + // available + Debug("cdn", "Calling FindParent from findParent"); + + // Bug INKqa08251: + // If a parent proxy is set by the API, + // no need to call FindParent() + if (rec != extApiRecord) + rec->FindParent(true, result, rdata, this); + + if (is_debug_tag_set("parent_select") || is_debug_tag_set("cdn")) { + switch (result->r) { + case PARENT_UNDEFINED: + Debug("cdn", "PARENT_UNDEFINED"); + break; + case PARENT_FAIL: + Debug("cdn", "PARENT_FAIL"); + break; + case PARENT_DIRECT: + Debug("cdn", "PARENT_DIRECT"); + break; + case PARENT_SPECIFIED: + Debug("cdn", "PARENT_SPECIFIED"); + break; + default: + // Handled here: + // PARENT_AGENT + break; + } + + const char *host = rdata->get_host(); + + switch (result->r) { + case PARENT_UNDEFINED: + case PARENT_FAIL: + case PARENT_DIRECT: + Debug("parent_select", "Result for %s was %s", host, ParentResultStr[result->r]); + break; + case PARENT_SPECIFIED: + Debug("parent_select", "sizeof ParentResult = %d", sizeof(ParentResult)); + Debug("parent_select", "Result for %s was parent %s:%d", host, result->hostname, result->port); + break; + default: + // Handled here: + // PARENT_AGENT + break; + } + } +} + + +void +ParentConfigParams::recordRetrySuccess(ParentResult * result) +{ + pRecord *pRec; + + // Make sure that we are being called back with with a + // result structure with a parent that is being retried + ink_release_assert(result->retry == true); + ink_assert(result->r == PARENT_SPECIFIED); + if (result->r != PARENT_SPECIFIED) { + return; + } + // If we were set through the API we currently have not failover + // so just return fail + if (result->rec == extApiRecord) { + ink_assert(0); + return; + } + + ink_assert((int) (result->last_parent) < result->rec->num_parents); + pRec = result->rec->parents + result->last_parent; + + ink_atomic_swap(&pRec->failedAt, 0); + int old_count = ink_atomic_swap(&pRec->failCount, 0); + + if (old_count > 0) { + Note("http parent proxy %s:%d restored", pRec->hostname, pRec->port); + } +} + +void +ParentConfigParams::markParentDown(ParentResult * result) +{ + time_t now; + pRecord *pRec; + int new_fail_count = 0; + + // Make sure that we are being called back with with a + // result structure with a parent + ink_assert(result->r == PARENT_SPECIFIED); + if (result->r != PARENT_SPECIFIED) { + return; + } + // If we were set through the API we currently have not failover + // so just return fail + if (result->rec == extApiRecord) { + return; + } + + ink_assert((int) (result->last_parent) < result->rec->num_parents); + pRec = result->rec->parents + result->last_parent; + + // If the parent has already been marked down, just increment + // the failure count. If this is the first mark down on a + // parent we need to both set the failure time and set + // count to one. It's possible for the count and time get out + // sync due there being no locks. Therefore the code should + // handle this condition. If this was the result of a retry, we + // must update move the failedAt timestamp to now so that we continue + // negative cache the parent + if (pRec->failedAt == 0 || result->retry == true) { + // Reread the current time. We want this to be accurate since + // it relates to how long the parent has been down. + now = time(NULL); + + // Mark the parent as down + ink_atomic_swap(&pRec->failedAt, now); + + // If this is clean mark down and not a failed retry, we + // must set the count to reflect this + if (result->retry == false) { + new_fail_count = pRec->failCount = 1; + } + + Debug("parent_select", "Parent %s marked as down %s:%d", (result->retry) ? "retry" : "initially", pRec->hostname, pRec->port); + + } else { + int old_count = ink_atomic_increment(&pRec->failCount, 1); + + Debug("parent_select", "Parent fail count increased to %d for %s:%d", old_count + 1, pRec->hostname, pRec->port); + new_fail_count = old_count + 1; + } + + if (new_fail_count > 0 && new_fail_count == FailThreshold) { + Note("http parent proxy %s:%d marked down", pRec->hostname, pRec->port); + } +} + +void +ParentConfigParams::nextParent(HttpRequestData * rdata, ParentResult * result) +{ + P_table *tablePtr = ParentTable; + + // Make sure that we are being called back with a + // result structure with a parent + ink_assert(result->r == PARENT_SPECIFIED); + if (result->r != PARENT_SPECIFIED) { + result->r = PARENT_FAIL; + return; + } + // If we were set through the API we currently have not failover + // so just return fail + if (result->rec == extApiRecord) { + Debug("parent_select", "Retry result for %s was %s", rdata->get_host(), ParentResultStr[result->r]); + result->r = PARENT_FAIL; + return; + } + // The epoch pointer is a legacy from the time when the tables + // would be swapped and deleted in the future. I'm using the + // pointer now to ensure that the ParentConfigParams structure + // is properly used. The table should never change out from + // under the a http transaction + ink_release_assert(tablePtr == result->epoch); + + // Find the next parent in the array + Debug("cdn", "Calling FindParent from nextParent"); + result->rec->FindParent(false, result, rdata, this); + + switch (result->r) { + case PARENT_UNDEFINED: + Debug("cdn", "PARENT_UNDEFINED"); + break; + case PARENT_FAIL: + Debug("cdn", "PARENT_FAIL"); + break; + case PARENT_DIRECT: + Debug("cdn", "PARENT_DIRECT"); + break; + case PARENT_SPECIFIED: + Debug("cdn", "PARENT_SPECIFIED"); + break; + default: + // Handled here: + // PARENT_AGENT + break; + } + + if (is_debug_tag_set("parent_select")) { + const char *host = rdata->get_host(); + + switch (result->r) { + case PARENT_UNDEFINED: + case PARENT_FAIL: + case PARENT_DIRECT: + Debug("parent_select", "Retry result for %s was %s", host, ParentResultStr[result->r]); + break; + case PARENT_SPECIFIED: + Debug("parent_select", "Retry result for %s was parent %s:%d", host, result->hostname, result->port); + break; + default: + // Handled here: + // PARENT_AGENT + break; + } + } +} + +// +// End API functions +// + +void +ParentRecord::FindParent(bool first_call, ParentResult * result, RD * rdata, ParentConfigParams * config) +{ + Debug("cdn", "Entering FindParent (the inner loop)"); + int cur_index = 0; + bool parentUp = false; + bool parentRetry = false; + bool bypass_ok = (go_direct == true && config->DNS_ParentOnly == 0); + + HttpRequestData *request_info = (HttpRequestData *) rdata; + + ink_assert(num_parents > 0 || go_direct == true); + + if (first_call == true) { + if (parents == NULL) { + // We should only get into this state if + // if we are supposed to go dirrect + ink_assert(go_direct == true); + goto NO_PARENTS; + } else if (round_robin == true) { + cur_index = ink_atomic_increment((int32_t *) & rr_next, 1); + cur_index = result->start_parent = cur_index % num_parents; + } else { + switch (round_robin) { + case P_STRICT_ROUND_ROBIN: + cur_index = ink_atomic_increment((int32_t *) & rr_next, 1); + cur_index = cur_index % num_parents; + break; + case P_HASH_ROUND_ROBIN: + // INKqa12817 - make sure to convert to host byte order + cur_index = ntohl(rdata->get_client_ip()) % num_parents; + break; + case P_NO_ROUND_ROBIN: + cur_index = result->start_parent = 0; + break; + default: + ink_release_assert(0); + } + } + } else { + // Move to next parent due to failure + cur_index = (result->last_parent + 1) % num_parents; + + // Check to see if we have wrapped around + if ((unsigned int) cur_index == result->start_parent) { + // We've wrapped around so bypass if we can + if (bypass_ok == true) { + goto NO_PARENTS; + } else { + // Bypass disabled so keep trying, ignoring whether we think + // a parent is down or not + FORCE_WRAP_AROUND: + result->wrap_around = true; + } + } + } + + // Loop through the array of parent seeing if any are up or + // should be retried + do { + // DNS ParentOnly inhibits bypassing the parent so always return that t + if ((parents[cur_index].failedAt == 0) || (parents[cur_index].failCount < config->FailThreshold)) { + Debug("parent_select", "config->FailThreshold = %d", config->FailThreshold); + Debug("parent_select", "Selecting a down parent due to little failCount" + "(faileAt: %u failCount: %d)", parents[cur_index].failedAt, parents[cur_index].failCount); + parentUp = true; + } else { + if ((result->wrap_around) || ((parents[cur_index].failedAt + config->ParentRetryTime) < request_info->xact_start)) { + Debug("parent_select", "Parent[%d].failedAt = %u, retry = %u,xact_start = %u but wrap = %d", cur_index, + parents[cur_index].failedAt, config->ParentRetryTime, request_info->xact_start, result->wrap_around); + // Reuse the parent + parentUp = true; + parentRetry = true; + Debug("parent_select", "Parent marked for retry %s:%d", parents[cur_index].hostname, parents[cur_index].port); + + } else { + parentUp = false; + } + } + + if (parentUp == true) { + result->r = PARENT_SPECIFIED; + result->hostname = parents[cur_index].hostname; + result->port = parents[cur_index].port; + result->last_parent = cur_index; + result->retry = parentRetry; + ink_assert(result->hostname != NULL); + ink_assert(result->port != 0); + Debug("parent_select", "Chosen parent = %s.%d", result->hostname, result->port); + return; + } + + cur_index = (cur_index + 1) % num_parents; + + } while ((unsigned int) cur_index != result->start_parent); + + // We can't bypass so retry, taking any parent that we can + if (bypass_ok == false) { + goto FORCE_WRAP_AROUND; + } + +NO_PARENTS: + + // Could not find a parent + if (this->go_direct == true) { + result->r = PARENT_DIRECT; + } else { + result->r = PARENT_FAIL; + } + + result->hostname = NULL; + result->port = 0; +} + +// const char* ParentRecord::ProcessParents(char* val) +// +// Reads in the value of a "round-robin" or "order" +// directive and parses out the individual parents +// allocates and builds the this->parents array +// +// Returns NULL on success and a static error string +// on failure +// +const char * +ParentRecord::ProcessParents(char *val) +{ + Tokenizer pTok(",; \t\r"); + int numTok; + const char *current; + int port; + char *tmp; + const char *errPtr; + + if (parents != NULL) { + return "Can not specify more than one set of parents"; + } + + numTok = pTok.Initialize(val, SHARE_TOKS); + + if (numTok == 0) { + return "No parents specified"; + } + // Allocate the parents array + this->parents = (pRecord *) xmalloc(sizeof(pRecord) * numTok); + + // Loop through the set of parents specified + // + for (int i = 0; i < numTok; i++) { + current = pTok[i]; + + // Find the parent port + tmp = (char *) strchr(current, ':'); + + if (tmp == NULL) { + errPtr = "No parent port specified"; + goto MERROR; + } + // Read the parent port + //coverity[secure_coding] + if (sscanf(tmp + 1, "%d", &port) != 1) { + errPtr = "Malformed parent port"; + goto MERROR; + } + // Make sure that is no garbage beyond the parent + // port + char *scan = tmp + 1; + for (; *scan != '\0' && ParseRules::is_digit(*scan); scan++); + for (; *scan != '\0' && ParseRules::is_wslfcr(*scan); scan++); + if (*scan != '\0') { + errPtr = "Garbage trailing entry or invalid separator"; + goto MERROR; + } + // Check to make sure that the string will fit in the + // pRecord + if (tmp - current > MAXDNAME) { + errPtr = "Parent hostname is too long"; + goto MERROR; + } else if (tmp - current == 0) { + errPtr = "Parent string is emtpy"; + goto MERROR; + } + // Update the pRecords + memcpy(this->parents[i].hostname, current, tmp - current); + this->parents[i].hostname[tmp - current] = '\0'; + this->parents[i].port = port; + this->parents[i].failedAt = 0; + this->parents[i].scheme = scheme; + } + + num_parents = numTok; + return NULL; + +MERROR: + if (parents != NULL) { + xfree(parents); + parents = NULL; + } + return errPtr; +} + +// bool ParentRecord::DefaultInit(char* val) +// +// Creates the record for a default parent proxy rule +/// established by a config variable +// +// matcher_line* line_info - contains the value of +// proxy.config.http.parent_proxies +// +// Returns true on success and false on failure +// +bool +ParentRecord::DefaultInit(char *val) +{ + const char *errPtr; + char *errBuf; + bool alarmAlready = false; + + this->go_direct = true; + this->round_robin = P_NO_ROUND_ROBIN; + this->scheme = NULL; + errPtr = ProcessParents(val); + + if (errPtr != NULL) { + errBuf = (char *) xmalloc(1024); + snprintf(errBuf, 1024, "%s %s for default parent proxy", modulePrefix, errPtr); + SignalError(errBuf, alarmAlready); + xfree(errBuf); + return false; + } else { + return true; + } +} + + +// char* ParentRecord::Init(matcher_line* line_info) +// +// matcher_line* line_info - contains parsed label/value +// pairs of the current cache.config line +// +// Returns NULL if everything is OK +// Otherwise, returns an error string that the caller MUST +// DEALLOCATE with free() +// +char * +ParentRecord::Init(matcher_line * line_info) +{ + const char *errPtr = NULL; + char *errBuf; + const int errBufLen = 1024; + const char *tmp; + char *label; + char *val; + bool used = false; + + this->line_num = line_info->line_num; + this->scheme = NULL; + + for (int i = 0; i < MATCHER_MAX_TOKENS; i++) { + used = false; + label = line_info->line[0][i]; + val = line_info->line[1][i]; + + if (label == NULL) { + continue; + } + + if (strcasecmp(label, "round_robin") == 0) { + if (strcasecmp(val, "true") == 0) { + round_robin = P_HASH_ROUND_ROBIN; + } else if (strcasecmp(val, "strict") == 0) { + round_robin = P_STRICT_ROUND_ROBIN; + } else if (strcasecmp(val, "false") == 0) { + round_robin = P_NO_ROUND_ROBIN; + } else { + round_robin = P_NO_ROUND_ROBIN; + errPtr = "invalid argument to round_robin directive"; + } + used = true; + } else if (strcasecmp(label, "parent") == 0) { + errPtr = ProcessParents(val); + used = true; + } else if (strcasecmp(label, "go_direct") == 0) { + if (strcasecmp(val, "false") == 0) { + go_direct = false; + } else if (strcasecmp(val, "true") != 0) { + errPtr = "invalid argument to go_direct directive"; + } else { + go_direct = true; + } + used = true; + } + // Report errors generated by ProcessParents(); + if (errPtr != NULL) { + errBuf = (char *) xmalloc(errBufLen * sizeof(char)); + snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num); + return errBuf; + } + + if (used == true) { + // Consume the label/value pair we used + line_info->line[0][i] = NULL; + line_info->num_el--; + } + } + + if (this->parents == NULL && go_direct == false) { + errBuf = (char *) xmalloc(errBufLen * sizeof(char)); + snprintf(errBuf, errBufLen, "%s No parent specified in parent.config at line %d", modulePrefix, line_num); + return errBuf; + } + // Process any modifiers to the directive, if they exist + if (line_info->num_el > 0) { + tmp = ProcessModifiers(line_info); + + if (tmp != NULL) { + errBuf = (char *) xmalloc(errBufLen * sizeof(char)); + snprintf(errBuf, errBufLen, "%s %s at line %d in parent.config", modulePrefix, tmp, line_num); + return errBuf; + } + // record SCHEME modifier if present. + // NULL if not present + this->scheme = this->getSchemeModText(); + if (this->scheme != NULL) { + // update parent entries' schemes + for (int j = 0; j < num_parents; j++) { + this->parents[j].scheme = this->scheme; + } + } + } + + return NULL; +} + +// void ParentRecord::UpdateMatch(ParentResult* result, RD* rdata); +// +// Updates the record ptr in result if the this element +// appears later in the file +// +void +ParentRecord::UpdateMatch(ParentResult * result, RD * rdata) +{ + if (this->CheckForMatch((HttpRequestData *) rdata, result->line_number) == true) { + result->rec = this; + result->line_number = this->line_num; + + Debug("parent_select", "Matched with 0x%x parent node from line %d", this, this->line_num); + } +} + +ParentRecord::~ParentRecord() +{ + xfree(parents); +} + +void +ParentRecord::Print() +{ + printf("\t\t"); + for (int i = 0; i < num_parents; i++) { + printf(" %s:%d ", parents[i].hostname, parents[i].port); + } + printf(" rr=%s direct=%s\n", ParentRRStr[round_robin], (go_direct == true) ? "true" : "false"); +} + + +// struct PA_UpdateContinuation +// +// Used to handle parent.conf or default parent updates after the +// manager signals a change +// +struct PA_UpdateContinuation: public Continuation +{ + int handle_event(int event, void *data) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + ParentConfig::reconfigure(); + delete this; + return EVENT_DONE; + + } + + PA_UpdateContinuation(ProxyMutex * m):Continuation(m) + { + SET_HANDLER(&PA_UpdateContinuation::handle_event); + } +}; + + +// ParentRecord* createDefaultParent(char* val) +// +// Atttemtps to allocate and init new ParentRecord +// for a default parent +// +// Returns a pointer to the new record on success +// and NULL on failure +// +ParentRecord * +createDefaultParent(char *val) +{ + ParentRecord *newRec; + + if (val == NULL || *val == '\0') { + return NULL; + } + + newRec = NEW(new ParentRecord); + if (newRec->DefaultInit(val) == true) { + return newRec; + } else { + delete newRec; + return NULL; + } +} + +// parentSelection_CB(const char *name, RecDataT data_type, +// RecData data, void *cookie)) +// +// Called by manager to notify of config changes +// +int +parentSelection_CB(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data_type); + NOWARN_UNUSED(data); + ParentCB_t type = (ParentCB_t) (long) cookie; + + switch (type) { + case PARENT_FILE_CB: + case PARENT_DEFAULT_CB: + case PARENT_RETRY_CB: + case PARENT_ENABLE_CB: + case PARENT_THRESHOLD_CB: + case PARENT_DNS_ONLY_CB: + eventProcessor.schedule_imm(NEW(new PA_UpdateContinuation(reconfig_mutex)), ET_CACHE); + break; + default: + ink_assert(0); + } + + return 0; +} + +// +//ParentConfig equivalent functions for SocksServerConfig +// + +int SocksServerConfig::m_id = 0; +static ProxyMutexPtr socks_server_reconfig_mutex = NULL; +void +SocksServerConfig::startup() +{ + socks_server_reconfig_mutex = new_ProxyMutex(); + + // Load the initial configuration + reconfigure(); + + /* Handle update functions later. Socks does not yet support config update */ +} + +static int +setup_socks_servers(ParentRecord * rec_arr, int len) +{ + /* This changes hostnames into ip addresses and sets go_direct to false */ + for (int j = 0; j < len; j++) { + rec_arr[j].go_direct = false; + + pRecord *pr = rec_arr[j].parents; + int n_parents = rec_arr[j].num_parents; + + for (int i = 0; i < n_parents; i++) { + uint32_t bad_ip = (uint32_t) - 1; + uint8_t *ip; + + ink_gethostbyname_r_data data; + struct hostent *ent = ink_gethostbyname_r(pr[i].hostname, &data); + + if (ent) { + ip = (uint8_t *) ent->h_addr_list[0]; + } else { + Warning("Could not resolve socks server name \"%s\". " "Please correct it", pr[i].hostname); + ip = (uint8_t *) & bad_ip; + } + snprintf(pr[i].hostname, MAXDNAME + 1, "%hhu.%hhu.%hhu.%hhu", ip[0], ip[1], ip[2], ip[3]); + } + } + + return 0; +} + + +void +SocksServerConfig::reconfigure() +{ + char *default_val = NULL; + int retry_time = 30; + int fail_threshold; + + ParentConfigParams *params; + params = NEW(new ParentConfigParams); + + // Allocate parent table + params->ParentTable = NEW(new P_table("proxy.config.socks.socks_config_file", "[Socks Server Selection]", + &socks_server_tags)); + + // Handle default parent + PARENT_ReadConfigStringAlloc(default_val, "proxy.config.socks.default_servers"); + params->DefaultParent = createDefaultParent(default_val); + if (default_val) { + xfree(default_val); + } + + if (params->DefaultParent) + setup_socks_servers(params->DefaultParent, 1); + if (params->ParentTable->ipMatch) + setup_socks_servers(params->ParentTable->ipMatch->data_array, params->ParentTable->ipMatch->array_len); + + // Handle parent timeout + PARENT_ReadConfigInteger(retry_time, "proxy.config.socks.server_retry_time"); + params->ParentRetryTime = retry_time; + + // Handle parent enable + // enable is always true for use. We will come here only if socks is enabled + params->ParentEnable = 1; + + // Handle the fail threshold + PARENT_ReadConfigInteger(fail_threshold, "proxy.config.socks.server_fail_threshold"); + params->FailThreshold = fail_threshold; + + // Handle dns parent only + //PARENT_ReadConfigInteger(dns_parent_only, dns_parent_only_var); + params->DNS_ParentOnly = 0; + + m_id = configProcessor.set(m_id, params); + + if (is_debug_tag_set("parent_config")) { + SocksServerConfig::print(); + } +} + +void +SocksServerConfig::print() +{ + ParentConfigParams *params = SocksServerConfig::acquire(); + + printf("Parent Selection Config for Socks Server\n"); + printf("\tEnabled %d\tRetryTime %d\tParent DNS Only %d\n", + params->ParentEnable, params->ParentRetryTime, params->DNS_ParentOnly); + if (params->DefaultParent == NULL) { + printf("\tNo Default Parent\n"); + } else { + printf("\tDefault Parent:\n"); + params->DefaultParent->Print(); + } + printf(" "); + params->ParentTable->Print(); + + SocksServerConfig::release(params); +} + +#define TEST_FAIL(str) { \ + printf("%d: %s\n", test_id,str);\ + err= REGRESSION_TEST_FAILED;\ +} + +void +request_to_data(HttpRequestData * req, ip_addr_t srcip, ip_addr_t dstip, const char *str) +{ + HTTPParser parser; + + req->src_ip = srcip; + req->dest_ip = dstip; + req->hdr = NEW(new HTTPHdr); + + http_parser_init(&parser); + + req->hdr->parse_req(&parser, &str, str + strlen(str), true); + + http_parser_clear(&parser); +} + + +#define IP(a,b,c,d) htonl((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +static int passes; +static int fails; + +// Parenting Tests +EXCLUSIVE_REGRESSION_TEST(PARENTSELECTION) (RegressionTest * t, int intensity_level, int *pstatus) +{ + NOWARN_UNUSED(t); + NOWARN_UNUSED(intensity_level); + // first, set everything up + *pstatus = REGRESSION_TEST_INPROGRESS; + ParentConfig config; + ParentConfigParams *params = new ParentConfigParams(); + params->FailThreshold = 1; + params->ParentRetryTime = 5; + passes = fails = 0; + config.startup(); + params->ParentEnable = true; + char tbl[2048]; +#define T(x) strncat(tbl,x, sizeof(tbl)); +#define REBUILD params->ParentTable = new P_table("", "ParentSelection Unit Test Table", &http_dest_tags, ALLOW_HOST_TABLE | ALLOW_REGEX_TABLE | ALLOW_IP_TABLE | DONT_BUILD_TABLE); params->ParentTable->BuildTableFromString(tbl); + HttpRequestData *request = NULL; + ParentResult *result = NULL; +#define REINIT delete request; delete result; request = new HttpRequestData(); result = new ParentResult(); if (!result || !request) { (void)printf("Allocation failed\n"); return; } +#define ST(x) printf ("*** TEST %d *** STARTING ***\n", x); +#define RE(x,y) if (x) { printf("*** TEST %d *** PASSED ***\n", y); passes ++; } else { printf("*** TEST %d *** FAILED *** FAILED *** FAILED ***\n", y); fails++; } +#define FP params->findParent(request, result); + + // Test 1 + tbl[0] = '\0'; + ST(1) + T("dest_domain=. parent=red:37412,orange:37412,yellow:37412 round_robin=strict\n") + REBUILD int c, red = 0, orange = 0, yellow = 0; + for (c = 0; c < 21; c++) { + REINIT br(request, "fruit_basket.net"); + FP red += verify(result, PARENT_SPECIFIED, "red", 37412); + orange += verify(result, PARENT_SPECIFIED, "orange", 37412); + yellow += verify(result, PARENT_SPECIFIED, "yellow", 37412); + } + RE(((red == 7) && (orange == 7) && (yellow == 7)), 1) + // Test 2 + ST(2) + tbl[0] = '\0'; + T("dest_domain=. parent=green:4325,blue:4325,indigo:4325,violet:4325 round_robin=false\n") + REBUILD int g = 0, b = 0, i = 0, v = 0; + for (c = 0; c < 17; c++) { + REINIT br(request, "fruit_basket.net"); + FP g += verify(result, PARENT_SPECIFIED, "green", 4325); + b += verify(result, PARENT_SPECIFIED, "blue", 4325); + i += verify(result, PARENT_SPECIFIED, "indigo", 4325); + v += verify(result, PARENT_SPECIFIED, "violet", 4325); + } + RE((((g == 17) && !b && !i && !v) || (!g && (b == 17) && !i && !v) || (!g && !b && (i == 17) && !v) || + (!g && !b && !i && (v == 17))), 2) + // Test 3 - 6 Parenting Table + tbl[0] = '\0'; + T("dest_ip=209.131.62.14 parent=cat:37,dog:24 round_robin=strict\n") /* L1 */ + T("dest_host=www.pilot.net parent=pilot_net:80\n") /* L2 */ + T("url_regex=snoopy parent=odie:80,garfield:80 round_robin=true\n") /* L3 */ + T("dest_domain=i.am parent=amy:80,katie:80,carissa:771 round_robin=false\n") /* L4 */ + T("dest_domain=microsoft.net time=03:00-22:10 parent=zoo.net:341\n") /* L5 */ + T("dest_domain=microsoft.net time=0:00-02:59 parent=zoo.net:347\n") /* L6 */ + T("dest_domain=microsoft.net time=22:11-23:59 parent=zoo.edu:111\n") /* L7 */ + T("dest_domain=imac.net port=819 parent=genie:80 round_robin=strict\n") /* L8 */ + T("dest_ip=172.34.61.211 port=3142 parent=orangina:80 go_direct=false\n") /* L9 */ + T("url_regex=miffy prefix=furry/rabbit parent=nintje:80 go_direct=false\n") /* L10 */ + T("url_regex=kitty suffix=tif parent=hello:80 round_robin=strict go_direct=false\n") /* L11 */ + T("url_regex=cyclops method=get parent=turkey:80\n") /* L12 */ + T("url_regex=cyclops method=post parent=club:80\n") /* L13 */ + T("url_regex=cyclops method=put parent=sandwich:80\n") /* L14 */ + T("url_regex=cyclops method=trace parent=mayo:80\n") /* L15 */ + T("dest_host=pluto scheme=HTTP parent=strategy:80\n") /* L16 */ + REBUILD + // Test 3 + ST(3) REINIT br(request, "numeric_host", IP(209, 131, 62, 14)); + FP RE(verify(result, PARENT_SPECIFIED, "cat", 37) + verify(result, PARENT_SPECIFIED, "dog", 24), 3) + // Test 4 + ST(4) REINIT br(request, "www.pilot.net"); + FP RE(verify(result, PARENT_SPECIFIED, "pilot_net", 80), 4) + // Test 5 + ST(5) REINIT br(request, "www.snoopy.net"); + const char *snoopy_dog = "http://www.snoopy.com/"; + request->hdr->url_set(snoopy_dog, strlen(snoopy_dog)); + FP RE(verify(result, PARENT_SPECIFIED, "odie", 80) + verify(result, PARENT_SPECIFIED, "garfield", 80), 5) + // Test 6 + ST(6) REINIT br(request, "a.rabbit.i.am"); + FP RE(verify(result, PARENT_SPECIFIED, "amy", 80) + + verify(result, PARENT_SPECIFIED, "katie", 80) + verify(result, PARENT_SPECIFIED, "carissa", 771), 6) + // Test 6+ BUGBUG needs to be fixed +// ST(7) REINIT +// br(request, "www.microsoft.net"); +// FP RE( verify(result,PARENT_SPECIFIED,"zoo.net",341) + +// verify(result,PARENT_SPECIFIED,"zoo.net",347) + +// verify(result,PARENT_SPECIFIED,"zoo.edu",111) ,7) + // Test 6++ BUGBUG needs to be fixed +// ST(7) REINIT +// br(request, "snow.imac.net:2020"); +// FP RE(verify(result,PARENT_DIRECT,0,0),7) + // Test 6+++ BUGBUG needs to be fixed +// ST(8) REINIT +// br(request, "snow.imac.net:819"); +// URL* u = new URL(); +// char* r = "http://snow.imac.net:819/"; +// u->create(0); +// u->parse(r,strlen(r)); +// u->port_set(819); +// request->hdr->url_set(u); +// ink_assert(request->hdr->url_get()->port_get() == 819); +// printf("url: %s\n",request->hdr->url_get()->string_get(0)); +// FP RE(verify(result,PARENT_SPECIFIED,"genie",80),8) + // Test 7 - N Parent Table + tbl[0] = '\0'; + T("dest_domain=rabbit.net parent=fuzzy:80,fluffy:80,furry:80,frisky:80 round_robin=strict go_direct=true\n") + REBUILD + // Test 7 + ST(7) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fuzzy", 80), 7) + params->markParentDown(result); + + // Test 8 + ST(8) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 8) + // Test 9 + ST(9) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "furry", 80), 9) + // Test 10 + ST(10) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "frisky", 80), 10) + // restart the loop + // Test 11 + ST(11) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 11) + // Test 12 + ST(12) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 12) + // Test 13 + ST(13) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "furry", 80), 13) + // Test 14 + ST(14) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "frisky", 80), 14) + params->markParentDown(result); + + // restart the loop + + // Test 15 + ST(15) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 15) + // Test 16 + ST(16) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 16) + // Test 17 + ST(17) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "furry", 80), 17) + // Test 18 + ST(18) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 18) + // restart the loop + // Test 19 + ST(19) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 19) + // Test 20 + ST(20) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 20) + // Test 21 + ST(21) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "furry", 80), 21) + params->markParentDown(result); + + // Test 22 - 31 + for (i = 0; i < 10; i++) { + ST(22 + i) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 22 + i) + } + + params->markParentDown(result); // now they're all down + + // Test 32 - 131 + for (i = 0; i < 100; i++) { + ST(32 + i) REINIT br(request, "i.am.rabbit.net"); + FP RE(verify(result, PARENT_DIRECT, 0, 0), 32 + i) + } + + // sleep(5); // parents should come back up; they don't + sleep(params->ParentRetryTime + 1); + + // Fix: The following tests failed because + // br() should set xact_start correctly instead of 0. + + // Test 132 - 631 + for (i = 0; i < 40; i++) { + ST(132 + i) REINIT br(request, "i.am.rabbit.net"); + FP sleep(1); + switch ((i + 1) % 4) { + case 0: + RE(verify(result, PARENT_SPECIFIED, "fuzzy", 80), 132 + i) break; + case 1: + RE(verify(result, PARENT_SPECIFIED, "fluffy", 80), 132 + i) break; + case 2: + RE(verify(result, PARENT_SPECIFIED, "furry", 80), 132 + i) break; + case 3: + RE(verify(result, PARENT_SPECIFIED, "frisky", 80), 132 + i) break; + default: + ink_assert(0); + } + } + delete request; + delete result; + + printf("Tests Passed: %d\nTests Failed: %d\n", passes, fails); + *pstatus = (!fails ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED); +} + +// verify returns 1 iff the test passes +int +verify(ParentResult * r, ParentResultType e, const char *h, int p) +{ + if (is_debug_tag_set("parent_select")) + show_result(r); + return (r->r != e) ? 0 : ((e != PARENT_SPECIFIED) ? 1 : (strcmp(r->hostname, h) ? 0 : ((r->port == p) ? 1 : 0))); +} + +// br creates an HttpRequestData object +void +br(HttpRequestData * h, const char *os_hostname, int dest_ip) +{ + int hostname_len = strlen(os_hostname) + 1; + + h->hdr = new HTTPHdr(); + h->hdr->create(HTTP_TYPE_REQUEST); + h->hostname_str = (char *) malloc(hostname_len); + ink_strncpy(h->hostname_str, os_hostname, hostname_len); + h->xact_start = time(NULL); + h->src_ip = 0; + h->dest_ip = dest_ip; + h->incoming_port = 80; + h->api_info = new _HttpApiInfo(); +} + +// show_result prints out the ParentResult information +void +show_result(ParentResult * p) +{ + switch (p->r) { + case PARENT_UNDEFINED: + printf("result is PARENT_UNDEFINED\n"); + break; + case PARENT_DIRECT: + printf("result is PARENT_DIRECT\n"); + break; + case PARENT_SPECIFIED: + printf("result is PARENT_SPECIFIED\n"); + printf("hostname is %s\n", p->hostname); + printf("port is %d\n", p->port); + break; + case PARENT_FAIL: + printf("result is PARENT_FAIL\n"); + break; + default: + // Handled here: + // PARENT_AGENT + break; + } +} diff --git a/proxy/ParentSelection.h b/proxy/ParentSelection.h new file mode 100644 index 00000000..a3c7e832 --- /dev/null +++ b/proxy/ParentSelection.h @@ -0,0 +1,240 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * ParentSelection.h - Interface to Parent Selection System + * + * + ****************************************************************************/ + +#ifndef _PARENT_SELECTION_H_ +#define _PARENT_SELECTION_H_ + +#include "Main.h" +#include "ProxyConfig.h" +#include "ControlBase.h" +#include "ControlMatcher.h" + +#include "ink_apidefs.h" + +#include "P_RecProcess.h" + +struct RequestData; +typedef RequestData RD; + +struct matcher_line; +struct ParentResult; +class ParentRecord; + +enum ParentResultType +{ + PARENT_UNDEFINED, PARENT_DIRECT, + PARENT_SPECIFIED, PARENT_AGENT, PARENT_FAIL +}; + +typedef ControlMatcher P_table; + +// +// API to outside world +// +struct ParentResult +{ + ParentResult() + : r(PARENT_UNDEFINED), hostname(NULL), port(0), line_number(0), epoch(NULL), rec(NULL), + last_parent(0), start_parent(0), wrap_around(false), retry(false) + { }; + + // For outside consumption + ParentResultType r; + const char *hostname; + int port; + + // Internal use only + // Not to be modified by HTTP + int line_number; + P_table *epoch; // A pointer to the table used. + ParentRecord *rec; + uint32_t last_parent; + uint32_t start_parent; + bool wrap_around; + bool retry; +}; + +class HttpRequestData; + +struct ParentConfigParams:public ConfigInfo +{ + ParentConfigParams(); + ~ParentConfigParams(); + + // void findParent(RD* rdata, ParentResult* result) + // + // Does initial parent lookup + // + inkcoreapi void findParent(HttpRequestData *rdata, ParentResult *result); + + // void markParentDown(ParentResult* rsult) + // + // Marks the parent pointed to by result as down + // + inkcoreapi void markParentDown(ParentResult *result); + + // void recordRetrySuccess + // + // After a successful retry, http calls this function + // to clear the bits indicating the parent is down + // + void recordRetrySuccess(ParentResult *result); + + // void nextParent(RD* rdata, ParentResult* result); + // + // Marks the parent pointed to by result as down and attempts + // to find the next parent + // + inkcoreapi void nextParent(HttpRequestData *rdata, ParentResult *result); + + // bool parentExists(HttpRequestData* rdata) + // + // Returns true if there is a parent matching the request data and + // false otherwise + bool parentExists(HttpRequestData *rdata); + + // bool apiParentExists(HttpRequestData* rdata) + // + // Retures true if a parent has been set through the api + bool apiParentExists(HttpRequestData *rdata); + + P_table *ParentTable; + ParentRecord *DefaultParent; + int32_t ParentRetryTime; + int32_t ParentEnable; + int32_t FailThreshold; + int32_t DNS_ParentOnly; +}; + +struct ParentConfig +{ +public: + static void startup(); + static void reconfigure(); + static void print(); + + inkcoreapi static ParentConfigParams *acquire() { return (ParentConfigParams *) configProcessor.get(ParentConfig::m_id); } + inkcoreapi static void release(ParentConfigParams *params) { configProcessor.release(ParentConfig::m_id, params); } + + + static int m_id; +}; +// +// End API to outside world +// + + +// struct pRecord +// +// A record for an invidual parent +// +struct pRecord +{ + char hostname[MAXDNAME + 1]; + int port; + int32_t failedAt; + int failCount; + int32_t upAt; + const char *scheme; // for which parent matches (if any) +}; + +enum ParentRR_t +{ + P_NO_ROUND_ROBIN = 0, + P_STRICT_ROUND_ROBIN, + P_HASH_ROUND_ROBIN +}; + +// class ParentRecord : public ControlBase +// +// A record for a configuration line in the parent.config +// file +// +class ParentRecord: public ControlBase +{ +public: + ParentRecord() + : parents(NULL), num_parents(0), round_robin(P_NO_ROUND_ROBIN), rr_next(0), go_direct(true) + { } + + ~ParentRecord(); + + char *Init(matcher_line *line_info); + bool DefaultInit(char *val); + void UpdateMatch(ParentResult *result, RD *rdata); + void FindParent(bool firstCall, ParentResult *result, RD *rdata, ParentConfigParams *config); + void Print(); + pRecord *parents; + int num_parents; + + bool bypass_ok() const { return go_direct; } + + const char *scheme; + //private: + const char *ProcessParents(char *val); + ParentRR_t round_robin; + volatile uint32_t rr_next; + bool go_direct; +}; + +// Helper Functions +ParentRecord *createDefaultParent(char *val); +void reloadDefaultParent(char *val); +void reloadParentFile(); +int parentSelection_CB(const char *name, RecDataT data_type, RecData data, void *cookie); + +// Unit Test Functions +void show_result(ParentResult *aParentResult); +void br(HttpRequestData *h, const char *os_hostname, int dest_ip = 0); // short for build request +int verify(ParentResult *r, ParentResultType e, const char *h, int p); + +/* + For supporting multiple Socks servers, we essentially use the + ParentSelection infrastructure. Only the initialization is different. + If needed, we will have to implement most of the functions in + ParentSection.cc for Socks as well. For right now we will just use + ParentSelection + + All the members in ParentConfig are static. Right now + we will duplicate the code for these static functions. +*/ +struct SocksServerConfig +{ + static void startup(); + static void reconfigure(); + static void print(); + + static ParentConfigParams *acquire() { return (ParentConfigParams *) configProcessor.get(SocksServerConfig::m_id); } + static void release(ParentConfigParams *params) { configProcessor.release(SocksServerConfig::m_id, params); } + + static int m_id; +}; + +#endif diff --git a/proxy/Plugin.cc b/proxy/Plugin.cc new file mode 100644 index 00000000..29f1a5be --- /dev/null +++ b/proxy/Plugin.cc @@ -0,0 +1,385 @@ +/** @file + + Plugin init + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +// XXX: HP-UX ??? Not part of configure supported hosts +#if defined(hpux) +#include +#endif +#include "ink_platform.h" +#include "ink_file.h" +#include "Compatability.h" +#include "ParseRules.h" +#include "I_RecCore.h" +#include "I_Layout.h" +#include "InkAPIInternal.h" +#include "Main.h" +#include "Plugin.h" +#include "PluginDB.h" +#include "stats/Stats.h" + +// HPUX: +// LD_SHAREDCMD=ld -b +// SGI: +// LD_SHAREDCMD=ld -shared +// OSF: +// LD_SHAREDCMD=ld -shared -all -expect_unresolved "*" +// Solaris: +// LD_SHAREDCMD=ld -G + + +static const char *plugin_dir = "."; +static const char *extensions_dir = "."; +static PluginDB *plugin_db = NULL; + +typedef void (*init_func_t) (int argc, char *argv[]); +typedef void (*init_func_w_handle_t) (void *handle, int argc, char *argv[]); +typedef int (*lic_req_func_t) (void); + +tsapi int +load_in_export_symbols(int j) +{ + int i = eight_bit_table[j]; + return i; +} + +// Plugin registration vars +// +// plugin_reg_list has an entry for each plugin +// we've successfully been able to load +// plugin_reg_current is used to associate the +// plugin we're in the process of loading with +// it struct. We need this global pointer since +// the API doesn't have any plugin context. Init +// is single threaded so we can get away with the +// global pointer +// +DLL plugin_reg_list; +PluginRegInfo *plugin_reg_current = NULL; + +PluginRegInfo::PluginRegInfo() + : plugin_registered(false), plugin_path(NULL), sdk_version(PLUGIN_SDK_VERSION_UNKNOWN), + plugin_name(NULL), vendor_name(NULL), support_email(NULL) +{ } + +static void * +dll_open(char *fn, bool global) +{ + int global_flags = global ? RTLD_GLOBAL : 0; + + return (void *) dlopen(fn, RTLD_NOW | global_flags); +} + +static void * +dll_findsym(void *dlp, const char *name) +{ + return (void *) dlsym(dlp, name); +} + +static char * +dll_error(void *dlp) +{ + NOWARN_UNUSED(dlp); + return (char *) dlerror(); +} + +static void +dll_close(void *dlp) +{ + dlclose(dlp); +} + + +static void +plugin_load(int argc, char *argv[], bool internal) +{ + char path[PATH_NAME_MAX + 1]; + void *handle; + init_func_t init; + lic_req_func_t lic_req; + PluginRegInfo *plugin_reg_temp; + const char *pdir = internal ? extensions_dir : plugin_dir; + + if (argc < 1) { + return; + } + ink_filepath_make(path, sizeof(path), pdir, argv[0]); + + Note("loading plugin '%s'", path); + + plugin_reg_temp = plugin_reg_list.head; + while (plugin_reg_temp) { + if (strcmp(plugin_reg_temp->plugin_path, path) == 0) { + Warning("multiple loading of plugin %s", path); + break; + } + plugin_reg_temp = (plugin_reg_temp->link).next; + } + + handle = dll_open(path, (internal ? true : false)); + if (!handle) { + Error("unable to load '%s': %s", path, dll_error(handle)); + abort(); + } + + lic_req = (lic_req_func_t) dll_findsym(handle, "TSPluginLicenseRequired"); + if (lic_req && lic_req() != 0) { + PluginDB::CheckLicenseResult result = plugin_db->CheckLicense(argv[0]); + if (result != PluginDB::license_ok) { + Error("unable to load '%s': %s", path, PluginDB::CheckLicenseResultStr[result]); + dll_close(handle); + abort(); + } + } + // Allocate a new registration structure for the + // plugin we're starting up + ink_assert(plugin_reg_current == NULL); + plugin_reg_current = new PluginRegInfo; + plugin_reg_current->plugin_path = xstrdup(path); + + init_func_w_handle_t inith = (init_func_w_handle_t) dll_findsym(handle, "TSPluginInitwDLLHandle"); + if (inith) { + inith(handle, argc, argv); + return; + } + + init = (init_func_t) dll_findsym(handle, "TSPluginInit"); + if (!init) { + Error("unable to find TSPluginInit function '%s': %s", path, dll_error(handle)); + dll_close(handle); + abort(); + } + + init(argc, argv); + + plugin_reg_list.push(plugin_reg_current); + plugin_reg_current = NULL; + //dll_close(handle); +} + +static char * +plugin_expand(char *arg) +{ + RecDataT data_type; + char *str = NULL; + + if (*arg != '$') { + return (char *) NULL; + } + // skip the $ character + arg += 1; + + if (RecGetRecordDataType(arg, &data_type) != REC_ERR_OKAY) { + goto not_found; + } + + switch (data_type) { + case RECD_STRING: + { + RecString str_val; + if (RecGetRecordString_Xmalloc(arg, &str_val) != REC_ERR_OKAY) { + goto not_found; + } + return (char *) str_val; + break; + } + case RECD_FLOAT: + { + RecFloat float_val; + if (RecGetRecordFloat(arg, &float_val) != REC_ERR_OKAY) { + goto not_found; + } + str = (char *) xmalloc(128); + snprintf(str, 128, "%f", (float) float_val); + return str; + break; + } + case RECD_INT: + { + RecInt int_val; + if (RecGetRecordInt(arg, &int_val) != REC_ERR_OKAY) { + goto not_found; + } + str = (char *) xmalloc(128); + snprintf(str, 128, "%ld", (long int) int_val); + return str; + break; + } + case RECD_COUNTER: + { + RecCounter count_val; + if (RecGetRecordCounter(arg, &count_val) != REC_ERR_OKAY) { + goto not_found; + } + str = (char *) xmalloc(128); + snprintf(str, 128, "%ld", (long int) count_val); + return str; + break; + } + default: + goto not_found; + break; + } + + +not_found: + Warning("plugin.config: unable to find parameter %s", arg); + return NULL; +} + + +int +plugins_exist(const char *config_dir) +{ + char path[PATH_NAME_MAX + 1]; + char line[1024], *p; + int fd; + int plugin_count = 0; + + ink_filepath_make(path, sizeof(path), config_dir, "plugin.config"); + fd = open(path, O_RDONLY); + if (fd < 0) { + Warning("unable to open plugin config file '%s': %d, %s", path, errno, strerror(errno)); + return 0; + } + while (ink_file_fd_readline(fd, sizeof(line) - 1, line) > 0) { + p = line; + // strip leading white space and test for comment or blank line + while (*p && ParseRules::is_wslfcr(*p)) + ++p; + if ((*p == '\0') || (*p == '#')) + continue; + plugin_count++; + } + close(fd); + return plugin_count; +} + +void +plugin_init(const char *config_dir, bool internal) +{ + char path[PATH_NAME_MAX + 1]; + char line[1024], *p; + char *argv[64]; + char *vars[64]; + int argc; + int fd; + int i; + static bool INIT_ONCE = true; + + if (INIT_ONCE) { + api_init(); + init_inkapi_stat_system(); + char *cfg = NULL; + + plugin_dir = TSPluginDirGet(); + + RecGetRecordString_Xmalloc("proxy.config.plugin.extensions_dir", (char**)&cfg); + if (cfg != NULL) { + extensions_dir = Layout::get()->relative(cfg); + xfree(cfg); + cfg = NULL; + } + ink_filepath_make(path, sizeof(path), config_dir, "plugin.db"); + plugin_db = new PluginDB(path); + INIT_ONCE = false; + } + + ink_assert(plugin_db); + + if (internal == false) { + ink_filepath_make(path, sizeof(path), config_dir, "plugin.config"); + } else { + ink_filepath_make(path, sizeof(path), config_dir, "extensions.config"); + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + /* secret extensions dont complain */ + if (internal == false) { + Warning("unable to open plugin config file '%s': %d, %s", path, errno, strerror(errno)); + } + return; + } + + while (ink_file_fd_readline(fd, sizeof(line) - 1, line) > 0) { + argc = 0; + p = line; + + // strip leading white space and test for comment or blank line + while (*p && ParseRules::is_wslfcr(*p)) + ++p; + if ((*p == '\0') || (*p == '#')) + continue; + + // not comment or blank, so rip line into tokens + while (1) { + while (*p && ParseRules::is_wslfcr(*p)) + ++p; + if ((*p == '\0') || (*p == '#')) + break; // EOL + + if (*p == '\"') { + p += 1; + + argv[argc++] = p; + + while (*p && (*p != '\"')) { + p += 1; + } + if (*p == '\0') { + break; + } + *p++ = '\0'; + } else { + argv[argc++] = p; + + while (*p && !ParseRules::is_wslfcr(*p) && (*p != '#')) { + p += 1; + } + if ((*p == '\0') || (*p == '#')) { + break; + } + *p++ = '\0'; + } + } + + for (i = 0; i < argc; i++) { + vars[i] = plugin_expand(argv[i]); + if (vars[i]) { + argv[i] = vars[i]; + } + } + + plugin_load(argc, argv, internal); + + for (i = 0; i < argc; i++) { + if (vars[i]) { + xfree(vars[i]); + } + } + } + + close(fd); +} + diff --git a/proxy/Plugin.h b/proxy/Plugin.h new file mode 100644 index 00000000..d5203130 --- /dev/null +++ b/proxy/Plugin.h @@ -0,0 +1,62 @@ +/** @file + + Plugin init declarations + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __PLUGIN_H__ +#define __PLUGIN_H__ + +#include "List.h" + +// need to keep syncronized with TSSDKVersion +// in ts/ts.h.in +typedef enum +{ + PLUGIN_SDK_VERSION_UNKNOWN = -1, + PLUGIN_SDK_VERSION_2_0, + PLUGIN_SDK_VERSION_3_0, + PLUGIN_SDK_VERSION_4_0 +} PluginSDKVersion; + +struct PluginRegInfo +{ + PluginRegInfo(); + ~PluginRegInfo(); + + bool plugin_registered; + char *plugin_path; + + PluginSDKVersion sdk_version; + char *plugin_name; + char *vendor_name; + char *support_email; + + LINK(PluginRegInfo, link); +}; + +// Plugin registration vars +extern DLL plugin_reg_list; +extern PluginRegInfo *plugin_reg_current; + +void plugin_init(const char *config_dir, bool internal_exts); +int plugins_exist(const char *config_dir); + +#endif /* __PLUGIN_H__ */ diff --git a/proxy/PluginDB.cc b/proxy/PluginDB.cc new file mode 100644 index 00000000..a2b42d25 --- /dev/null +++ b/proxy/PluginDB.cc @@ -0,0 +1,205 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_config.h" +#include +#include +#include +#include "ink_code.h" +#include "Diags.h" +#include "ParseRules.h" +#include "PluginDB.h" + +/*************************************************************************** + * + * An Inktomi Traffic Server plugin license key should look like: + * + * XXXXXEEEEDDDDDD + * + * XXXXX is a 5 digit alphanumeric id used by plugin vendors to + * assign to their customers. + * + * EEEE is the hex encoding of the expiration date. It's the number + * of days from January 1, 1970. If a plugin has no expiration date, + * 0000 can be used instead. + * + * DDDDDD is the INK_MD5 encoding of some combination of the following + * strings: "Inktomi Traffic Server", "Plugin Name", "XXXXXEEEE". + * + * + ***************************************************************************/ + +const char * + PluginDB::CheckLicenseResultStr[] = { + "license missing", + "license expired", + "license invalid", + "license ok" +}; + +const unsigned int + PluginDB::license_custid_len = 5; +const unsigned int + PluginDB::license_expire_len = 4; +const unsigned int + PluginDB::license_digest_len = 6; +const unsigned int + PluginDB::license_total_len = PluginDB::license_custid_len + + PluginDB::license_expire_len + PluginDB::license_digest_len; + +PluginDB::PluginDB(const char *plugin_db_file) +{ + info_table = ink_hash_table_create(InkHashTableKeyType_String); + ReadPluginDB(plugin_db_file); +} + +PluginDB::~PluginDB(void) +{ + ink_hash_table_destroy_and_free_values(info_table); +} + +void +PluginDB::ReadPluginDB(const char *plugin_db_file) +{ + FILE *pdb = fopen(plugin_db_file, "r"); + if (pdb == NULL) { + Warning("unable to open plugin.db file '%s': %d, %s", plugin_db_file, errno, strerror(errno)); + return; + } + + char line[1024]; + char plugin_obj[256]; + plugin_obj[0] = '\0'; + PluginDB::PluginInfo * pinfo = new PluginDB::PluginInfo(); + + while (fgets(line, sizeof(line) - 1, pdb) != NULL) { + char *p = line; + while (*p && ParseRules::is_wslfcr(*p)) { + p++; + } + if ((*p == '\0') || (*p == '#')) { + continue; + } + // We have a non-comment and non-blank line + + // Nullify the newline character + int len = strlen(p); + int i; + p[len - 1] = '\0'; + + if (p[0] == '[') { + if (plugin_obj[0] != '\0' && (pinfo->name[0] != '\0' || pinfo->license[0] != '\0')) { + ink_hash_table_insert(info_table, (InkHashTableKey) plugin_obj, (InkHashTableValue) pinfo); + plugin_obj[0] = '\0'; + pinfo = new PluginDB::PluginInfo(); + } + p++; + for (i = 0; p[i] != '\0' && p[i] != ']' && i < 255; i++) { + pinfo->name[i] = p[i]; + } + pinfo->name[i] = '\0'; + + } else { + if (strstr(p, "Object=")) { + p = p + sizeof("Object=") - 1; + for (i = 0; p[i] != '\0' && i < 255; i++) { + plugin_obj[i] = p[i]; + } + plugin_obj[i] = '\0'; + } else if (strstr(p, "License=")) { + p = p + sizeof("License=") - 1; + for (i = 0; p[i] != '\0' && i < 255; i++) { + pinfo->license[i] = p[i]; + } + pinfo->license[i] = '\0'; + } + } + } + + if (plugin_obj[0] != '\0' && (pinfo->name[0] != '\0' || pinfo->license[0] != '\0')) { + ink_hash_table_insert(info_table, (InkHashTableKey) plugin_obj, (InkHashTableValue) pinfo); + } else { + delete pinfo; + } + fclose(pdb); +} + +PluginDB::CheckLicenseResult PluginDB::CheckLicense(const char *plugin_obj) +{ + char + buffer[1024], + buffer_md5[16], + buffer_md5_str[33]; + char + expire_str[PluginDB::license_expire_len + 1]; + unsigned long + expire_days; + INK_DIGEST_CTX + md5_context; + PluginDB::PluginInfo * pinfo; + char * + end_ptr = NULL; + + InkHashTableEntry * + ht_entry = ink_hash_table_lookup_entry(info_table, + (InkHashTableKey) plugin_obj); + if (ht_entry != NULL) { + pinfo = (PluginDB::PluginInfo *) ink_hash_table_entry_value(info_table, ht_entry); + } else { + return PluginDB::license_missing; + } + + if (strlen(pinfo->license) != PluginDB::license_total_len) { + return PluginDB::license_invalid; + } + + snprintf(buffer, sizeof(buffer), "Inktomi Traffic Server %s ", pinfo->name); + strncat(buffer, pinfo->license, PluginDB::license_custid_len + PluginDB::license_expire_len); + + ink_code_incr_md5_init(&md5_context); + ink_code_incr_md5_update(&md5_context, buffer, strlen(buffer)); + ink_code_incr_md5_final(buffer_md5, &md5_context); + // coverity[uninit_use_in_call] + ink_code_md5_stringify(buffer_md5_str, sizeof(buffer_md5_str), buffer_md5); + + if (strncmp(buffer_md5_str, + pinfo->license + PluginDB::license_custid_len + + PluginDB::license_expire_len, PluginDB::license_digest_len) != 0) { + return PluginDB::license_invalid; + } + + strncpy(expire_str, pinfo->license + PluginDB::license_custid_len, PluginDB::license_expire_len); + expire_str[PluginDB::license_expire_len] = '\0'; + + expire_days = strtoul(expire_str, &end_ptr, 16); + + if (expire_days != 0) { + time_t + time_now = time(NULL); + if ((unsigned long) time_now > expire_days * (60 * 60 * 24)) { + return PluginDB::license_expired; + } + } + + return PluginDB::license_ok; +} diff --git a/proxy/PluginDB.h b/proxy/PluginDB.h new file mode 100644 index 00000000..cf8f3aea --- /dev/null +++ b/proxy/PluginDB.h @@ -0,0 +1,65 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __PLUGIN_DB_H__ +#define __PLUGIN_DB_H__ + +#include "ink_hash_table.h" + +class PluginDB +{ +public: + typedef enum + { + license_missing = 0, + license_expired, + license_invalid, + license_ok + } CheckLicenseResult; + + PluginDB(const char *plugin_db_file); + ~PluginDB(void); + + CheckLicenseResult CheckLicense(const char *plugin_obj); + + static const char *CheckLicenseResultStr[]; + +private: + + typedef struct + { + char name[256]; + char license[256]; + } PluginInfo; + + static const unsigned int license_custid_len; + static const unsigned int license_expire_len; + static const unsigned int license_digest_len; + static const unsigned int license_total_len; + + void ReadPluginDB(const char *plugin_db_file); + + InkHashTable *info_table; +}; + +#endif /* __PLUGIN_DB_H__ */ diff --git a/proxy/PluginVC.cc b/proxy/PluginVC.cc new file mode 100644 index 00000000..35d9f488 --- /dev/null +++ b/proxy/PluginVC.cc @@ -0,0 +1,1265 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + PluginVC.cc + + Description: Allows bi-directional transfer for data from one + continuation to another via a mechanism that impersonates a + NetVC. Should implement all external attributes of NetVConnections. + + Since data is transfered within Traffic Server, this is a two + headed beast. One NetVC on initiating side (active side) and + one NetVC on the receiving side (passive side). + + The two NetVC subclasses, PluginVC, are part PluginVCCore object. All + three objects share the same mutex. That mutex is required + for doing operations that affect the shared buffers, + read state from the PluginVC on the other side or deal with deallocation. + + To simplify the code, all data passing through the system goes initially + into a shared buffer. There are two shared buffers, one for each + direction of the connection. While it's more efficient to transfer + the data from one buffer to another directly, this creates a lot + of tricky conditions since you must be holding the lock for both + sides, in additional this VC's lock. Additionally, issues like + watermarks are very hard to deal with. Since we try to + to move data by IOBufferData references the efficiency penalty shouldn't + be too bad and if it is a big pentaly, a brave soul can reimplement + to move the data directly without the intermediate buffer. + + Locking is difficult issue for this multi-headed beast. In each + PluginVC, there a two locks. The one we got from our PluginVCCore and + the lock from the state machine using the PluginVC. The read side + lock & the write side lock must be the same. The regular net processor has + this constraint as well. In order to handle scheduling of retry events cleanly, + we have two event poitners, one for each lock. sm_lock_retry_event can only + be changed while holding the using state machine's lock and + core_lock_retry_event can only be manipulated while holding the PluginVC's + lock. On entry to PluginVC::main_handler, we obtain all the locks + before looking at the events. If we can't get all the locks + we reschedule the event for further retries. Since all the locks are + obtained in the beginning of the handler, we know we are running + exclusively in the later parts of the handler and we will + be free from do_io or reenable calls on the PluginVC. + + The assumption is made (conistant with IO Core spec) that any close, + shutdown, reenable, or do_io_{read,write) operation is done by the callee + while holding the lock for that side of the operation. + + + ****************************************************************************/ + +#include "PluginVC.h" +#include "P_EventSystem.h" +#include "P_Net.h" +#include "Regression.h" + +#define PVC_LOCK_RETRY_TIME HRTIME_MSECONDS(10) +#undef MIN +#define MIN(x,y) (((x) <= (y)) ? (x) : (y)) +#undef MAX +#define MAX(x,y) (((x) >= (y)) ? (x) : (y)) + +#define PVC_DEFAULT_MAX_BYTES 32768 +#define MIN_BLOCK_TRANSFER_BYTES 128 + +#define EVENT_PTR_LOCKED (void*) 0x1 +#define EVENT_PTR_CLOSED (void*) 0x2 + +#define PVC_TYPE ((vc_type == PLUGIN_VC_ACTIVE) ? "Active" : "Passive") +#define PVC_ID (core_obj? core_obj->id : (unsigned)-1) + +PluginVC::PluginVC(): +NetVConnection(), +magic(PLUGIN_VC_MAGIC_ALIVE), vc_type(PLUGIN_VC_UNKNOWN), core_obj(NULL), +other_side(NULL), read_state(), write_state(), +need_read_process(false), need_write_process(false), +closed(false), sm_lock_retry_event(NULL), core_lock_retry_event(NULL), +deletable(false), reentrancy_count(0), active_timeout(0), inactive_timeout(0), active_event(NULL), inactive_event(NULL) +{ + SET_HANDLER(&PluginVC::main_handler); +} + +PluginVC::~PluginVC() +{ + mutex = NULL; +} + +int +PluginVC::main_handler(int event, void *data) +{ + + Debug("pvc_event", "[%u] %s: Received event %d", PVC_ID, PVC_TYPE, event); + + ink_release_assert(event == EVENT_INTERVAL || event == EVENT_IMMEDIATE); + ink_release_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + ink_debug_assert(!deletable); + ink_debug_assert(data != NULL); + + Event *call_event = (Event *) data; + EThread *my_ethread = mutex->thread_holding; + ink_release_assert(my_ethread != NULL); + + bool read_mutex_held = false; + bool write_mutex_held = false; + Ptr read_side_mutex = read_state.vio.mutex; + Ptr write_side_mutex = write_state.vio.mutex; + + if (read_side_mutex) { + read_mutex_held = MUTEX_TAKE_TRY_LOCK(read_side_mutex, my_ethread); + + if (!read_mutex_held) { + call_event->schedule_in(PVC_LOCK_RETRY_TIME); + return 0; + } + + if (read_side_mutex.m_ptr != read_state.vio.mutex.m_ptr) { + // It's possible some swapped the mutex on us before + // we were able to grab it + Mutex_unlock(read_side_mutex, my_ethread); + call_event->schedule_in(PVC_LOCK_RETRY_TIME); + return 0; + } + } + + if (write_side_mutex) { + write_mutex_held = MUTEX_TAKE_TRY_LOCK(write_side_mutex, my_ethread); + + if (!write_mutex_held) { + if (read_mutex_held) { + Mutex_unlock(read_side_mutex, my_ethread); + } + call_event->schedule_in(PVC_LOCK_RETRY_TIME); + return 0; + } + + if (write_side_mutex.m_ptr != write_state.vio.mutex.m_ptr) { + // It's possible some swapped the mutex on us before + // we were able to grab it + Mutex_unlock(write_side_mutex, my_ethread); + if (read_mutex_held) { + Mutex_unlock(read_side_mutex, my_ethread); + } + call_event->schedule_in(PVC_LOCK_RETRY_TIME); + return 0; + } + } + // We've got all the locks so there should not be any + // other calls active + ink_release_assert(reentrancy_count == 0); + + if (closed) { + process_close(); + return 0; + } + // We can get closed while we're calling back the + // continuation. Set the reentrancy count so we know + // we could be calling the continuation and that we + // need to defer close processing + reentrancy_count++; + + if (call_event == active_event) { + process_timeout(call_event, VC_EVENT_ACTIVE_TIMEOUT, &active_event); + } else if (call_event == inactive_event) { + process_timeout(call_event, VC_EVENT_INACTIVITY_TIMEOUT, &inactive_event); + } else { + if (call_event == sm_lock_retry_event) { + sm_lock_retry_event = NULL; + } else { + ink_release_assert(call_event == core_lock_retry_event); + core_lock_retry_event = NULL; + } + + if (need_read_process) { + process_read_side(false); + } + + if (need_write_process && !closed) { + process_write_side(false); + } + + } + + reentrancy_count--; + if (closed) { + process_close(); + } + + if (read_mutex_held) { + Mutex_unlock(read_side_mutex, my_ethread); + } + + if (write_mutex_held) { + Mutex_unlock(write_side_mutex, my_ethread); + } + + return 0; +} + +VIO * +PluginVC::do_io_read(Continuation * c, int64_t nbytes, MIOBuffer * buf) +{ + + ink_assert(!closed); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + if (buf) { + read_state.vio.buffer.writer_for(buf); + } else { + read_state.vio.buffer.clear(); + } + + // Note: we set vio.op last because process_read_side looks at it to + // tell if the VConnection is active. + read_state.vio.mutex = c->mutex; + read_state.vio._cont = c; + read_state.vio.nbytes = nbytes; + read_state.vio.ndone = 0; + read_state.vio.vc_server = (VConnection *) this; + read_state.vio.op = VIO::READ; + + Debug("pvc", "[%u] %s: do_io_read for %d bytes", PVC_ID, PVC_TYPE, nbytes); + + // Since reentrant callbacks are not allowed on from do_io + // functions schedule ourselves get on a different stack + need_read_process = true; + setup_event_cb(0, &sm_lock_retry_event); + + return &read_state.vio; +} + +VIO * +PluginVC::do_io_write(Continuation * c, int64_t nbytes, IOBufferReader * abuffer, bool owner) +{ + + ink_assert(!closed); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + if (abuffer) { + ink_assert(!owner); + write_state.vio.buffer.reader_for(abuffer); + } else { + write_state.vio.buffer.clear(); + } + + // Note: we set vio.op last because process_write_side looks at it to + // tell if the VConnection is active. + write_state.vio.mutex = c->mutex; + write_state.vio._cont = c; + write_state.vio.nbytes = nbytes; + write_state.vio.ndone = 0; + write_state.vio.vc_server = (VConnection *) this; + write_state.vio.op = VIO::WRITE; + + Debug("pvc", "[%u] %s: do_io_write for %d bytes", PVC_ID, PVC_TYPE, nbytes); + + // Since reentrant callbacks are not allowed on from do_io + // functions schedule ourselves get on a different stack + need_write_process = true; + setup_event_cb(0, &sm_lock_retry_event); + + return &write_state.vio; +} + +void +PluginVC::reenable(VIO * vio) +{ + + ink_assert(!closed); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + ink_debug_assert(vio->mutex->thread_holding == this_ethread()); + + Debug("pvc", "[%u] %s: reenable %s", PVC_ID, PVC_TYPE, (vio->op == VIO::WRITE) ? "Write" : "Read"); + + if (vio->op == VIO::WRITE) { + ink_assert(vio == &write_state.vio); + need_write_process = true; + } else if (vio->op == VIO::READ) { + need_read_process = true; + } else { + ink_release_assert(0); + } + setup_event_cb(0, &sm_lock_retry_event); +} + +void +PluginVC::reenable_re(VIO * vio) +{ + + ink_assert(!closed); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + ink_debug_assert(vio->mutex->thread_holding == this_ethread()); + + Debug("pvc", "[%u] %s: reenable_re %s", PVC_ID, PVC_TYPE, (vio->op == VIO::WRITE) ? "Write" : "Read"); + + MUTEX_TRY_LOCK(lock, this->mutex, this_ethread()); + if (!lock) { + if (vio->op == VIO::WRITE) { + need_write_process = true; + } else { + need_read_process = true; + } + setup_event_cb(PVC_LOCK_RETRY_TIME, &sm_lock_retry_event); + return; + } + + reentrancy_count++; + + if (vio->op == VIO::WRITE) { + ink_assert(vio == &write_state.vio); + process_write_side(false); + } else if (vio->op == VIO::READ) { + ink_assert(vio == &read_state.vio); + process_read_side(false); + } else { + ink_release_assert(0); + } + + reentrancy_count--; + + // To process the close, we need the lock + // for the PluginVC. Schedule an event + // to make sure we get it + if (closed) { + setup_event_cb(0, &sm_lock_retry_event); + } +} + +void +PluginVC::do_io_close(int flag) +{ + NOWARN_UNUSED(flag); + ink_assert(closed == false); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + Debug("pvc", "[%u] %s: do_io_close", PVC_ID, PVC_TYPE); + + if (reentrancy_count > 0) { + // Do nothing since dealloacting ourselves + // now will lead to us running on a dead + // PluginVC since we are being called + // reentrantly + closed = true; + return; + } + + MUTEX_TRY_LOCK(lock, mutex, this_ethread()); + + if (!lock) { + setup_event_cb(PVC_LOCK_RETRY_TIME, &sm_lock_retry_event); + closed = true; + return; + } else { + closed = true; + } + + process_close(); +} + +void +PluginVC::do_io_shutdown(ShutdownHowTo_t howto) +{ + + ink_assert(!closed); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + switch (howto) { + case IO_SHUTDOWN_READ: + read_state.shutdown = true; + break; + case IO_SHUTDOWN_WRITE: + write_state.shutdown = true; + break; + case IO_SHUTDOWN_READWRITE: + read_state.shutdown = true; + write_state.shutdown = true; + break; + } +} + +// int PluginVC::transfer_bytes(MIOBuffer* transfer_to, +// IOBufferReader* transfer_from, int act_on) +// +// Takes care of transfering bytes from a reader to another buffer +// In the case of large transfers, we move blocks. In the case +// of small transfers we copy data so as to not build too many +// buffer blocks +// +// Args: +// transfer_to: buffer to copy to +// transfer_from: buffer_copy_from +// act_on: is the max number of bytes we are to copy. There must +// be at least act_on bytes available from transfer_from +// +// Returns number of bytes transfered +// +int64_t +PluginVC::transfer_bytes(MIOBuffer * transfer_to, IOBufferReader * transfer_from, int64_t act_on) +{ + + int64_t total_added = 0; + + ink_debug_assert(act_on <= transfer_from->read_avail()); + + while (act_on > 0) { + int64_t block_read_avail = transfer_from->block_read_avail(); + int64_t to_move = MIN(act_on, block_read_avail); + int64_t moved = 0; + + if (to_move <= 0) { + break; + } + + if (to_move >= MIN_BLOCK_TRANSFER_BYTES) { + moved = transfer_to->write(transfer_from, to_move, 0); + } else { + // We have a really small amount of data. To make + // sure we don't get a huge build up of blocks which + // can lead to stack overflows if the buffer is destroyed + // before we read from it, we need copy over to the new + // buffer instead of doing a block transfer + moved = transfer_to->write(transfer_from->start(), to_move); + + if (moved == 0) { + // We are out of buffer space + break; + } + } + + act_on -= moved; + transfer_from->consume(moved); + total_added += moved; + } + + return total_added; +} + +// void PluginVC::process_write_side(bool cb_ok) +// +// This function may only be called while holding +// this->mutex & while it is ok to callback the +// write side continuation +// +// Does write side processing +// +void +PluginVC::process_write_side(bool other_side_call) +{ + + ink_assert(!deletable); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + MIOBuffer *core_buffer = (vc_type == PLUGIN_VC_ACTIVE) ? core_obj->a_to_p_buffer : core_obj->p_to_a_buffer; + + need_write_process = false; + + if (write_state.vio.op != VIO::WRITE || closed || write_state.shutdown) { + return; + } + // Acquire the lock of the write side continuation + EThread *my_ethread = mutex->thread_holding; + ink_assert(my_ethread != NULL); + MUTEX_TRY_LOCK(lock, write_state.vio.mutex, my_ethread); + if (!lock) { + Debug("pvc_event", "[%u] %s: process_write_side lock miss, retrying", PVC_ID, PVC_TYPE); + + need_write_process = true; + setup_event_cb(PVC_LOCK_RETRY_TIME, &core_lock_retry_event); + return; + } + + Debug("pvc", "[%u] %s: process_write_side", PVC_ID, PVC_TYPE); + need_write_process = false; + + + // Check the state of our write buffer as well as ntodo + int64_t ntodo = write_state.vio.ntodo(); + if (ntodo == 0) { + return; + } + + IOBufferReader *reader = write_state.vio.get_reader(); + int64_t bytes_avail = reader->read_avail(); + int64_t act_on = MIN(bytes_avail, ntodo); + + Debug("pvc", "[%u] %s: process_write_side; act_on %d", PVC_ID, PVC_TYPE, act_on); + + if (other_side->closed || other_side->read_state.shutdown) { + write_state.vio._cont->handleEvent(VC_EVENT_ERROR, &write_state.vio); + return; + } + + if (act_on <= 0) { + if (ntodo > 0) { + // Notify the continuation that we are "disabling" + // ourselves due to to nothing to write + write_state.vio._cont->handleEvent(VC_EVENT_WRITE_READY, &write_state.vio); + } + return; + } + // Bytes available, try to transfer to the PluginVCCore + // intermediate buffer + // + int64_t buf_space = PVC_DEFAULT_MAX_BYTES - core_buffer->max_read_avail(); + if (buf_space <= 0) { + Debug("pvc", "[%u] %s: process_write_side no buffer space", PVC_ID, PVC_TYPE); + return; + } + act_on = MIN(act_on, buf_space); + + int64_t added = transfer_bytes(core_buffer, reader, act_on); + if (added < 0) { + // Couldn't actually get the buffer space. This only + // happens on small transfers with the above + // PVC_DEFAULT_MAX_BYTES factor doesn't apply + Debug("pvc", "[%u] %s: process_write_side out of buffer space", PVC_ID, PVC_TYPE); + return; + } + + write_state.vio.ndone += added; + + Debug("pvc", "[%u] %s: process_write_side; added %d", PVC_ID, PVC_TYPE, added); + + if (write_state.vio.ntodo() == 0) { + write_state.vio._cont->handleEvent(VC_EVENT_WRITE_COMPLETE, &write_state.vio); + } else { + write_state.vio._cont->handleEvent(VC_EVENT_WRITE_READY, &write_state.vio); + } + + update_inactive_time(); + + // Wake up the read side on the other side to process these bytes + if (!other_side->closed) { + if (!other_side_call) { + other_side->process_read_side(true); + } else { + other_side->read_state.vio.reenable(); + } + } +} + + +// void PluginVC::process_read_side() +// +// This function may only be called while holding +// this->mutex & while it is ok to callback the +// read side continuation +// +// Does read side processing +// +void +PluginVC::process_read_side(bool other_side_call) +{ + + ink_assert(!deletable); + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + // TODO: Never used?? + //MIOBuffer *core_buffer; + + IOBufferReader *core_reader; + + if (vc_type == PLUGIN_VC_ACTIVE) { + //core_buffer = core_obj->p_to_a_buffer; + core_reader = core_obj->p_to_a_reader; + } else { + ink_assert(vc_type == PLUGIN_VC_PASSIVE); + //core_buffer = core_obj->a_to_p_buffer; + core_reader = core_obj->a_to_p_reader; + } + + need_read_process = false; + + if (read_state.vio.op != VIO::READ || closed || read_state.shutdown) { + return; + } + // Acquire the lock of the read side continuation + EThread *my_ethread = mutex->thread_holding; + ink_assert(my_ethread != NULL); + MUTEX_TRY_LOCK(lock, read_state.vio.mutex, my_ethread); + if (!lock) { + Debug("pvc_event", "[%u] %s: process_read_side lock miss, retrying", PVC_ID, PVC_TYPE); + + need_read_process = true; + setup_event_cb(PVC_LOCK_RETRY_TIME, &core_lock_retry_event); + return; + } + + Debug("pvc", "[%u] %s: process_read_side", PVC_ID, PVC_TYPE); + need_read_process = false; + + // Check the state of our read buffer as well as ntodo + int64_t ntodo = read_state.vio.ntodo(); + if (ntodo == 0) { + return; + } + + int64_t bytes_avail = core_reader->read_avail(); + int64_t act_on = MIN(bytes_avail, ntodo); + + Debug("pvc", "[%u] %s: process_read_side; act_on %d", PVC_ID, PVC_TYPE, act_on); + + if (act_on <= 0) { + if (other_side->closed || other_side->write_state.shutdown) { + read_state.vio._cont->handleEvent(VC_EVENT_EOS, &read_state.vio); + } + return; + } + // Bytes available, try to transfer from the PluginVCCore + // intermediate buffer + // + MIOBuffer *output_buffer = read_state.vio.get_writer(); + + int64_t water_mark = output_buffer->water_mark; + water_mark = MAX(water_mark, PVC_DEFAULT_MAX_BYTES); + int64_t buf_space = water_mark - output_buffer->max_read_avail(); + if (buf_space <= 0) { + Debug("pvc", "[%u] %s: process_read_side no buffer space", PVC_ID, PVC_TYPE); + return; + } + act_on = MIN(act_on, buf_space); + + int64_t added = transfer_bytes(output_buffer, core_reader, act_on); + if (added <= 0) { + // Couldn't actually get the buffer space. This only + // happens on small transfers with the above + // PVC_DEFAULT_MAX_BYTES factor doesn't apply + Debug("pvc", "[%u] %s: process_read_side out of buffer space", PVC_ID, PVC_TYPE); + return; + } + + read_state.vio.ndone += added; + + Debug("pvc", "[%u] %s: process_read_side; added %d", PVC_ID, PVC_TYPE, added); + + if (read_state.vio.ntodo() == 0) { + read_state.vio._cont->handleEvent(VC_EVENT_READ_COMPLETE, &read_state.vio); + } else { + read_state.vio._cont->handleEvent(VC_EVENT_READ_READY, &read_state.vio); + } + + update_inactive_time(); + + // Wake up the other side so it knows there is space available in + // intermediate buffer + if (!other_side->closed) { + if (!other_side_call) { + other_side->process_write_side(true); + } else { + other_side->write_state.vio.reenable(); + } + } +} + +// void PluginVC::process_read_close() +// +// This function may only be called while holding +// this->mutex +// +// Tries to close the and dealloc the the vc +// +void +PluginVC::process_close() +{ + + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + Debug("pvc", "[%u] %s: process_close", PVC_ID, PVC_TYPE); + + if (!deletable) { + deletable = true; + } + + if (sm_lock_retry_event) { + sm_lock_retry_event->cancel(); + sm_lock_retry_event = NULL; + } + + if (core_lock_retry_event) { + core_lock_retry_event->cancel(); + core_lock_retry_event = NULL; + } + + if (active_event) { + active_event->cancel(); + active_event = NULL; + } + + if (inactive_event) { + inactive_event->cancel(); + inactive_event = NULL; + } + // If the other side of the PluginVC is not closed + // we need to force it process both living sides + // of the connection in order that it recognizes + // the close + if (!other_side->closed && core_obj->connected) { + other_side->need_write_process = true; + other_side->need_read_process = true; + other_side->setup_event_cb(0, &other_side->core_lock_retry_event); + } + + core_obj->attempt_delete(); +} + +// void PluginVC::process_timeout(Event* e, int event_to_send, Event** our_eptr) +// +// Handles sending timeout event to the VConnection. e is the event we got +// which indicats the timeout. event_to_send is the event to the +// vc user. Our_eptr is a pointer our event either inactive_event, +// or active_event. If we successfully send the timeout to vc user, +// we clear the pointer, otherwise we reschedule it. +// +// Because the possibility of reentrant close from vc user, we don't want to +// touch any state after making the call back +// +void +PluginVC::process_timeout(Event * e, int event_to_send, Event ** our_eptr) +{ + + ink_assert(e = *our_eptr); + + if (read_state.vio.op == VIO::READ && !read_state.shutdown && read_state.vio.ntodo() > 0) { + MUTEX_TRY_LOCK(lock, read_state.vio.mutex, e->ethread); + if (!lock) { + e->schedule_in(PVC_LOCK_RETRY_TIME); + return; + } + *our_eptr = NULL; + read_state.vio._cont->handleEvent(event_to_send, &read_state.vio); + } else if (write_state.vio.op == VIO::WRITE && !write_state.shutdown && write_state.vio.ntodo() > 0) { + MUTEX_TRY_LOCK(lock, write_state.vio.mutex, e->ethread); + if (!lock) { + e->schedule_in(PVC_LOCK_RETRY_TIME); + return; + } + *our_eptr = NULL; + write_state.vio._cont->handleEvent(event_to_send, &write_state.vio); + } else { + *our_eptr = NULL; + } +} + +void +PluginVC::update_inactive_time() +{ + if (inactive_event) { + inactive_event->cancel(); + inactive_event = eventProcessor.schedule_in(this, inactive_timeout); + } +} + +// void PluginVC::setup_event_cb(ink_hrtime in) +// +// Setup up the event processor to call us back. +// We've got two different event pointers to handle +// locking issues +// +void +PluginVC::setup_event_cb(ink_hrtime in, Event ** e_ptr) +{ + + ink_assert(magic == PLUGIN_VC_MAGIC_ALIVE); + + if (*e_ptr == NULL) { + + // We locked the pointer so we can now allocate an event + // to call us back + if (in == 0) { + if(this_ethread()->tt == REGULAR) { + *e_ptr = this_ethread()->schedule_imm_local(this); + } + else + { + *e_ptr = eventProcessor.schedule_imm(this); + } + } + else + { + if(this_ethread()->tt == REGULAR) { + *e_ptr = this_ethread()->schedule_in_local(this,in); + } + else + { + *e_ptr = eventProcessor.schedule_in(this, in); + } + } + } +} + +void +PluginVC::set_active_timeout(ink_hrtime timeout_in) +{ + active_timeout = timeout_in; + + // FIX - Do we need to handle the case where the timeout is set + // but no io has been done? + if (active_event) { + ink_assert(!active_event->cancelled); + active_event->cancel(); + active_event = NULL; + } + + if (active_timeout > 0) { + active_event = eventProcessor.schedule_in(this, active_timeout); + } +} + +void +PluginVC::set_inactivity_timeout(ink_hrtime timeout_in) +{ + inactive_timeout = timeout_in; + + // FIX - Do we need to handle the case where the timeout is set + // but no io has been done? + if (inactive_event) { + ink_assert(!inactive_event->cancelled); + inactive_event->cancel(); + inactive_event = NULL; + } + + if (inactive_timeout > 0) { + inactive_event = eventProcessor.schedule_in(this, inactive_timeout); + } +} + +void +PluginVC::cancel_active_timeout() +{ + set_active_timeout(0); +} + +void +PluginVC::cancel_inactivity_timeout() +{ + set_inactivity_timeout(0); +} + +ink_hrtime +PluginVC::get_active_timeout() +{ + return active_timeout; +} + +ink_hrtime +PluginVC::get_inactivity_timeout() +{ + return inactive_timeout; +} + +SOCKET +PluginVC::get_socket() +{ + return 0; +} + +void +PluginVC::set_local_addr() +{ + if (vc_type == PLUGIN_VC_ACTIVE) { + local_addr = core_obj->active_addr_struct; + } else { + local_addr = core_obj->passive_addr_struct; + } +} + +void +PluginVC::set_remote_addr() +{ + if (vc_type == PLUGIN_VC_ACTIVE) { + remote_addr = core_obj->passive_addr_struct; + } else { + remote_addr = core_obj->active_addr_struct; + } +} + + +bool +PluginVC::get_data(int id, void *data) +{ + if (data == NULL) { + return false; + } + switch (id) { + case PLUGIN_VC_DATA_LOCAL: + if (vc_type == PLUGIN_VC_ACTIVE) { + *(void **) data = core_obj->active_data; + } else { + *(void **) data = core_obj->passive_data; + } + return true; + case PLUGIN_VC_DATA_REMOTE: + if (vc_type == PLUGIN_VC_ACTIVE) { + *(void **) data = core_obj->passive_data; + } else { + *(void **) data = core_obj->active_data; + } + return true; + default: + *(void **) data = NULL; + return false; + } +} + +bool +PluginVC::set_data(int id, void *data) +{ + switch (id) { + case PLUGIN_VC_DATA_LOCAL: + if (vc_type == PLUGIN_VC_ACTIVE) { + core_obj->active_data = data; + } else { + core_obj->passive_data = data; + } + return true; + case PLUGIN_VC_DATA_REMOTE: + if (vc_type == PLUGIN_VC_ACTIVE) { + core_obj->passive_data = data; + } else { + core_obj->active_data = data; + } + return true; + default: + return false; + } +} + +// PluginVCCore + +vint32 + PluginVCCore::nextid = 0; + +PluginVCCore::~PluginVCCore() +{ +} + +PluginVCCore * +PluginVCCore::alloc() +{ + PluginVCCore *pvc = NEW(new PluginVCCore); + pvc->init(); + return pvc; +} + +void +PluginVCCore::init() +{ + mutex = new_ProxyMutex(); + + active_vc.vc_type = PLUGIN_VC_ACTIVE; + active_vc.other_side = &passive_vc; + active_vc.core_obj = this; + active_vc.mutex = mutex; + active_vc.thread = this_ethread(); + + passive_vc.vc_type = PLUGIN_VC_PASSIVE; + passive_vc.other_side = &active_vc; + passive_vc.core_obj = this; + passive_vc.mutex = mutex; + passive_vc.thread = active_vc.thread; + + p_to_a_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_32K); + p_to_a_reader = p_to_a_buffer->alloc_reader(); + + a_to_p_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_32K); + a_to_p_reader = a_to_p_buffer->alloc_reader(); + + Debug("pvc", "[%u] Created PluginVCCore at 0x%X, active 0x%X, passive 0x%X", id, this, &active_vc, &passive_vc); +} + +void +PluginVCCore::destroy() +{ + + Debug("pvc", "[%u] Destroying PluginVCCore at 0x%X", id, this); + + ink_assert(active_vc.closed == true || !connected); + active_vc.mutex = NULL; + active_vc.read_state.vio.buffer.clear(); + active_vc.write_state.vio.buffer.clear(); + active_vc.magic = PLUGIN_VC_MAGIC_DEAD; + + ink_assert(passive_vc.closed == true || !connected); + passive_vc.mutex = NULL; + passive_vc.read_state.vio.buffer.clear(); + passive_vc.write_state.vio.buffer.clear(); + passive_vc.magic = PLUGIN_VC_MAGIC_DEAD; + + if (p_to_a_buffer) { + free_MIOBuffer(p_to_a_buffer); + p_to_a_buffer = NULL; + } + + if (a_to_p_buffer) { + free_MIOBuffer(a_to_p_buffer); + a_to_p_buffer = NULL; + } + + this->mutex = NULL; + delete this; +} + +void +PluginVCCore::set_accept_cont(Continuation * c) +{ + connect_to = c; + + // FIX ME - must return action +} + +PluginVC * +PluginVCCore::connect() +{ + + // Make sure there is another end to connect to + if (connect_to == NULL) { + return NULL; + } + + connected = true; + state_send_accept(EVENT_IMMEDIATE, NULL); + + return &active_vc; +} + +Action * +PluginVCCore::connect_re(Continuation * c) +{ + + // Make sure there is another end to connect to + if (connect_to == NULL) { + return NULL; + } + + EThread *my_thread = this_ethread(); + MUTEX_TAKE_LOCK(this->mutex, my_thread); + + connected = true; + state_send_accept(EVENT_IMMEDIATE, NULL); + + // We have to take out our mutex because rest of the + // system expects the VC mutex to held when calling back. + // We can use take lock here instead of try lock because the + // lock should never already be held. + + c->handleEvent(NET_EVENT_OPEN, &active_vc); + MUTEX_UNTAKE_LOCK(this->mutex, my_thread); + + return ACTION_RESULT_DONE; +} + +int +PluginVCCore::state_send_accept_failed(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + MUTEX_TRY_LOCK(lock, connect_to->mutex, this_ethread()); + + if (lock) { + connect_to->handleEvent(NET_EVENT_ACCEPT_FAILED, NULL); + destroy(); + } else { + SET_HANDLER(&PluginVCCore::state_send_accept_failed); + eventProcessor.schedule_in(this, PVC_LOCK_RETRY_TIME); + } + + return 0; + +} + +int +PluginVCCore::state_send_accept(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + MUTEX_TRY_LOCK(lock, connect_to->mutex, this_ethread()); + + if (lock) { + connect_to->handleEvent(NET_EVENT_ACCEPT, &passive_vc); + } else { + SET_HANDLER(&PluginVCCore::state_send_accept); + eventProcessor.schedule_in(this, PVC_LOCK_RETRY_TIME); + } + + return 0; +} + + +// void PluginVCCore::attempt_delete() +// +// Mutex must be held when calling this function +// +void +PluginVCCore::attempt_delete() +{ + + if (active_vc.deletable) { + if (passive_vc.deletable) { + destroy(); + } else if (!connected) { + state_send_accept_failed(EVENT_IMMEDIATE, NULL); + } + } +} + +// void PluginVCCore::kill_no_connect() +// +// Called to kill the PluginVCCore when the +// connect call hasn't been made yet +// +void +PluginVCCore::kill_no_connect() +{ + ink_assert(!connected); + ink_assert(!active_vc.closed); + active_vc.do_io_close(); +} + +void +PluginVCCore::set_passive_addr(uint32_t ip, int port) +{ + ((struct sockaddr_in *)&(passive_addr_struct))->sin_addr.s_addr = htonl(ip); + ((struct sockaddr_in *)&(passive_addr_struct))->sin_port = htons(port); +} + +void +PluginVCCore::set_active_addr(uint32_t ip, int port) +{ + ((struct sockaddr_in *)&(active_addr_struct))->sin_addr.s_addr = htonl(ip); + ((struct sockaddr_in *)&(active_addr_struct))->sin_port = htons(port); +} + +void +PluginVCCore::set_passive_data(void *data) +{ + passive_data = data; +} + +void +PluginVCCore::set_active_data(void *data) +{ + active_data = data; +} + +/************************************************************* + * + * REGRESSION TEST STUFF + * + **************************************************************/ + +#if TS_HAS_TESTS +class PVCTestDriver:public NetTestDriver +{ +public: + PVCTestDriver(); + ~PVCTestDriver(); + + void start_tests(RegressionTest * r_arg, int *pstatus_arg); + void run_next_test(); + int main_handler(int event, void *data); + +private: + int i; + int completions_received; +}; + +PVCTestDriver::PVCTestDriver(): +NetTestDriver(), i(0), completions_received(0) +{ +} + +PVCTestDriver::~PVCTestDriver() +{ + mutex = NULL; +} + +void +PVCTestDriver::start_tests(RegressionTest * r_arg, int *pstatus_arg) +{ + mutex = new_ProxyMutex(); + MUTEX_TRY_LOCK(lock, mutex, this_ethread()); + + r = r_arg; + pstatus = pstatus_arg; + + run_next_test(); + + SET_HANDLER(&PVCTestDriver::main_handler); +} + +void +PVCTestDriver::run_next_test() +{ + + int a_index = i * 2; + int p_index = a_index + 1; + + if (p_index >= num_netvc_tests) { + // We are done - // FIX - PASS or FAIL? + if (errors == 0) { + *pstatus = REGRESSION_TEST_PASSED; + } else { + *pstatus = REGRESSION_TEST_FAILED; + } + delete this; + return; + } + completions_received = 0; + i++; + + Debug("pvc_test", "Starting test %s", netvc_tests_def[a_index].test_name); + + NetVCTest *p = NEW(new NetVCTest); + NetVCTest *a = NEW(new NetVCTest); + PluginVCCore *core = PluginVCCore::alloc(); + core->set_accept_cont(p); + + p->init_test(NET_VC_TEST_PASSIVE, this, NULL, r, &netvc_tests_def[p_index], "PluginVC", "pvc_test_detail"); + PluginVC *a_vc = core->connect(); + + a->init_test(NET_VC_TEST_ACTIVE, this, a_vc, r, &netvc_tests_def[a_index], "PluginVC", "pvc_test_detail"); +} + +int +PVCTestDriver::main_handler(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + completions_received++; + + if (completions_received == 2) { + run_next_test(); + } + + return 0; +} + +EXCLUSIVE_REGRESSION_TEST(PVC) (RegressionTest * t, int atype, int *pstatus) +{ + NOWARN_UNUSED(atype); + PVCTestDriver *driver = NEW(new PVCTestDriver); + driver->start_tests(t, pstatus); +} +#endif diff --git a/proxy/PluginVC.h b/proxy/PluginVC.h new file mode 100644 index 00000000..a73199fc --- /dev/null +++ b/proxy/PluginVC.h @@ -0,0 +1,233 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + PluginVC.h + + Description: Allows bi-directional transfer for data from one + continuation to another via a mechanism that impersonates a + NetVC. Should implement all external attributes of NetVConnections. + [See PluginVC.cc for further comments] + + + ****************************************************************************/ + +#ifndef _PLUGIN_VC_H_ +#define _PLUGIN_VC_H_ + +#include "P_Net.h" +#include "ink_atomic.h" + +class PluginVCCore; + +struct PluginVCState +{ + PluginVCState(); + VIO vio; + bool shutdown; +}; + +inline +PluginVCState::PluginVCState(): +vio(), +shutdown(false) +{ +} + +enum PluginVC_t +{ + PLUGIN_VC_UNKNOWN, + PLUGIN_VC_ACTIVE, + PLUGIN_VC_PASSIVE +}; + +// For the id in set_data/get_data +enum +{ + PLUGIN_VC_DATA_LOCAL, + PLUGIN_VC_DATA_REMOTE +}; + +enum +{ + PLUGIN_VC_MAGIC_ALIVE = 0xaabbccdd, + PLUGIN_VC_MAGIC_DEAD = 0xaabbdead +}; + +class PluginVC:public NetVConnection +{ + friend class PluginVCCore; +public: + + PluginVC(); + ~PluginVC(); + + virtual VIO *do_io_read(Continuation * c = NULL, int64_t nbytes = INT64_MAX, MIOBuffer * buf = 0); + + virtual VIO *do_io_write(Continuation * c = NULL, int64_t nbytes = INT64_MAX, IOBufferReader * buf = 0, bool owner = false); + + virtual bool is_over_ssl() + { + return (false); + } + + virtual void do_io_close(int lerrno = -1); + virtual void do_io_shutdown(ShutdownHowTo_t howto); + + // Reenable a given vio. The public interface is through VIO::reenable + virtual void reenable(VIO * vio); + virtual void reenable_re(VIO * vio); + + // Timeouts + virtual void set_active_timeout(ink_hrtime timeout_in); + virtual void set_inactivity_timeout(ink_hrtime timeout_in); + virtual void cancel_active_timeout(); + virtual void cancel_inactivity_timeout(); + virtual ink_hrtime get_active_timeout(); + virtual ink_hrtime get_inactivity_timeout(); + + // Pure virutal functions we need to compile + virtual SOCKET get_socket(); + virtual void set_local_addr(); + virtual void set_remote_addr(); + + virtual bool get_data(int id, void *data); + virtual bool set_data(int id, void *data); + + virtual PluginVC* get_other_side() { return other_side; } + + int main_handler(int event, void *data); + +private: + void process_read_side(bool); + void process_write_side(bool); + void process_close(); + void process_timeout(Event * e, int event_to_send, Event ** our_eptr); + + void setup_event_cb(ink_hrtime in, Event ** e_ptr); + + void update_inactive_time(); + int64_t transfer_bytes(MIOBuffer * transfer_to, IOBufferReader * transfer_from, int64_t act_on); + + uint32_t magic; + PluginVC_t vc_type; + PluginVCCore *core_obj; + + PluginVC *other_side; + + PluginVCState read_state; + PluginVCState write_state; + + bool need_read_process; + bool need_write_process; + + volatile bool closed; + Event *sm_lock_retry_event; + Event *core_lock_retry_event; + + bool deletable; + int reentrancy_count; + + ink_hrtime active_timeout; + ink_hrtime inactive_timeout; + Event *active_event; + Event *inactive_event; + +}; + +class PluginVCCore:public Continuation +{ + friend class PluginVC; +public: + PluginVCCore(); + ~PluginVCCore(); + + static PluginVCCore *alloc(); + void init(); + void set_accept_cont(Continuation * c); + + int state_send_accept(int event, void *data); + int state_send_accept_failed(int event, void *data); + + void attempt_delete(); + + PluginVC *connect(); + Action *connect_re(Continuation * c); + void kill_no_connect(); + + void set_active_addr(uint32_t ip, int port); + void set_passive_addr(uint32_t ip, int port); + + void set_active_data(void *data); + void set_passive_data(void *data); + +private: + + void destroy(); + + // The active vc is handed to the initiator of + // connection. The passive vc is handled to + // receiver of the connection + PluginVC active_vc; + PluginVC passive_vc; + Continuation *connect_to; + bool connected; + + MIOBuffer *p_to_a_buffer; + IOBufferReader *p_to_a_reader; + + MIOBuffer *a_to_p_buffer; + IOBufferReader *a_to_p_reader; + + struct sockaddr_storage passive_addr_struct; + struct sockaddr_storage active_addr_struct; + + void *passive_data; + void *active_data; + + static vint32 nextid; + unsigned id; +}; + +inline +PluginVCCore::PluginVCCore(): +active_vc(), +passive_vc(), +connect_to(NULL), +connected(false), +p_to_a_buffer(NULL), +p_to_a_reader(NULL), +a_to_p_buffer(NULL), +a_to_p_reader(NULL), +passive_data(NULL), +active_data(NULL), +id(0) +{ + memset(&active_addr_struct, 0, sizeof(struct sockaddr_storage)); + memset(&passive_addr_struct, 0, sizeof(struct sockaddr_storage)); + + id = ink_atomic_increment(&nextid, 1); +} + +#endif diff --git a/proxy/Prefetch.cc b/proxy/Prefetch.cc new file mode 100644 index 00000000..b1c7c41a --- /dev/null +++ b/proxy/Prefetch.cc @@ -0,0 +1,2205 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + + +#include "Prefetch.h" +#include "HdrUtils.h" +#include "HttpCompat.h" +#include "I_Layout.h" + +#ifdef PREFETCH + +struct html_tag prefetch_allowable_html_tags[] = { + //All embedded objects (fetched by the browser without requiring a click) + //should be here + //{ "a", "href"}, /* NOT USED */ + {"img", "src"}, + {"body", "background"}, + {"frame", "src"}, + {"fig", "src"}, + {"applet", "code"}, + {"script", "src"}, + {"embed", "src"}, + {"td", "background"}, + {"base", "href"}, // special handling + {"meta", "content"}, // special handling + //{ "area", "href"}, //used for testing parser + {"input", "src"}, + {"link", "href"}, + {NULL, NULL} +}; + +// this attribute table is hard coded. It has to be the same size as +// the prefetch_allowable_html_tags table +struct html_tag prefetch_allowable_html_attrs[] = { + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {NULL, NULL}, + {"rel", "stylesheet"}, // We want to prefetch the .css files that are common; make sure this matches {"link", "href"} + {NULL, NULL} +}; + +static const char *PREFETCH_FIELD_RECURSION; +static int PREFETCH_FIELD_LEN_RECURSION; + +PrefetchProcessor prefetchProcessor; +KeepAliveConnTable *g_conn_table; + +static int prefetch_udp_fd = 0; +static int32_t udp_seq_no; + +static inline uint32_t +get_udp_seq_no() +{ + return ink_atomic_increment(&udp_seq_no, 1); +} + +static inline void +setup_udp_header(char *header, uint32_t seq_no, uint32_t pkt_no, bool last_pkt) +{ + uint32_t *hdr = (uint32_t *) header; + hdr[0] = 0; + hdr[1] = htonl(seq_no); + hdr[2] = htonl((last_pkt ? PRELOAD_UDP_LAST_PKT_FLAG : 0) | (pkt_no & PRELOAD_UDP_PKT_NUM_MASK)); +} + +static inline void +setup_object_header(char *header, int64_t size, bool url_promise) +{ + uint32_t *hdr = (uint32_t *) header; + hdr[0] = htonl(size); + hdr[1] = 0; //we are not pinning + hdr[2] = (url_promise) ? htonl(PRELOAD_HDR_URL_PROMISE_FLAG) : 0; +} + +// Raghu's info about domain extraction +inline const char * +findDomainFromHost(const char *host, int host_len, bool & no_dot) +{ + const char *h_cur = host + host_len - 1; + + if (host_len > 4) { + // checking for .com .edu .net .org .gov .mil .int + h_cur = host + host_len - 4; + if (*h_cur == '.') { + // convert to lower case + char c3 = *(h_cur + 1); + char c1 = (c3 >= 'A' && c3 <= 'Z') ? (c3 + 'a' - 'A') : c3; + c3 = *(h_cur + 2); + char c2 = (c3 >= 'A' && c3 <= 'Z') ? (c3 + 'a' - 'A') : c3; + c3 = *(h_cur + 3); + if (c3 >= 'A' && c3 <= 'Z') + c3 += 'a' - 'A'; + + // there is a high posibility that the postfix is one of the seven + if ((c1 == 'c' && c2 == 'o' && c3 == 'm') || + (c1 == 'e' && c2 == 'd' && c3 == 'u') || + (c1 == 'n' && c2 == 'e' && c3 == 't') || + (c1 == 'o' && c2 == 'r' && c3 == 'g') || + (c1 == 'g' && c2 == 'o' && c3 == 'v') || + (c1 == 'm' && c2 == 'i' && c3 == 'l') || (c1 == 'i' && c2 == 'n' && c3 == 't')) { + h_cur--; + + while (h_cur != host) { + if (*h_cur == '.') + break; + h_cur--; + } + if (h_cur != host) { + // found a '.' + h_cur++; + } else if (*h_cur == '.') + return NULL; + + return h_cur; + } + } + } + // for non-top level domains, require the first char is not '.' and + // two '.' minimum, e.g. abc.va.us + int num_dots = 0; + while (h_cur != host) { + if (*h_cur == '.') { + num_dots++; + if (num_dots == 3) { + h_cur++; + return h_cur; + } + } + h_cur--; + } + + if (num_dots < 2 || *host == '.') { + if (num_dots == 0) + no_dot = true; + return NULL; + } else + return h_cur; +} + +static int +normalize_url(char *url, int *len) +{ + /* returns > 0 if the url is modified */ + + char *p, *root, *end = url + len[0]; + int modified = 0; // most of the time we don't modify the url. + + enum + { + NONE, + FIRST_DOT, + SECOND_DOT, + SLASH + } state; + + if (!(p = strstr(url, "://"))) + return -1; + p += 3; + + //get to the first slash: + root = (p = strchr(p, '/')); + + if (!root) + return 0; + + state = SLASH; + + while (++p <= end) { + + switch (p[0]) { + + case '\0': + case '/': + switch (state) { + + case SLASH: // "//" => "/" + if (p[0]) { + modified = 1; + p[0] = 0; + } + break; + + case FIRST_DOT: // "/./" => "/" + modified = 1; + p[0] = (p[-1] = 0); + break; + + case SECOND_DOT:{ // "/dir/../" or "/../" => "/" + modified = 1; + p[0] = (p[-1] = (p[-2] = 0)); + + char *dir = p - 3; + while (dir[0] == 0 && dir > root) + dir--; + + ink_debug_assert(dir[0] == '/'); + if (dir > root && dir[0] == '/') { + do { + dir[0] = 0; + } while (*--dir != '/'); + } + } + break; + default: /* NONE */ ; + }; /* end of switch (state) */ + + state = SLASH; + break; + + case '.': + switch (state) { + case SLASH: + state = FIRST_DOT; + break; + case FIRST_DOT: + state = SECOND_DOT; + break; + default: + state = NONE; + } + break; + + default: + state = NONE; + } + } + + if (modified) { + //ok, now remove all the 0s in between + p = ++root; + + while (p < end) { + if (p[0]) { + *root++ = p[0]; + } else + len[0]--; + p++; + } + *root = 0; + return 1; + } + + return 0; +} + +static PrefetchConfiguration prefetch_config; +ClassAllocator prefetchUrlEntryAllocator("prefetchUrlEntryAllocator"); + +#define HTTP_STATUS_MOVED_PERMANENTLY 301 +#define HTTP_STATUS_MOVED_TEMPORARILY 302 +#define HTTP_STATUS_SEE_OTHER 303 +#define HTTP_STATUS_TEMPORARY_REDIRECT 307 + + +#define IS_STATUS_REDIRECT(status) (prefetch_config.redirection > 0 &&\ + (((status) == HTTP_STATUS_MOVED_PERMANENTLY) ||\ + ((status) == HTTP_STATUS_MOVED_TEMPORARILY) ||\ + ((status) == HTTP_STATUS_SEE_OTHER) ||\ + (((status) == HTTP_STATUS_TEMPORARY_REDIRECT)))) + + +PrefetchTransform::PrefetchTransform(HttpSM *sm, HTTPHdr *resp) + : INKVConnInternal(NULL, reinterpret_cast((ProxyMutex*)sm->mutex)), + m_output_buf(NULL), m_output_vio(NULL), m_sm(sm) +{ + refcount_inc(); + + HTTPHdr *request = &sm->t_state.hdr_info.client_request; + url = request->url_get()->string_get(NULL, NULL); + + html_parser.Init(url, prefetch_config.html_tags_table, prefetch_config.html_attrs_table); + + SET_HANDLER(&PrefetchTransform::handle_event); + + Debug("PrefetchParser", "Created: transform for %s\n", url); + + memset(&hash_table[0], 0, HASH_TABLE_LENGTH * sizeof(hash_table[0])); + + udp_url_list = blasterUrlListAllocator.alloc(); + udp_url_list->init(UDP_BLAST, prefetch_config.url_buffer_timeout, prefetch_config.url_buffer_size); + tcp_url_list = blasterUrlListAllocator.alloc(); + tcp_url_list->init(TCP_BLAST, prefetch_config.url_buffer_timeout, prefetch_config.url_buffer_size); + + //extract domain + host_start = request->url_get()->host_get(&host_len); + + if (!host_start || !host_len) + host_start = request->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &host_len); + + no_dot_in_host = false; + if (host_start && host_len) { + domain_end = host_start + (host_len - 1); + domain_start = findDomainFromHost(host_start, host_len, no_dot_in_host); + } else + domain_start = 0; + + // Check for redirection and redirect get the redirect URL before parsing the + // body of the redirect. + redirect(resp); +} + +PrefetchTransform::~PrefetchTransform() +{ + //inform the lists that there no more urls left. + this_ethread()->schedule_imm_local(udp_url_list); + this_ethread()->schedule_imm_local(tcp_url_list); + + Debug("PrefetchParserURLs", "Unique URLs 0x%p (%s):\n", this, url); + int nurls = 0; + for (int i = 0; i < HASH_TABLE_LENGTH; i++) { + PrefetchUrlEntry *e = hash_table[i]; + while (e) { + Debug("PrefetchParserURLs", "(0x%p) %d: %s\n", this, i, e->url); + nurls++; + PrefetchUrlEntry *next = e->hash_link; + e->free(); + e = next; + } + } + + Debug("PrefetchParserURLs", "Number of embedded objects extracted for %s: %d\n", url, nurls); + + if (m_output_buf) + free_MIOBuffer(m_output_buf); + if (url) + xfree(url); +} + +int +PrefetchTransform::handle_event(int event, void *edata) +{ + handle_event_count(event); + + if (m_closed) { + if (m_deletable) { + Debug("PrefetchParser", "PrefetchTransform free(): %d", m_output_vio ? m_output_vio->ndone : 0); + if (m_output_buf) { + free_MIOBuffer(m_output_buf); + m_output_buf = 0; + } + Debug("Prefetch", "Freeing after closed %p", this); + free(); + } + } else { + switch (event) { + case VC_EVENT_ERROR: + m_write_vio._cont->handleEvent(VC_EVENT_ERROR, &m_write_vio); + break; + + case VC_EVENT_WRITE_COMPLETE: + + Debug("Prefetch", "got write_complete %p", this); + ink_assert(m_output_vio == (VIO *) edata); + + ink_assert(m_write_vio.ntodo() == 0); + + m_output_vc->do_io_shutdown(IO_SHUTDOWN_WRITE); + break; + + case VC_EVENT_WRITE_READY: + default:{ + + if (!m_output_vio) { + m_output_buf = new_empty_MIOBuffer(); + m_output_reader = m_output_buf->alloc_reader(); + m_output_vio = m_output_vc->do_io_write(this, INT64_MAX, m_output_reader); + } + // If the write vio is null, it means it doesn't want + // to get anymore event (WRITE_READY or WRITE_COMPLETE) + // It also means we're done reading + if (m_write_vio.op == VIO::NONE) { + m_output_vio->nbytes = m_write_vio.ndone; + m_output_vio->reenable(); + return 0; + } + + ink_assert(m_output_vc != NULL); + + MUTEX_TRY_LOCK(trylock, m_write_vio.mutex, this_ethread()); + if (!trylock) { + retry(10); + return 0; + } + + if (m_closed) { + return 0; + } + + int64_t towrite = m_write_vio.ntodo(); + + if (towrite > 0) { + IOBufferReader *buf_reader = m_write_vio.get_reader(); + int64_t avail = buf_reader->read_avail(); + + if (towrite > avail) { + towrite = avail; + } + + if (towrite > 0) { + Debug("PrefetchParser", "handle_event() " "writing %d bytes to output", towrite); + + //Debug("PrefetchParser", "Read avail before = %d\n", avail); + + m_output_buf->write(buf_reader, towrite); + + parse_data(buf_reader); + + //buf_reader->consume (towrite); + m_write_vio.ndone += towrite; + } + } + + if (m_write_vio.ntodo() > 0) { + if (towrite > 0) { + m_output_vio->reenable(); + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_READY, &m_write_vio); + } + } else { + m_output_vio->nbytes = m_write_vio.ndone; + m_output_vio->reenable(); + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_COMPLETE, &m_write_vio); + } + + break; + } + } + } + return 0; +} + +int +PrefetchTransform::redirect(HTTPHdr *resp) +{ + HTTPHdr *req = NULL; + int response_status = 0; + char *req_url = NULL; + char *redirect_url = NULL; + + /* Check for responses validity. If the response is valid, determine the status of the response. + We need to find out if there was a redirection (301, 302, 303, 307). + */ + if ((resp != NULL) && (resp->valid())) { + response_status = resp->status_get(); + } else { + response_status = -1; + } + + /* OK, so we got the response. Now if the response is a redirect we have to check if we also + got a Location: header. This indicates the new location where our object is located. + If refirect_url was not found, letz falter back to just a recursion. Since + we might find the url in the body. + */ + if (resp->presence(MIME_PRESENCE_LOCATION)) { + int redirect_url_len = 0; + const char *tmp_url = resp->value_get(MIME_FIELD_LOCATION, MIME_LEN_LOCATION, &redirect_url_len); + + redirect_url = (char *) xmalloc(redirect_url_len + 1); + strncpy(redirect_url, tmp_url, redirect_url_len); + redirect_url[redirect_url_len] = '\0'; + Debug("PrefetchTransform", "redirect_url = %s\n", redirect_url); + } else { + response_status = -1; + } + + + + + if (IS_STATUS_REDIRECT(response_status)) { + if (redirect_url) { + + req = &m_sm->t_state.hdr_info.client_request; + req_url = req->url_get()->string_get(NULL, NULL); + + Debug("PrefetchTransform", "Received response status = %d\n", response_status); + Debug("PrefetchTransform", "Redirect from request = %s\n", req_url); + + int location_len = strlen(redirect_url); + Debug("PrefetchTransform", "Redirect url to HTTP Hdr Location: \'%s\'\n", redirect_url); + if (strncmp(redirect_url, req_url, location_len) == 0) { + Debug("PrefetchTransform", "'%s' -> '%s' - Could be a loop. Discontinuing this path.\n", req_url, redirect_url); + xfree(redirect_url); + xfree(req_url); + return 0; + } + + PrefetchUrlEntry *entry = hash_add(redirect_url); + + if (!entry) { + Debug("PrefetchParserURLs", "Ignoring duplicate url '%s'", redirect_url); + xfree(redirect_url); + xfree(req_url); + return 0; + } + + Debug("PrefetchTransform", "Found embedded URL: %s", redirect_url); + entry->req_ip = m_sm->t_state.client_info.ip; + + PrefetchBlaster *blaster = prefetchBlasterAllocator.alloc(); + blaster->init(entry, &m_sm->t_state.hdr_info.client_request, this); + if (req_url) + xfree(req_url); + } + } + if (redirect_url) + xfree(redirect_url); + return 0; +} + +int +PrefetchTransform::parse_data(IOBufferReader *reader) +{ + char *url_start = NULL, *url_end = NULL; + + while (html_parser.ParseHtml(reader, &url_start, &url_end)) { + + PrefetchUrlEntry *entry = hash_add(url_start); + + if (!entry) { + //Debug("PrefetchParserURLs", "Duplicate URL: %s", url_start); + continue; + } + //Debug("PrefetchParserURLs", "Found embedded URL: %s", url_start); + entry->req_ip = m_sm->t_state.client_info.ip; + + PrefetchBlaster *blaster = prefetchBlasterAllocator.alloc(); + blaster->init(entry, &m_sm->t_state.hdr_info.client_request, this); + } + + return 0; +} + +PrefetchUrlEntry * +PrefetchTransform::hash_add(char *s) +{ + uint32_t index = 0; + int str_len = strlen(s); + + if (normalize_url(s, &str_len) > 0) + Debug("PrefetchParserURLs", "Normalized URL: %s\n", s); + + + INK_MD5 md5; + md5.encodeBuffer(s, str_len); + index = md5.word(1) % HASH_TABLE_LENGTH; + + PrefetchUrlEntry **e = &hash_table[index]; + for (; *e; e = &(*e)->hash_link) + if (strcmp((*e)->url, s) == 0) + return NULL; + + *e = prefetchUrlEntryAllocator.alloc(); + (*e)->init(xstrdup(s), md5); + + return *e; +} + +#define IS_RECURSIVE_PREFETCH(req_ip) (prefetch_config.max_recursion > 0 &&\ + (req_ip) == htonl((127<<24)|1)) + +static void +check_n_attach_prefetch_transform(HttpSM *sm, HTTPHdr *resp, bool from_cache) +{ + INKVConnInternal *prefetch_trans; + + unsigned int client_ip = sm->t_state.client_info.ip; + + Debug("PrefetchParser", "Checking response for request from %u.%u.%u.%u\n", IPSTRARGS(client_ip)); + + unsigned int rec_depth = 0; + HTTPHdr *request = &sm->t_state.hdr_info.client_request; + + if (IS_RECURSIVE_PREFETCH(client_ip)) { + rec_depth = request->value_get_int(PREFETCH_FIELD_RECURSION, PREFETCH_FIELD_LEN_RECURSION); + rec_depth++; + + Debug("PrefetchTemp", "recursion: %d", rec_depth); + + if (rec_depth > prefetch_config.max_recursion) { + Debug("PrefetchParserRecursion", "Recursive parsing is not done " + "since recursion depth(%d) is greater than max allowed (%d)", rec_depth, prefetch_config.max_recursion); + return; + } + } else if (!prefetch_config.ip_range.match(client_ip)) { + Debug("PrefetchParser", "client (%u.%u.%u.%u) does not match any of the " + "prefetch_children mentioned in configuration\n", IPSTRARGS(client_ip)); + return; + } + + if (prefetch_config.max_recursion > 0) { + request->value_set_int(PREFETCH_FIELD_RECURSION, PREFETCH_FIELD_LEN_RECURSION, rec_depth); + } + + int c_type_len; + const char *c_type = resp->value_get(MIME_FIELD_CONTENT_TYPE, + MIME_LEN_CONTENT_TYPE, &c_type_len); + + if ((c_type == NULL) || strncmp("text/html", c_type, 9) != 0) { + Debug("PrefetchParserCT", "Content type is not text/html.. skipping\n"); + return; + } + + /* skip if it is encoded */ + c_type = resp->value_get(MIME_FIELD_CONTENT_ENCODING, MIME_LEN_CONTENT_ENCODING, &c_type_len); + if (c_type) { + char type[64]; + memcpy(type, c_type, c_type_len); + type[c_type_len] = 0; + Debug("PrefetchParserCT", "Content is encoded with %s .. skipping\n", type); + return; + } + + Debug("PrefetchParserCT", "Content type is text/html\n"); + + if (prefetch_config.pre_parse_hook) { + TSPrefetchInfo info; + + HTTPHdr *req = &sm->t_state.hdr_info.client_request; + info.request_buf = reinterpret_cast(req); + info.request_loc = reinterpret_cast(req->m_http); + info.response_buf = reinterpret_cast(resp); + info.response_loc = reinterpret_cast(resp->m_http); + + info.client_ip = client_ip; + info.embedded_url = 0; + info.present_in_cache = from_cache; + info.url_proto = 0; + info.url_response_proto = 0; + + info.object_buf = 0; + info.object_buf_reader = 0; + info.object_buf_status = TS_PREFETCH_OBJ_BUF_NOT_NEEDED; + + int ret = (prefetch_config.pre_parse_hook) (TS_PREFETCH_PRE_PARSE_HOOK, &info); + if (ret == TS_PREFETCH_DISCONTINUE) + return; + } + //now insert the parser + prefetch_trans = NEW(new PrefetchTransform(sm, resp)); + + if (prefetch_trans) { + Debug("PrefetchParser", "Adding Prefetch Parser 0x%p\n", prefetch_trans); + TSHttpTxnHookAdd(reinterpret_cast(sm), TS_HTTP_RESPONSE_TRANSFORM_HOOK, reinterpret_cast(prefetch_trans)); + + DUMP_HEADER("PrefetchParserHdrs", &sm->t_state.hdr_info.client_request, (int64_t)0, + "Request Header given for Prefetch Parser"); + } +} + + +static int +PrefetchPlugin(TSCont contp, TSEvent event, void *edata) +{ + NOWARN_UNUSED(contp); + HttpSM *sm = (HttpSM *) edata; + HTTPHdr *resp = 0; + bool from_cache = false; + + switch (event) { + + case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:{ + + Debug("PrefetchPlugin", "Received TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK " "event (sm = 0x%p)\n", sm); + int status; + TSHttpTxnCacheLookupStatusGet((TSHttpTxn) sm, &status); + + if (status == TS_CACHE_LOOKUP_HIT_FRESH) { + Debug("PrefetchPlugin", "Cached object is fresh\n"); + resp = sm->t_state.cache_info.object_read->response_get(); + from_cache = true; + } else { + Debug("PrefetchPlugin", "Cache lookup did not succeed\n"); + } + + break; + } + case TS_EVENT_HTTP_READ_RESPONSE_HDR: + Debug("PrefetchPlugin", "Received TS_EVENT_HTTP_READ_RESPONSE_HDR " "event (sm = 0x%p)\n", sm); + resp = &sm->t_state.hdr_info.server_response; + + break; + + default: + Debug("PrefetchPlugin", "Error: Received unexpected event\n"); + return 0; + } + + if (resp && resp->valid()) + check_n_attach_prefetch_transform(sm, resp, from_cache); + + TSHttpTxnReenable(reinterpret_cast(sm), TS_EVENT_HTTP_CONTINUE); + + //Debug("PrefetchPlugin", "Returning after check_n_attach_prefetch_transform()\n"); + + return 0; +} + +void +PrefetchProcessor::start() +{ + prefetch_config.readConfiguration(); + + if (prefetch_config.prefetch_enabled) { + + PREFETCH_FIELD_RECURSION = "@InkPrefetch"; + PREFETCH_FIELD_LEN_RECURSION = strlen(PREFETCH_FIELD_RECURSION); + //hdrtoken_wks_to_length(PREFETCH_FIELD_RECURSION); + + g_conn_table = NEW(new KeepAliveConnTable); + g_conn_table->init(); + + udp_seq_no = this_ethread()->generator.random(); + + prefetch_udp_fd = socketManager.socket(PF_INET, SOCK_DGRAM, 0); + + TSCont contp = TSContCreate(PrefetchPlugin, NULL); + TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, contp); + TSHttpHookAdd(TS_HTTP_READ_RESPONSE_HDR_HOOK, contp); + + Note("PrefetchProcessor: Started the prefetch processor\n"); + } else { + Debug("PrefetchProcessor", "Prefetch processor is not started\n"); + } + + +} + +//Blaster + +ClassAllocator blasterUrlListAllocator("blasterUrlList"); + +int +BlasterUrlList::handleEvent(int event, void *data) +{ + switch (event) { + + case EVENT_INTERVAL: + ink_assert(list_head); + if (list_head) { + invokeUrlBlaster(); + } + action = NULL; + break; + + case EVENT_IMMEDIATE: + /* + PrefetchTransform informed us not to expect any more URLs + This is used so that we dont wait for timeout when the mtu has not filled + but theren't any URLs left in the page. + */ + if (list_head) { + action->cancel(); + action = NULL; + invokeUrlBlaster(); + } + free(); // we need to call free because PrefetchTransform does not. + break; + + case PREFETCH_EVENT_SEND_URL:{ + PrefetchUrlEntry *entry = ((PrefetchUrlEntry *) data)->assign(); + + if (list_head) { + action->cancel(); + action = NULL; + if ((cur_len + entry->len) > mtu) { + invokeUrlBlaster(); + } + } + + entry->blaster_link = list_head; //will be reversed before sending + list_head = entry; + cur_len += entry->len; + + if (cur_len >= mtu || timeout == 0) { + invokeUrlBlaster(); + } else { + action = this_ethread()->schedule_in(this, HRTIME_MSECONDS(timeout)); + } + + break; + } + + default: + ink_assert(!"not reached"); + } + + return EVENT_DONE; +} + +ClassAllocator prefetchUrlBlasterAllocator("prefetchUrlBlaster"); + +inline void +PrefetchUrlBlaster::free() +{ + if (action) + action->cancel(); + + //free the list; + while (url_head) { + PrefetchUrlEntry *next = url_head->blaster_link; + this_ethread()->schedule_imm(url_head->resp_blaster); + url_head->free(); + url_head = next; + } + + mutex.clear(); + prefetchUrlBlasterAllocator.free(this); +} + +void +PrefetchUrlBlaster::writeBuffer(MIOBuffer *buf) +{ + //reverse the list: + PrefetchUrlEntry *entry = NULL; + //int total_len = 0; + while (url_head) { + //total_len += url_head->len; + + PrefetchUrlEntry *next = url_head->blaster_link; + url_head->blaster_link = entry; + entry = url_head; + url_head = next; + } + url_head = entry; + + int nurls = 0; + //write it: + while (entry) { + buf->write(entry->url, entry->len); + entry = entry->blaster_link; + nurls++; + } + Debug("PrefetchBlasterUrlList", "found %d urls in the list", nurls); + return; +} + +int +PrefetchUrlBlaster::udpUrlBlaster(int event, void *data) +{ + switch (event) { + + case SIMPLE_EVENT_EVENTS_START:{ + SET_HANDLER((EventHandler) (&PrefetchUrlBlaster::udpUrlBlaster)); + + MIOBuffer *buf = new_MIOBuffer(); + IOBufferReader *reader = buf->alloc_reader(); + + int udp_hdr_len = (proto == TCP_BLAST) ? 0 : PRELOAD_UDP_HEADER_LEN; + + buf->fill(udp_hdr_len + PRELOAD_HEADER_LEN); + + writeBuffer(buf); + + + if (proto == TCP_BLAST) { + setup_object_header(reader->start(), reader->read_avail(), true); + g_conn_table->append(url_head->child_ip, buf, reader); + free(); + } else { + + IOBufferBlock *block = buf->get_current_block(); + ink_assert(reader->read_avail() == block->read_avail()); + setup_udp_header(block->start(), get_udp_seq_no(), 0, true); + setup_object_header(block->start() + PRELOAD_UDP_HEADER_LEN, block->read_avail() - PRELOAD_UDP_HEADER_LEN, true); + + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(prefetch_config.stuffer_port); + if (url_head->url_multicast_ip) + saddr.sin_addr.s_addr = url_head->url_multicast_ip; + else + saddr.sin_addr.s_addr = url_head->child_ip; + //saddr.sin_addr.s_addr = htonl((209<<24)|(131<<16)|(60<<8)|243); + //saddr.sin_addr.s_addr = htonl((209<<24)|(131<<16)|(48<<8)|52); + + udpNet.sendto_re(this, NULL, prefetch_udp_fd, (sockaddr *) & saddr, sizeof(saddr), block, block->read_avail()); + } + break; + } + + case NET_EVENT_DATAGRAM_WRITE_ERROR: + Debug("PrefetchBlaster", "Error in sending the url list on UDP (%p)", data); + case NET_EVENT_DATAGRAM_WRITE_COMPLETE: + free(); + break; + } + return EVENT_DONE; +} + +ClassAllocator prefetchBlasterAllocator("PrefetchBlasterAllocator"); + +int +PrefetchBlaster::init(PrefetchUrlEntry *entry, HTTPHdr *req_hdr, PrefetchTransform *p_trans) +{ + mutex = new_ProxyMutex(); + + //extract host and the path + // by this time, the url is sufficiently error checked.. + // we will just use sscanf to parse it: + //int host_pos=-1, path_pos=-1; + int url_len = strlen(entry->url); + + request = NEW(new HTTPHdr); + request->copy(req_hdr); + url_clear(request->url_get()->m_url_impl); /* BugID: INKqa11148 */ + //request->url_get()->clear(); + + // INKqa12871 + request->field_delete(MIME_FIELD_HOST, MIME_LEN_HOST); + request->field_delete(MIME_FIELD_IF_MATCH, MIME_LEN_IF_MATCH); + request->field_delete(MIME_FIELD_IF_MODIFIED_SINCE, MIME_LEN_IF_MODIFIED_SINCE); + request->field_delete(MIME_FIELD_IF_NONE_MATCH, MIME_LEN_IF_NONE_MATCH); + request->field_delete(MIME_FIELD_IF_RANGE, MIME_LEN_IF_RANGE); + request->field_delete(MIME_FIELD_IF_UNMODIFIED_SINCE, MIME_LEN_IF_UNMODIFIED_SINCE); + request->field_delete(MIME_FIELD_CACHE_CONTROL, MIME_LEN_CACHE_CONTROL); + // BZ 50540 + request->field_delete(MIME_FIELD_CONTENT_LENGTH, MIME_LEN_CONTENT_LENGTH); + + int temp; + if (request->url_get()->parse(entry->url, url_len) != PARSE_DONE || + request->url_get()->scheme_get(&temp) != URL_SCHEME_HTTP) { + Debug("PrefetchParserURLs", "URL parsing failed or scheme is not HTTP " "for %s", entry->url); + free(); + return -1; + } + + request->method_set(HTTP_METHOD_GET, HTTP_LEN_GET); + + request->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION); + request->value_set(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION, "close", 5); + + // INKqa12871 + if (request->field_find(MIME_FIELD_REFERER, MIME_LEN_REFERER)) { + int topurl_len; + char *topurl = req_hdr->url_get()->string_get(NULL, &topurl_len); + if (topurl) { + request->value_set(MIME_FIELD_REFERER, MIME_LEN_REFERER, topurl, topurl_len); + xfree(topurl); + } + } + + if (request->field_find(MIME_FIELD_AUTHORIZATION, MIME_LEN_AUTHORIZATION)) { + int host_len; + bool delete_auth; + const char *host_start = request->url_get()->host_get(&host_len); + + if (host_start == NULL) + delete_auth = true; + else { + const char *host_end = host_start + host_len - 1; + int cmp_len = p_trans->domain_end - p_trans->domain_start + 1; + + if (cmp_len <= 0 || host_len cmp_len && host_start[host_len - cmp_len - 1] != '.') || //nbc.com != cnbc.com + strncasecmp(p_trans->domain_start, host_end - (cmp_len - 1), cmp_len) != 0) { + delete_auth = true; + } else + delete_auth = false; + } + + if (delete_auth) + request->field_delete(MIME_FIELD_AUTHORIZATION, MIME_LEN_AUTHORIZATION); + } + //Should we remove any cookies? Probably yes + //We should probably add a referer header. + handleCookieHeaders(req_hdr, + &p_trans->m_sm->t_state.hdr_info.server_response, + p_trans->domain_start, p_trans->domain_end, + p_trans->host_start, p_trans->host_len, p_trans->no_dot_in_host); + + int ip_len; + const char *ip_str; + if (IS_RECURSIVE_PREFETCH(entry->req_ip) && + (ip_str = request->value_get(MIME_FIELD_CLIENT_IP, MIME_LEN_CLIENT_IP, &ip_len))) { + //this is a recursive prefetch. get child ip address from + //Client-IP header + if (ip_len > 15) + ip_len = 15; + + char ip_buf[16]; + strncpy(ip_buf, ip_str, ip_len); + ip_buf[ip_len] = '\0'; + + entry->child_ip = inet_addr(ip_buf); + } else + entry->child_ip = entry->req_ip; + + DUMP_HEADER("PrefetchBlasterHdrs", request, (int64_t)0, "Request Header from Prefetch Blaster"); + + url_ent = entry->assign(); //refcount + transform = p_trans->assign(); + + buf = new_MIOBuffer(); + reader = buf->alloc_reader(); + + SET_HANDLER((EventHandler) (&PrefetchBlaster::handleEvent)); + + this_ethread()->schedule_imm(this); + + return EVENT_DONE; +} + +void +PrefetchBlaster::free() +{ + if (serverVC) + serverVC->do_io_close(); + + if (url_ent) + url_ent->free(); + if (transform) + transform->free(); + + if (buf) + free_MIOBuffer(buf); + if (io_block) { + io_block->free(); + } + + if (request) { + request->destroy(); + delete request; + } + + mutex.clear(); + prefetchBlasterAllocator.free(this); +} + +bool +isCookieUnique(HTTPHdr *req, const char *move_cookie, int move_cookie_len) +{ + // another double for loop for multiple Cookie headers + MIMEField *o_cookie = req->field_find(MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + const char *a_raw; + int a_raw_len; + const char *iter_cookie; + int iter_cookie_len; + bool equalsign = false; + + if ((a_raw = (const char *) memchr(move_cookie, '=', move_cookie_len)) != NULL) { + int tmp_len = (int) (a_raw - move_cookie) + 1; + if (tmp_len < move_cookie_len) { + equalsign = true; + move_cookie_len = tmp_len; + } + } + + for (; o_cookie; o_cookie = o_cookie->m_next_dup) { + a_raw = o_cookie->value_get(&a_raw_len); + if (a_raw != NULL && a_raw_len > 0) { + StrList a_param_list; + Str *a_param; + + HttpCompat::parse_tok_list(&a_param_list, 0, a_raw, a_raw_len, ';'); + for (a_param = a_param_list.head; a_param; a_param = a_param->next) { + iter_cookie = a_param->str; + iter_cookie_len = a_param->len; + + if (equalsign) { + if (iter_cookie_len > move_cookie_len && memcmp(iter_cookie, move_cookie, move_cookie_len) == 0) { + // INKqa11823 id=new to replace id=old + return false; + } + } else { + if (iter_cookie_len == move_cookie_len && memcmp(iter_cookie, move_cookie, iter_cookie_len) == 0) { + // dupliate - do not add + return false; + } + } + } + } + } + + return true; +} + +inline void +cookie_debug(const char *level, const char *value, int value_len) +{ + if (is_debug_tag_set("PrefetchCookies")) { + char *str = (char *) xmalloc(value_len + 1); + memcpy(str, value, value_len); + str[value_len] = 0; + Debug("PrefetchCookies", "Processing %s value: %s", level, str); + if (str) + xfree(str); + } +} + +// resp_hdr is the server response for the top page +void +PrefetchBlaster::handleCookieHeaders(HTTPHdr *req_hdr, + HTTPHdr *resp_hdr, + const char *domain_start, + const char *domain_end, const char *thost_start, int thost_len, bool no_dot) +{ + bool add_cookies = true; + bool existing_req_cookies = request->valid() && request->presence(MIME_PRESENCE_COOKIE); + bool existing_resp_cookies = resp_hdr->valid() && resp_hdr->presence(MIME_PRESENCE_SET_COOKIE); + bool default_domain_match; + const char *host_start; + const char *host_end; + int host_len, cmp_len; + + if (!existing_req_cookies && !existing_resp_cookies) + return; + + if (!domain_start && (!thost_start || no_dot == false)) { + // mising domain name information + add_cookies = false; + goto Lcheckcookie; + } + + host_start = request->url_get()->host_get(&host_len); + + if (!host_start || !host_len) + host_start = request->value_get(MIME_FIELD_HOST, MIME_LEN_HOST, &host_len); + + if (!host_start && !host_len) { + add_cookies = false; + goto Lcheckcookie; + } + + host_end = host_start + host_len - 1; + if (domain_start) { + cmp_len = domain_end - domain_start + 1; + + if (host_len cmp_len && host_start[host_len - cmp_len - 1] != '.') || //nbc.com != cnbc.com + strncasecmp(domain_start, host_end - (cmp_len - 1), cmp_len) != 0) { + add_cookies = false; + goto Lcheckcookie; + } + // Netscape Cookie spec says the default domain is the host name + if (thost_len != host_len || strncasecmp(thost_start, host_start, host_len) != 0) + default_domain_match = false; + else + default_domain_match = true; + } else { + if (host_len != thost_len || strncasecmp(thost_start, host_start, host_len) != 0) { + add_cookies = false; + goto Lcheckcookie; + } + default_domain_match = true; + } + + if (existing_resp_cookies) { + const char *a_raw; + int a_raw_len; + const char *move_cookie; + int move_cookie_len; + MIMEField *s_cookie = NULL; + + add_cookies = false; + // delete the old Cookie first - INKqa11823 + request->field_delete(MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + // for Set-Cookie it is not comma separated, each a_value contains + // the value for one Set-Cookie header + s_cookie = resp_hdr->field_find(MIME_FIELD_SET_COOKIE, MIME_LEN_SET_COOKIE); + for (; s_cookie; s_cookie = s_cookie->m_next_dup) { + a_raw = s_cookie->value_get(&a_raw_len); + MIMEField *new_cookie = NULL; + bool new_cookie_attached = false; + StrList a_param_list; + Str *a_param; + bool first_move; + bool domain_match; + + cookie_debug("PrefetchCookies", a_raw, a_raw_len); + + domain_match = default_domain_match; + HttpCompat::parse_tok_list(&a_param_list, 0, a_raw, a_raw_len, ';'); + for (a_param = a_param_list.head; a_param; a_param = a_param->next) { + move_cookie = a_param->str; + move_cookie_len = a_param->len; + + cookie_debug("Field", move_cookie, move_cookie_len); + + if (!new_cookie) { + new_cookie = request->field_create(); + first_move = true; + } else + first_move = false; + + if (move_cookie_len > 7 && strncasecmp(move_cookie, "domain=", 7) == 0) { + // the Set-cookie header specify the domain name + const char *cookie_domain_start = move_cookie + 7; + int cookie_domain_len = move_cookie_len - 7; + const char *cookie_domain_end = (const char *) (move_cookie + move_cookie_len - 1); + + if (*cookie_domain_start == '"') { + // domain=".amazon.com" style + if (*cookie_domain_end == '"') { + cookie_domain_start++; + cookie_domain_end--; + cookie_domain_len -= 2; + if (cookie_domain_len <= 0) + goto Lnotmatch; + } else { + // invalid fomat, missing trailing quote + goto Lnotmatch; + } + } + // remove trailing . + while (*cookie_domain_end == '.' && cookie_domain_len > 0) + cookie_domain_end--, cookie_domain_len--; + + if (cookie_domain_len <= 0) + goto Lnotmatch; + + // matching domain based on RFC2109 + int prefix_len = host_len - cookie_domain_len; + if (host_len <= 0 || prefix_len < 0) + goto Lnotmatch; + + if (strncasecmp(host_start + prefix_len, cookie_domain_start, cookie_domain_len) != 0) + goto Lnotmatch; + + // make sure that the prefix doesn't contain a '.' + if (prefix_len > 0 && memchr(host_start, '.', prefix_len)) + goto Lnotmatch; + + // Ok, when we get here, it should be a real match as far as + // domain is concerned. + // possibly overwrite the default domain matching result + domain_match = true; + continue; + } else if (move_cookie_len > 5 && strncasecmp(move_cookie, "path=", 5) == 0) { + const char *cookie_path_start = move_cookie + 5; + int cookie_path_len = move_cookie_len - 5; + const char *cookie_path_end = (const char *) (move_cookie + move_cookie_len - 1); + + if (cookie_path_len <= 0) + goto Lnotmatch; + + if (*cookie_path_start == '/') { + cookie_path_start++; + cookie_path_len--; + } + + if (cookie_path_len == 0) { + // a match - "/" + continue; + } + + if (*cookie_path_end == '/') { + cookie_path_end--; + cookie_path_len--; + } + + if (cookie_path_len == 0) { + // invalid format "//" + goto Lnotmatch; + } + // matching path based on RFC2109 + + int dest_path_len; + const char *dest_path_start = request->url_get()->path_get(&dest_path_len); + + // BZ 49734 + if (dest_path_start == NULL || dest_path_len == 0) { + goto Lnotmatch; + } + + if (*dest_path_start == '/') { + dest_path_start++; + dest_path_len--; + } + + if (dest_path_len < cookie_path_len || strncasecmp(dest_path_start, cookie_path_start, cookie_path_len) != 0) + goto Lnotmatch; + + // when we get here the path is a match + } else if (move_cookie_len > 8 && strncasecmp(move_cookie, "expires=", 8) == 0) { + // ignore expires directive for the time being + continue; + } else { + // append the value to the request Cookie header + request->field_value_append(new_cookie, move_cookie, move_cookie_len, !first_move, ';'); + } + } + + if (domain_match == false) + goto Lnotmatch; + + if (new_cookie && !new_cookie_attached) { + new_cookie_attached = true; + if (add_cookies == false) + add_cookies = true; + new_cookie->name_set(request->m_heap, request->m_mime, MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + request->field_attach(new_cookie); + } + continue; + + Lnotmatch: + if (new_cookie) { + if (!new_cookie_attached) { + new_cookie->name_set(request->m_heap, request->m_mime, MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + request->field_attach(new_cookie); + } + request->field_delete(new_cookie); + new_cookie = NULL; + } + } + + // INKqa11823 - now add the old Cookies back based on the new cookies + if (add_cookies && existing_req_cookies) { + MIMEField *o_cookie = req_hdr->field_find(MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + const char *iter_cookie; + int iter_cookie_len; + + for (; o_cookie; o_cookie = o_cookie->m_next_dup) { + MIMEField *n_cookie = NULL; + a_raw = o_cookie->value_get(&a_raw_len); + if (a_raw != NULL && a_raw_len > 0) { + StrList a_param_list; + Str *a_param; + bool f_move; + + HttpCompat::parse_tok_list(&a_param_list, 0, a_raw, a_raw_len, ';'); + for (a_param = a_param_list.head; a_param; a_param = a_param->next) { + iter_cookie = a_param->str; + iter_cookie_len = a_param->len; + + if (isCookieUnique(request, iter_cookie, iter_cookie_len)) { + // this is a unique cookie attribute, ready to add + if (n_cookie == NULL) { + n_cookie = request->field_create(); + f_move = true; + } else + f_move = false; + + request->field_value_append(n_cookie, iter_cookie, iter_cookie_len, !f_move, ';'); + } + } + + if (n_cookie) { + n_cookie->name_set(request->m_heap, request->m_mime, MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + request->field_attach(n_cookie); + } + } + } + } + // add_cookies now means whether new Cookie headers are created + // from the Set-Cookie headers + // now also check the existing Cookie headers from the req_hdr + add_cookies = add_cookies || existing_req_cookies; + } + +Lcheckcookie: + if (add_cookies == false) { + // delete the cookie header, if there is any at all + request->field_delete(MIME_FIELD_COOKIE, MIME_LEN_COOKIE); + } + + DUMP_HEADER("PrefetchCookies", req_hdr, (int64_t)0, + "Request Header for the top page used as the base for the new request with Cookies"); + DUMP_HEADER("PrefetchCookies", resp_hdr, (int64_t)0, + "Response Header for the top page used as the base for the new request with Cookies"); + DUMP_HEADER("PrefetchCookies", request, (int64_t)0, "Request Header with Cookies generated by Prefetch Parser"); +} + +int +PrefetchBlaster::handleEvent(int event, void *data) +{ + /* + This one first decides if we need to send the url or not. + If necessary, send the url ( Right now, just connect on TCP + connection and send the data) + */ + + switch (event) { + + case EVENT_IMMEDIATE:{ + //Here, we need to decide if we need to prefetch based on whether it + //is in the cache or not. + + //if (cache_lookup_necessary) do: + initCacheLookupConfig(); + cacheProcessor.open_read(this, request->url_get(), request, &cache_lookup_config, 0); + + break; + } + + case EVENT_INTERVAL:{ + + if (url_list) { + MUTEX_TRY_LOCK(trylock, url_list->mutex, this_ethread()); + if (!trylock) { + this_ethread()->schedule_in(this, HRTIME_MSECONDS(10)); + break; + } + url_ent->resp_blaster = this; + url_list->handleEvent(PREFETCH_EVENT_SEND_URL, url_ent); + } + + if (serverVC) { + SET_HANDLER((EventHandler) (&PrefetchBlaster::bufferObject)); + } else { + SET_HANDLER((EventHandler) (&PrefetchBlaster::httpClient)); + } + + transform->free(); + transform = NULL; + + if (!url_list) + this_ethread()->schedule_imm_local(this); + // Otherwise, just wait till PrefetchUrlBlaster signals us. + + break; + } + + case CACHE_EVENT_OPEN_READ:{ + //action = NULL; + + Debug("PrefetchBlaster", "Cache lookup succeded for %s\n", url_ent->url); + + serverVC = (VConnection *) data; + + ((CacheVConnection *) data)->get_http_info(&cache_http_info); + + invokeBlaster(); + break; + } + case CACHE_EVENT_OPEN_READ_FAILED: + //action = NULL; + Debug("PrefetchBlaster", "Cache lookup failed for %s\n", url_ent->url); + + invokeBlaster(); + break; + + default: + ink_assert(!"not reached"); + free(); + } + + return EVENT_DONE; +} + +static int +copy_header(MIOBuffer *buf, HTTPHdr *hdr, const char *hdr_tail) +{ + //copy the http header into to the buffer + int64_t done = 0; + int64_t offset = 0; + + while (!done) { + int64_t block_len = buf->block_write_avail(); + int index = 0, temp = offset; + + done = hdr->print(buf->end(), block_len, &index, &temp); + + ink_debug_assert(done || index == block_len); + + offset += index; + + if (!done) { + buf->fill(index); + buf->add_block(); + } else { + ink_debug_assert(index >= 2); + if (hdr_tail && index >= 2) { + /*This is a hack to be able to send headers beginning with @ */ + int len = strlen(hdr_tail); + offset += len - 2; + buf->fill(index - 2); + buf->write(hdr_tail, len); + } else + buf->fill(index); + } + } + + return offset; +} + +int +PrefetchBlaster::httpClient(int event, void *data) +{ + /* + This one makes an http connection on the local host and sends the request + */ + + switch (event) { + + case EVENT_IMMEDIATE:{ + netProcessor.connect_re(this, htonl((127 << 24) | 1), prefetch_config.local_http_server_port); + break; + } + + case NET_EVENT_OPEN:{ + serverVC = (VConnection *) data; + buf->reset(); + + char *rec_header = 0; + char hdr_buf[64]; + + if (request->field_find(PREFETCH_FIELD_RECURSION, PREFETCH_FIELD_LEN_RECURSION)) { + snprintf(hdr_buf, sizeof(hdr_buf), "%s: %d\r\n\r\n", PREFETCH_FIELD_RECURSION, + request->value_get_int(PREFETCH_FIELD_RECURSION, PREFETCH_FIELD_LEN_RECURSION)); + rec_header = hdr_buf; + } + + int len = copy_header(buf, request, rec_header); + + serverVC->do_io_write(this, len, reader); + + break; + } + + case NET_EVENT_OPEN_FAILED: + Debug("PrefetchBlaster", "Open to local http port failed.. strange\n"); + free(); + break; + + case VC_EVENT_WRITE_READY: + break; + case VC_EVENT_WRITE_COMPLETE: + SET_HANDLER((EventHandler) (&PrefetchBlaster::bufferObject)); + bufferObject(EVENT_IMMEDIATE, NULL); + break; + + default: + Debug("PrefetchBlaster", "Unexpected Event: %d(%s)\n", event, get_vc_event_name(event)); + case VC_EVENT_ERROR: + case VC_EVENT_EOS: + free(); + break; + } + + return EVENT_DONE; +} + +int +PrefetchBlaster::bufferObject(int event, void *data) +{ + NOWARN_UNUSED(data); + switch (event) { + + case EVENT_INTERVAL: + case EVENT_IMMEDIATE:{ + buf->reset(); + buf->water_mark = prefetch_config.max_object_size; + buf->fill(PRELOAD_HEADER_LEN); + + int64_t ntoread = INT64_MAX; + int len = copy_header(buf, request, NULL); + + if (cache_http_info) { + len += copy_header(buf, cache_http_info->response_get(), NULL); + ntoread = cache_http_info->object_size_get(); + } + serverVC->do_io_read(this, ntoread, buf); + break; + } + + case VC_EVENT_READ_READY: + if (buf->high_water()) { + //right now we don't handle DEL events on the child + Debug("PrefetchBlasterTemp", "The object is bigger than %d bytes " "cancelling the url", buf->water_mark); + buf->reset(); + buf->fill(PRELOAD_HEADER_LEN); + buf->write("DEL ", 4); + buf->write(url_ent->url, url_ent->len); + blastObject(EVENT_IMMEDIATE, (void *) 1); + } + break; + + default: + Debug("PrefetchBlaster", "Error Event: %s\n", get_vc_event_name(event)); + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + blastObject(EVENT_IMMEDIATE, NULL); + break; + } + + return EVENT_DONE; +} + +/* following sturcture and masks should be the same in StufferUdpReceiver.cc + on microTS */ + +int +PrefetchBlaster::blastObject(int event, void *data) +{ + switch (event) { + + case EVENT_IMMEDIATE: + serverVC->do_io_close(); + serverVC = 0; + + // (data == (void*)1) implies we are not sending the object because + // it is too large. Instead we will send "DEL" msg for the promise + bool obj_cancelled; + obj_cancelled = (data == (void *) 1); + + setup_object_header(reader->start(), reader->read_avail(), obj_cancelled); + + if (url_ent->object_buf_status != TS_PREFETCH_OBJ_BUF_NOT_NEEDED && + prefetch_config.embedded_obj_hook && !obj_cancelled) { + TSPrefetchInfo info; + memset(&info, 0, sizeof(info)); + + info.embedded_url = url_ent->url; + info.object_buf_status = url_ent->object_buf_status; + + info.object_buf = TSIOBufferCreate(); + info.object_buf_reader = TSIOBufferReaderAlloc(info.object_buf); + + ((MIOBuffer *) info.object_buf)->write(reader); + + prefetch_config.embedded_obj_hook(TS_PREFETCH_EMBEDDED_OBJECT_HOOK, &info); + } + + if (url_ent->object_buf_status == TS_PREFETCH_OBJ_BUF_NEEDED) { + //we need not send this to the child + free(); + break; + } + + if (data_proto == TCP_BLAST) { + g_conn_table->append(url_ent->child_ip, buf, reader); + buf = 0; + free(); + break; + } else { + SET_HANDLER((EventHandler) (&PrefetchBlaster::blastObject)); + *(int *) reader->start() = htonl(reader->read_avail()); + + io_block = ioBlockAllocator.alloc(); + io_block->alloc(BUFFER_SIZE_INDEX_32K); + + seq_no = get_udp_seq_no(); + //fall through + } + + case NET_EVENT_DATAGRAM_WRITE_COMPLETE:{ + io_block->reset(); + io_block->fill(PRELOAD_UDP_HEADER_LEN); + + int64_t nread_avail = reader->read_avail(); + + if (nread_avail <= 0) { + free(); + break; + } + + int64_t nwrite_avail = io_block->write_avail(); + + int64_t towrite = (nread_avail < nwrite_avail) ? nread_avail : nwrite_avail; + + reader->read(io_block->end(), towrite); + io_block->fill(towrite); + + Debug("PrefetchBlaster", "UDP: sending data: pkt_no: %d last_pkt: %d" + " url: %s", n_pkts_sent, (towrite >= nread_avail), url_ent->url); + + setup_udp_header(io_block->start(), seq_no, n_pkts_sent++, (towrite >= nread_avail)); + + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(prefetch_config.stuffer_port); + saddr.sin_addr.s_addr = (url_ent->data_multicast_ip) ? url_ent->data_multicast_ip : url_ent->child_ip; + + //saddr.sin_addr.s_addr = htonl((209<<24)|(131<<16)|(60<<8)|243); + //saddr.sin_addr.s_addr = htonl((209<<24)|(131<<16)|(48<<8)|52); + + udpNet.sendto_re(this, NULL, prefetch_udp_fd, (sockaddr *) & saddr, sizeof(saddr), io_block, io_block->read_avail()); + } + break; + + case NET_EVENT_DATAGRAM_WRITE_ERROR: + Debug("PrefetchBlaster", "error in sending the udp data %p", data); + + default: + ink_assert(!"unexpected event"); + } + return EVENT_DONE; +} + +int +PrefetchBlaster::invokeBlaster() +{ + int ret = (cache_http_info && !prefetch_config.push_cached_objects) + ? TS_PREFETCH_DISCONTINUE : TS_PREFETCH_CONTINUE; + + unsigned int url_proto = prefetch_config.default_url_proto; + data_proto = prefetch_config.default_data_proto; + + if (prefetch_config.embedded_url_hook) { + + TSPrefetchInfo info; + + info.request_buf = reinterpret_cast(request); + info.request_loc = reinterpret_cast(request->m_http); + info.response_buf = 0; + info.response_loc = 0; + + info.object_buf = 0; + info.object_buf_reader = 0; + info.object_buf_status = TS_PREFETCH_OBJ_BUF_NOT_NEEDED; + + info.client_ip = url_ent->child_ip; + info.embedded_url = url_ent->url; + info.present_in_cache = (cache_http_info != NULL); + info.url_proto = url_proto; + info.url_response_proto = data_proto; + + ret = (*prefetch_config.embedded_url_hook) + (TS_PREFETCH_EMBEDDED_URL_HOOK, &info); + + url_proto = info.url_proto; + data_proto = info.url_response_proto; + + url_ent->object_buf_status = info.object_buf_status; + } + + if (ret == TS_PREFETCH_CONTINUE) { + + if (url_proto != TCP_BLAST && url_proto != UDP_BLAST) + url_ent->url_multicast_ip = url_proto; + if (data_proto != TCP_BLAST && data_proto != UDP_BLAST) + url_ent->data_multicast_ip = data_proto; + + if (url_ent->object_buf_status != TS_PREFETCH_OBJ_BUF_NEEDED) { + if (url_proto == TCP_BLAST) + url_list = transform->tcp_url_list; + else + url_list = transform->udp_url_list; + } + //if recursion is enabled, go through local host even for cached + //objects + if (prefetch_config.max_recursion > 0 && serverVC) { + serverVC->do_io_close(); + serverVC = NULL; + cache_http_info = 0; + } + + /* + if (data_proto == TCP_BLAST) + data_blaster = (EventHandler)(&PrefetchBlaster::tcpDataBlaster); + else data_blaster = (EventHandler)(&PrefetchBlaster::udpDataBlaster); + */ + handleEvent(EVENT_INTERVAL, NULL); + } else { + free(); + } + return 0; +} + +void +PrefetchBlaster::initCacheLookupConfig() +{ + //The look up parameters are intialized in the same as it is done + //in HttpSM::init(). Any changes there should come in here. + HttpConfigParams *http_config_params = HttpConfig::acquire(); + cache_lookup_config.cache_global_user_agent_header = http_config_params->global_user_agent_header ? true : false; + cache_lookup_config.cache_enable_default_vary_headers = + http_config_params->cache_enable_default_vary_headers ? true : false; + cache_lookup_config.cache_vary_default_text = http_config_params->cache_vary_default_text; + cache_lookup_config.cache_vary_default_images = http_config_params->cache_vary_default_images; + cache_lookup_config.cache_vary_default_other = http_config_params->cache_vary_default_other; + + HttpConfig::release(http_config_params); +} + +static int +config_read_proto(unsigned int &proto, const char *str) +{ + if (strncasecmp(str, "udp", 3) == 0) + proto = UDP_BLAST; + else if (strncasecmp(str, "tcp", 3) == 0) + proto = TCP_BLAST; + else { // this is a multicast address: + if (strncasecmp("multicast:", str, 10) == 0) { + unsigned int ip[4]; + // coverity[secure_coding] + if (sscanf(str + 10, "%u.%u.%u.%u", &ip[0], &ip[1], &ip[2], &ip[3]) < 4) { + Error("PrefetchProcessor: Address specified for multicast does not seem to " + "be of the form multicast:ip_addr (eg: multicast:224.0.0.1)"); + return 1; + } else { + proto = htonl(((ip[0] & 0xff) << 24) | ((ip[1] & 0xff) << 16) | ((ip[2] & 0xff) << 8) | (ip[3] & 0xff)); + Debug("Prefetch", "Setting multicast address: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + } + } else { + Error("PrefetchProcessor: The protocol for Prefetch should of the form: " "tcp or udp or multicast:ip_address"); + return 1; + } + } + + return 0; +} + +int +PrefetchConfiguration::readConfiguration() +{ + char *conf_file_name; + char conf_path[PATH_NAME_MAX + 1]; + int fd = -1; + + local_http_server_port = stuffer_port = 0; + prefetch_enabled = TS_ConfigReadInteger("proxy.config.prefetch.prefetch_enabled"); + if (prefetch_enabled <= 0) { + prefetch_enabled = 0; + return 0; + } + + TS_ReadConfigInteger(local_http_server_port, "proxy.config.http.server_port"); + TS_ReadConfigInteger(stuffer_port, "proxy.config.prefetch.child_port"); + TS_ReadConfigInteger(url_buffer_size, "proxy.config.prefetch.url_buffer_size"); + TS_ReadConfigInteger(url_buffer_timeout, "proxy.config.prefetch.url_buffer_timeout"); + TS_ReadConfigInteger(keepalive_timeout, "proxy.config.prefetch.keepalive_timeout"); + if (keepalive_timeout <= 0) + keepalive_timeout = 3600; + + TS_ReadConfigInteger(push_cached_objects, "proxy.config.prefetch.push_cached_objects"); + + TS_ReadConfigInteger(max_object_size, "proxy.config.prefetch.max_object_size"); + + TS_ReadConfigInteger(max_recursion, "proxy.config.prefetch.max_recursion"); + + TS_ReadConfigInteger(redirection, "proxy.config.prefetch.redirection"); + + char *tstr = TS_ConfigReadString("proxy.config.prefetch.default_url_proto"); + if (config_read_proto(default_url_proto, tstr)) + goto Lerror; + + tstr = TS_ConfigReadString("proxy.config.prefetch.default_data_proto"); + if (config_read_proto(default_data_proto, tstr)) + goto Lerror; + + //pre_parse_hook = 0; + //embedded_url_hook = 0; + + conf_file_name = TS_ConfigReadString("proxy.config.prefetch.config_file"); + + if (conf_file_name == NULL) { + Warning("PrefetchProcessor: No prefetch configuration file specified. Prefetch disabled\n"); + goto Lerror; + } + Layout::relative_to(conf_path, sizeof(conf_path), + system_config_directory, conf_file_name); + xfree(conf_file_name); + + fd = open(conf_path, O_RDONLY); + if (fd < 0) { + Error("PrefetchProcessor: Error, could not open '%s' disabling Prefetch\n", conf_path); + goto Lerror; + } + + char *temp_str; + if ((temp_str = ip_range.read_table_from_file(fd, "prefetch_children", FALSE)) != 0) { + Error("PrefetchProcessor: Error in reading ip_range from %s: %.256s\n", conf_path, temp_str); + xfree(temp_str); + goto Lerror; + } + + lseek(fd, 0, SEEK_SET); + readHtmlTags(fd, &html_tags_table, &html_attrs_table); + if (html_tags_table == NULL) { + html_tags_table = &prefetch_allowable_html_tags[0]; + ink_assert(html_attrs_table == NULL); + html_attrs_table = &prefetch_allowable_html_attrs[0]; + } + + close(fd); + return 0; +Lerror: + if (fd >= 0) + close(fd); + prefetch_enabled = 0; + return -1; +} + +void +PrefetchConfiguration::readHtmlTags(int fd, html_tag ** ptags, html_tag ** pattrs) +{ + int ntags = 0; + html_tag tags[256]; + html_tag attrs[256]; + bool attrs_exist = false; + char buf[512], tag[64], attr[64], attr_tag[64], attr_attr[64]; + int num; + int end_of_file = 0; + + memset(attrs, 0, 256 * sizeof(html_tag)); + while (!end_of_file && ntags < 256) { + char c; + int ret, len = 0; + //read the line + while (((ret = read(fd, &c, 1)) == 1) && (c != '\n')) + if (len < 511) + buf[len++] = c; + buf[len] = 0; + if (ret <= 0) + end_of_file = 1; + + // length(63) specified in sscanf, no need to worry about string overflow + // coverity[secure_coding] + if ((num = sscanf(buf, " html_tag %63s %63s %63s %63s", tag, attr, attr_tag, attr_attr)) >= 2) { + Debug("Prefetch", "Read html_tag: %s %s\n", tag, attr); + tags[ntags].tag = xstrdup(tag); + tags[ntags].attr = xstrdup(attr); + if (num >= 4) { + if (!attrs_exist) + attrs_exist = true; + attrs[ntags].tag = xstrdup(attr_tag); + attrs[ntags].tag = xstrdup(attr_attr); + } + ntags++; + } + } + + if (ntags > 0) { + html_tag *xtags = (html_tag *) xmalloc((ntags + 3) * sizeof(html_tag)); + ink_assert(xtags); + memcpy(xtags, &tags[0], ntags * sizeof(tags[0])); + //the following two are always added + xtags[ntags].tag = "base"; + xtags[ntags].attr = "href"; + xtags[ntags + 1].tag = "meta"; + xtags[ntags + 1].attr = "content"; + xtags[ntags + 2].tag = xtags[ntags + 2].attr = NULL; + + *ptags = xtags; + if (attrs_exist) { + html_tag *xattrs = (html_tag *) xmalloc((ntags + 3) * sizeof(html_tag)); + memcpy(xattrs, &attrs[0], 256 * sizeof(html_tag)); + *pattrs = xattrs; + } else + *pattrs = NULL; + return; + } + + *ptags = NULL; + *pattrs = NULL; +} + +/* Keep Alive stuff */ + +#define CONN_ARR_SIZE 256 +inline int +KeepAliveConnTable::ip_hash(unsigned int ip) +{ + unsigned char *ip_str = (unsigned char *) &ip; + + return (ip_str[0] ^ ip_str[1] ^ ip_str[2] ^ ip_str[3]) & (CONN_ARR_SIZE - 1); +} + +inline int +KeepAliveConn::append(IOBufferReader *rdr) +{ + int64_t size = rdr->read_avail(); + + nbytes_added += size; + + buf->write(rdr); + vio->reenable(); + + return 0; +} + +int +KeepAliveConnTable::init() +{ + arr = NEW(new conn_elem[CONN_ARR_SIZE]); + + for (int i = 0; i < CONN_ARR_SIZE; i++) { + arr[i].conn = 0; + arr[i].mutex = new_ProxyMutex(); + } + + return 0; +} + +void +KeepAliveConnTable::free() +{ + for (int i = 0; i < CONN_ARR_SIZE; i++) + arr[i].mutex.clear(); + + delete arr; + delete this; +} + +ClassAllocator prefetchLockHandlerAllocator("prefetchLockHandlerAllocator"); + +int +KeepAliveConnTable::append(unsigned int ip, MIOBuffer *buf, IOBufferReader *reader) +{ + int index = ip_hash(ip); + + MUTEX_TRY_LOCK(trylock, arr[index].mutex, this_ethread()); + if (!trylock) { + /* This lock fails quite often. This can be expected because, + multiple threads try to append their buffer all the the same + time to the same connection. Other thread holds it for a long + time when it is doing network IO 'n stuff. This is one more + reason why URL messages should be sent by UDP. We will avoid + appending small messages here and those URL message reach the + child much faster */ + + prefetchLockHandlerAllocator.alloc()->init(ip, buf, reader); + return 1; + } + + KeepAliveConn **conn = &arr[index].conn; + + while (*conn && (*conn)->ip != ip) + conn = &(*conn)->next; + + if (*conn) { + (*conn)->append(reader); + free_MIOBuffer(buf); + } else { + *conn = NEW(new KeepAliveConn); //change to fast allocator? + (*conn)->init(ip, buf, reader); + } + + return 0; +} + +int +KeepAliveConn::init(unsigned int xip, MIOBuffer *xbuf, IOBufferReader *xreader) +{ + mutex = g_conn_table->arr[KeepAliveConnTable::ip_hash(xip)].mutex; + + ip = xip; + buf = xbuf; + reader = xreader; + + childVC = 0; + vio = 0; + next = 0; + + read_buf = new_MIOBuffer(); //we should give minimum size possible + + nbytes_added = reader->read_avail(); + + SET_HANDLER(&KeepAliveConn::handleEvent); + + //we are already under lock + netProcessor.connect_re(this, ip, prefetch_config.stuffer_port); + + return 0; +} + +void +KeepAliveConn::free() +{ + if (childVC) + childVC->do_io_close(); + + if (buf) + free_MIOBuffer(buf); + if (read_buf) + free_MIOBuffer(read_buf); + + KeepAliveConn *prev = 0; + KeepAliveConn **head = &g_conn_table->arr[KeepAliveConnTable::ip_hash(ip)].conn; + + KeepAliveConn *conn = *head; + while (conn != this) { + prev = conn; + conn = conn->next; + } + + if (prev) + prev->next = next; + else + *head = next; + + mutex.clear(); + Debug("PrefetchKConn", "deleting a KeepAliveConn"); + delete this; +} + +int +KeepAliveConn::handleEvent(int event, void *data) +{ + switch (event) { + + case NET_EVENT_OPEN: + + childVC = (NetVConnection *) data; + + childVC->set_inactivity_timeout(HRTIME_SECONDS(prefetch_config.keepalive_timeout)); + + vio = childVC->do_io_write(this, INT64_MAX, reader); + + //his read lets us disconnect when the other side closes + childVC->do_io_read(this, INT64_MAX, read_buf); + break; + + case NET_EVENT_OPEN_FAILED: + Debug("PrefetchKeepAlive", "Connection to child %u.%u.%u.%u failed\n", IPSTRARGS(ip)); + free(); + break; + + case VC_EVENT_WRITE_READY: + //Debug("PrefetchTemp", "ndone = %d", vio->ndone); + + break; + + case VC_EVENT_INACTIVITY_TIMEOUT: + //Debug("PrefetchTemp", "%d sec timeout expired for %d.%d.%d.%d", + //prefetch_config.keepalive_timeout, IPSTRARGS(ip)); + + if (reader->read_avail()) + childVC->set_inactivity_timeout(HRTIME_SECONDS(prefetch_config.keepalive_timeout)); + else + free(); + break; + + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_READ_READY: + /*Right now we dont expect any response from the child. + Read event implies POLLHUP */ + case VC_EVENT_EOS: + Debug("PrefetchKeepAlive", "the other side closed the connection"); + free(); + break; + + case VC_EVENT_ERROR: + Debug("PrefetchKeepAlive", "got VC_ERROR.. connection problem? " "(ip: %u.%u.%u.%u)", IPSTRARGS(ip)); + free(); + break; + + default: + ink_debug_assert(!"not reached"); + free(); + } + + return EVENT_DONE; +} + +int +KeepAliveLockHandler::handleEvent(int event, void *data) +{ + NOWARN_UNUSED(data); + if (event == EVENT_INTERVAL) + g_conn_table->append(ip, buf, reader); + + prefetchLockHandlerAllocator.free(this); + + return EVENT_DONE; +} + +/* API */ +int +TSPrefetchStart() +{ + printf("TSPrefetchStart() is called\n"); + return 0; +} + +int +TSPrefetchHookSet(int hook_no, TSPrefetchHook hook) +{ + switch (hook_no) { + + case TS_PREFETCH_PRE_PARSE_HOOK: + prefetch_config.pre_parse_hook = hook; + return 0; + + case TS_PREFETCH_EMBEDDED_URL_HOOK: + prefetch_config.embedded_url_hook = hook; + return 0; + + case TS_PREFETCH_EMBEDDED_OBJECT_HOOK: + prefetch_config.embedded_obj_hook = hook; + return 0; + + default: + return -1; + } +} + +#endif // PREFETCH diff --git a/proxy/Prefetch.h b/proxy/Prefetch.h new file mode 100644 index 00000000..1a9e5fef --- /dev/null +++ b/proxy/Prefetch.h @@ -0,0 +1,453 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _PREFETCH_H_ +#define _PREFETCH_H_ + +#include "IPRange.h" +#include "TransformInternal.h" + +#ifdef PREFETCH + +#include "Update.h" +#include "api/ts/experimental.h" +#include "api/ts/InkAPIHughes.h" + +#define IPSTRARGS(ip) (unsigned int) ((unsigned char *) &(ip))[0], \ + (unsigned int) ((unsigned char *) &(ip))[1], \ + (unsigned int) ((unsigned char *) &(ip))[2], \ + (unsigned int) ((unsigned char *) &(ip))[3] + +typedef enum +{ + ILL_BLAST = 0, + UDP_BLAST = TS_PREFETCH_PROTO_UDP, + TCP_BLAST = TS_PREFETCH_PROTO_TCP + //MULTICAST_BLAST = TS_PREFETCH_PROTO_UDP_MULTICAST +} PrefetchBlastType; + +class BlasterUrlList; +class PrefetchUrlBlaster; +class PrefetchBlaster; +extern BlasterUrlList *multicastUrlBlaster; + +struct PrefetchConfiguration +{ + int prefetch_enabled; + IPRange ip_range; + struct html_tag *html_tags_table; + struct html_tag *html_attrs_table; + + int local_http_server_port; + int stuffer_port; + + int url_buffer_size; + int url_buffer_timeout; + + unsigned int default_url_proto; + unsigned int default_data_proto; + + int keepalive_timeout; + int push_cached_objects; + + unsigned int max_object_size; + + unsigned int max_recursion; //limit on depth of recursive prefetch + unsigned int redirection; //limit on depth of redirect prefetch + + TSPrefetchHook pre_parse_hook; + TSPrefetchHook embedded_url_hook; + TSPrefetchHook embedded_obj_hook; + + int readConfiguration(); + void readHtmlTags(int fd, html_tag ** ptags, html_tag ** pattrs); +}; + +// TODO: This used to be private, which seems wrong. +class PrefetchUrlEntry: public RefCountObj +{ +public: + PrefetchUrlEntry() + : url(0), len(INT_MAX), resp_blaster(0), + object_buf_status(TS_PREFETCH_OBJ_BUF_NOT_NEEDED), + req_ip(0), child_ip(0), url_multicast_ip(0), data_multicast_ip(0), blaster_link(0), hash_link(0) + { + refcount_inc(); + } + + void init(char *str, INK_MD5 & xmd5) + { + len = strlen(url = str) + 1; + md5 = xmd5; + } + void free(); + + PrefetchUrlEntry *assign() + { + refcount_inc(); + return this; + }; + + char *url; + int len; + INK_MD5 md5; + + //PrefetchBlastType resp_blast_proto; + //HTTPHdr * request; + PrefetchBlaster *resp_blaster; + + int object_buf_status; + + uint32_t req_ip; /*ip address where request is coming from */ + uint32_t child_ip; + uint32_t url_multicast_ip; + uint32_t data_multicast_ip; + + PrefetchUrlEntry *blaster_link; + PrefetchUrlEntry *hash_link; + +private: + // this private copy ctor is set to prevent from being used + // coverity[uninit_member] + PrefetchUrlEntry(const PrefetchUrlEntry &) + { + }; +}; + +extern ClassAllocator prefetchUrlEntryAllocator; + +inline void +PrefetchUrlEntry::free() +{ + if (refcount_dec() == 0) { + if (url) + xfree(url); + prefetchUrlEntryAllocator.free(this); + } +} + +class PrefetchTransform:public INKVConnInternal, public RefCountObj +{ + enum + { HASH_TABLE_LENGTH = 61 /*127, 511 */ }; +public: + + PrefetchTransform(HttpSM * sm, HTTPHdr * resp); + ~PrefetchTransform(); + void free() + { + if (refcount_dec() == 0) + delete this; + }; + PrefetchTransform *assign() + { + refcount_inc(); + return this; + }; + + int handle_event(int event, void *edata); + int parse_data(IOBufferReader * reader); + int redirect(HTTPHdr * resp); + + PrefetchUrlEntry *hash_add(char *url); + +public: + MIOBuffer * m_output_buf; + IOBufferReader *m_output_reader; + VIO *m_output_vio; + + HttpSM *m_sm; + //HTTPHdr *m_request; + //HTTPHdr *m_response; + + char *url; + + //unsigned int child_ip; + HtmlParser html_parser; + + PrefetchUrlEntry *hash_table[HASH_TABLE_LENGTH]; + + BlasterUrlList *udp_url_list; + BlasterUrlList *tcp_url_list; + + const char *domain_start; + const char *domain_end; + const char *host_start; + int host_len; + bool no_dot_in_host; +}; + + +//blaster +class BlasterUrlList:public Continuation +{ + + int timeout; //in milliseconds + Action *action; + int mtu; + PrefetchBlastType blast_proto; + + PrefetchUrlEntry *list_head; + int cur_len; + +public: + BlasterUrlList() + : Continuation(), timeout(0), action(0), mtu(0), blast_proto(ILL_BLAST), list_head(0), cur_len(0) + { } + + void init(PrefetchBlastType btype = UDP_BLAST, int tout = 0, int xmtu = INT_MAX) { + SET_HANDLER((int (BlasterUrlList::*)(int, void *))(&BlasterUrlList::handleEvent)); + mutex = new_ProxyMutex(); + blast_proto = btype; + timeout = tout; + mtu = xmtu; + } + + void free(); + + int handleEvent(int event, void *data); + void invokeUrlBlaster(); +}; + +extern ClassAllocator blasterUrlListAllocator; + +inline void +BlasterUrlList::free() +{ + mutex = NULL; + blasterUrlListAllocator.free(this); +} + +class PrefetchUrlBlaster:public Continuation +{ +public: + typedef int (PrefetchUrlBlaster::*EventHandler) (int, void *); + + PrefetchUrlBlaster() + : url_head(0), proto(ILL_BLAST), action(0) + { + } + + void init(PrefetchUrlEntry * list_head, PrefetchBlastType u_proto = UDP_BLAST); + + void free(); + + PrefetchUrlEntry *url_head; + PrefetchBlastType proto; + + Action *action; + + void writeBuffer(MIOBuffer * buf); + + int udpUrlBlaster(int event, void *data); + +}; + +extern ClassAllocator prefetchUrlBlasterAllocator; + +void +PrefetchUrlBlaster::init(PrefetchUrlEntry * list_head, PrefetchBlastType u_proto) +{ + /* More clean up necessary... we should not need this class + XXXXXXXXX */ + mutex = new_ProxyMutex(); + + url_head = list_head; + proto = u_proto; + + MUTEX_LOCK(lock, mutex, this_ethread()); + + udpUrlBlaster(SIMPLE_EVENT_EVENTS_START, NULL); +} + +inline void +BlasterUrlList::invokeUrlBlaster() +{ + PrefetchUrlBlaster *u_blaster = prefetchUrlBlasterAllocator.alloc(); + u_blaster->init(list_head, blast_proto); + list_head = NULL; + cur_len = 0; +} + +class PrefetchBlaster:public Continuation +{ + +public: + typedef int (PrefetchBlaster::*EventHandler) (int event, void *data); + + PrefetchBlaster() + : Continuation(), url_ent(0), transform(0), url_list(0), request(0), + cache_http_info(0), buf(0), reader(0), serverVC(0), data_proto(0), n_pkts_sent(0), seq_no(0), io_block(0) + { + }; + ~PrefetchBlaster() { + }; + + int init(PrefetchUrlEntry * entry, HTTPHdr * request, PrefetchTransform * p_trans); + + int handleEvent(int event, void *data); + int bufferObject(int event, void *data); + int blastObject(int event, void *data); + int httpClient(int event, void *data); + + int invokeBlaster(); + void initCacheLookupConfig(); + + void handleCookieHeaders(HTTPHdr * req_hdr, HTTPHdr * resp_hdr, + const char *domain_start, const char *domain_end, + const char *host_start, int host_len, bool no_dot); + + void free(); + + PrefetchUrlEntry *url_ent; + PrefetchTransform *transform; + BlasterUrlList *url_list; + + HTTPHdr *request; + CacheHTTPInfo *cache_http_info; + + MIOBuffer *buf; + IOBufferReader *reader; + + VConnection *serverVC; + + unsigned int data_proto; + + CacheLookupHttpConfig cache_lookup_config; + + //udp related: + uint32_t n_pkts_sent; + uint32_t seq_no; + IOBufferBlock *io_block; +}; + +extern ClassAllocator prefetchBlasterAllocator; + +/*Conncetion keep alive*/ + +#define PRELOAD_HEADER_LEN 12 //this is the new header +//assuming bigendian bit order. does any body have a little endian bit order? +#define PRELOAD_HDR_URL_PROMISE_FLAG (0x40000000) +#define PRELOAD_HDR_RESPONSE_FLAG (0x80000000) +#define PRELOAD_UDP_HEADER_LEN 12 +#define PRELOAD_UDP_LAST_PKT_FLAG (0x80000000) +#define PRELOAD_UDP_PKT_NUM_MASK (0x7fffffff) + +class KeepAliveConn: public Continuation +{ +public: + + KeepAliveConn() + : Continuation(), ip(0), nbytes_added(0) + { } + + int init(unsigned int ip, MIOBuffer * buf, IOBufferReader * reader); + void free(); + + int append(IOBufferReader * reader); + int handleEvent(int event, void *data); + + unsigned int ip; + + MIOBuffer *buf; + IOBufferReader *reader; + + MIOBuffer *read_buf; + + NetVConnection *childVC; + VIO *vio; + + KeepAliveConn *next; + + int64_t nbytes_added; +}; + +class KeepAliveConnTable +{ +public: + + KeepAliveConnTable():arr(NULL) + { + }; + + int init(); + void free(); + static int ip_hash(unsigned int ip); + int append(unsigned int ip, MIOBuffer * buf, IOBufferReader * reader); + + typedef struct + { + KeepAliveConn *conn; + ProxyMutexPtr mutex; + } conn_elem; + + conn_elem *arr; +}; +extern KeepAliveConnTable *g_conn_table; + +class KeepAliveLockHandler: public Continuation +{ + /* Used when we miss the lock for the connection */ + +public: + KeepAliveLockHandler() + :Continuation(), ip(0) + { + }; + + void init(unsigned int xip, MIOBuffer * xbuf, IOBufferReader * xreader) + { + mutex = g_conn_table->arr[KeepAliveConnTable::ip_hash(ip)].mutex; + + ip = xip; + buf = xbuf; + reader = xreader; + + SET_HANDLER(&KeepAliveLockHandler::handleEvent); + this_ethread()->schedule_in(this, HRTIME_MSECONDS(10)); + } + + ~KeepAliveLockHandler() { + mutex = NULL; + } + + int handleEvent(int event, void *data); + + unsigned int ip; + MIOBuffer *buf; + IOBufferReader *reader; +}; + + +#define TS_ReadConfigInteger REC_ReadConfigInteger +#define TS_ReadConfigString REC_ReadConfigString +#define TS_EstablishStaticConfigInteger REC_EstablishStaticConfigInteger +#define TS_RegisterConfigUpdateFunc REC_RegisterConfigUpdateFunc +#define TS_ReadConfigStringAlloc REC_ReadConfigStringAlloc +#define TS_ConfigReadInteger REC_ConfigReadInteger +#define TS_ConfigReadString REC_ConfigReadString + + +#endif // PREFETCH + +#endif // _PREFETCH_H_ diff --git a/proxy/ProtoSM.h b/proxy/ProtoSM.h new file mode 100644 index 00000000..762e6b5f --- /dev/null +++ b/proxy/ProtoSM.h @@ -0,0 +1,150 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ProtoSM.h + + Description: + Common elements for protocol state machines + + + ****************************************************************************/ + +#ifndef _PROTO_SM_H_ +#define _PROTO_SM_H_ + +template struct ProtoVCTable +{ +public: + ProtoVCTable(); + VCTentry vc_table[max_entries]; + + VCTentry *new_entry(); + VCTentry *find_entry(VConnection *); + VCTentry *find_entry(VIO *); + void remove_entry(VCTentry *); + void cleanup_entry(VCTentry *); + void cleanup_all(); + bool is_table_clear(); +}; + +template inline ProtoVCTable::ProtoVCTable() +{ + memset(&vc_table, 0, sizeof(vc_table)); +} + +template inline VCTentry * ProtoVCTable::new_entry() +{ + for (int i = 0; i < max_entries; i++) { + if (vc_table[i].vc == NULL) { + return vc_table + i; + } + } + + ink_release_assert(0); + return NULL; +} + +template + inline VCTentry * ProtoVCTable::find_entry(VConnection * vc) +{ + for (int i = 0; i < max_entries; i++) { + if (vc_table[i].vc == vc) { + return vc_table + i; + } + } + + return NULL; +} + +template + inline VCTentry * ProtoVCTable::find_entry(VIO * vio) +{ + for (int i = 0; i < max_entries; i++) { + if (vc_table[i].read_vio == vio || vc_table[i].write_vio == vio) { + ink_assert(vc_table[i].vc != NULL); + return vc_table + i; + } + } + + return NULL; +} + +// bool ProtoVCTable::remove_entry(HttpVCEntry* e) +// +// Deallocates all buffers from the associated +// entry and re-initializes it's other fields +// for reuse +// +template + inline void ProtoVCTable::remove_entry(VCTentry * e) +{ + ink_assert(e->vc == NULL || e->in_tunnel); + if (e->read_buffer) { + free_MIOBuffer(e->read_buffer); + } + if (e->write_buffer) { + free_MIOBuffer(e->write_buffer); + } + memset(e, 0, sizeof(VCTentry)); +} + +// void ProtoVCTable::cleanup_entry(HttpVCEntry* e) +// +// Closes the associate vc for the entry, +// and the call remove_entry +// +template + inline void ProtoVCTable::cleanup_entry(VCTentry * e) +{ + + ink_assert(e->vc); + if (e->in_tunnel == false) { + e->vc->do_io_close(); + e->vc = NULL; + } + remove_entry(e); +} + +template inline void ProtoVCTable::cleanup_all() +{ + for (int i = 0; i < max_entries; i++) { + if (vc_table[i].vc != NULL) { + cleanup_entry(vc_table + i); + } + } +} + + +template inline bool ProtoVCTable::is_table_clear() +{ + for (int i = 0; i < max_entries; i++) { + if (vc_table[i].vc != NULL) { + return false; + } + } + return true; +} + +#endif diff --git a/proxy/ProxyConfig.cc b/proxy/ProxyConfig.cc new file mode 100644 index 00000000..41926129 --- /dev/null +++ b/proxy/ProxyConfig.cc @@ -0,0 +1,204 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" +#include "ProxyConfig.h" +#include "P_EventSystem.h" + +ConfigProcessor configProcessor; + + +void * +config_int_cb(void *data, void *value) +{ + *(int *) data = *(int64_t *) value; + return NULL; +} + +void * +config_float_cb(void *data, void *value) +{ + *(float *) data = *(float *) value; + return NULL; +} + +void * +config_long_long_cb(void *data, void *value) +{ + *(int64_t *) data = *(int64_t *) value; + return NULL; +} + +///////////////////////////////////////////////////////////// +// +// config_string_alloc_cb() +// +// configuration callback function. The function is called +// by the manager when a string configuration variable +// changed. It allocates new memory for the new data. +// the old variable is scheduled to be freed using +// ConfigFreerContinuation which will free the memory +// used for this variable after long time, assuming that +// during all this time all the users of this memory will +// disappear. +///////////////////////////////////////////////////////////// +void * +config_string_alloc_cb(void *data, void *value) +{ + char *_ss = (char *) value; + char *_new_value = 0; + +//#define DEBUG_CONFIG_STRING_UPDATE +#if defined (DEBUG_CONFIG_STRING_UPDATE) + printf("config callback [new, old] = [%s : %s]\n", + (_ss) ? (_ss) : (""), (*(char **) data) ? (*(char **) data) : ("")); +#endif + int len = -1; + if (_ss) { + len = strlen(_ss); + _new_value = (char *) xmalloc(len + 1); + memcpy(_new_value, _ss, len + 1); + } + + char *_temp2 = *(char **) data; + *(char **) data = _new_value; + + // free old data + if (_temp2 != 0) + new_Freer(_temp2, HRTIME_DAY); + + return NULL; +} + + +class ConfigInfoReleaser:public Continuation +{ +public: + ConfigInfoReleaser(unsigned int id, ConfigInfo * info) + : Continuation(new_ProxyMutex()), m_id(id), m_info(info) + { + SET_HANDLER(&ConfigInfoReleaser::handle_event); + } + + int handle_event(int event, void *edata) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(edata); + configProcessor.release(m_id, m_info); + delete this; + return 0; + } + +public: + unsigned int m_id; + ConfigInfo *m_info; +}; + + +ConfigProcessor::ConfigProcessor() + : ninfos(0) +{ + int i; + + for (i = 0; i < MAX_CONFIGS; i++) { + infos[i] = NULL; + } +} + +unsigned int +ConfigProcessor::set(unsigned int id, ConfigInfo * info) +{ + ConfigInfo *old_info; + int idx; + + if (id == 0) { + id = ink_atomic_increment((int *) &ninfos, 1) + 1; + ink_assert(id != 0); + ink_assert(id <= MAX_CONFIGS); + } + + info->m_refcount = 1; + + if (id > MAX_CONFIGS) { + // invalid index + Error("[ConfigProcessor::set] invalid index"); + return 0; + } + + idx = id - 1; + + do { + old_info = (ConfigInfo *) infos[idx]; + } while (!ink_atomic_cas_ptr((pvvoidp) & infos[idx], old_info, info)); + + if (old_info) { + eventProcessor.schedule_in(NEW(new ConfigInfoReleaser(id, old_info)), HRTIME_SECONDS(60)); + } + + return id; +} + +ConfigInfo * +ConfigProcessor::get(unsigned int id) +{ + ConfigInfo *info; + int idx; + + ink_assert(id != 0); + ink_assert(id <= MAX_CONFIGS); + + if (id == 0 || id > MAX_CONFIGS) { + // return NULL, because we of an invalid index + return NULL; + } + + idx = id - 1; + info = (ConfigInfo *) infos[idx]; + if (ink_atomic_increment((int *) &info->m_refcount, 1) < 0) { + ink_assert(!"not reached"); + } + + return info; +} + +void +ConfigProcessor::release(unsigned int id, ConfigInfo * info) +{ + int val; + int idx; + + ink_assert(id != 0); + ink_assert(id <= MAX_CONFIGS); + + if (id == 0 || id > MAX_CONFIGS) { + // nothing to delete since we have an invalid index + return; + } + + idx = id - 1; + val = ink_atomic_increment((int *) &info->m_refcount, -1); + + if ((infos[idx] != info) && (val == 1)) { + delete info; + } +} diff --git a/proxy/ProxyConfig.h b/proxy/ProxyConfig.h new file mode 100644 index 00000000..40952a91 --- /dev/null +++ b/proxy/ProxyConfig.h @@ -0,0 +1,84 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + ProxyConfig.h + + + ****************************************************************************/ + +#ifndef _Proxy_Config_h +#define _Proxy_Config_h + +#include "libts.h" +#include "ProcessManager.h" +#include "Error.h" + +void *config_int_cb(void *data, void *value); +void *config_long_long_cb(void *data, void *value); +void *config_float_cb(void *data, void *value); +void *config_string511_cb(void *data, void *value); +void *config_string_alloc_cb(void *data, void *value); + +// +// Macros that spin waiting for the data to be bound +// +#define SignalManager(_n,_d) pmgmt->signalManager(_n,(char*)_d) +#define SignalWarning(_n,_s) { Warning(_s); SignalManager(_n,_s); } + +#define RegisterMgmtCallback(_signal,_fn,_data) \ +pmgmt->registerMgmtCallback(_signal,_fn,_data) + + +#define MAX_CONFIGS 100 + + +struct ConfigInfo +{ + volatile int m_refcount; + + virtual ~ ConfigInfo() + { + } +}; + + +class ConfigProcessor +{ +public: + ConfigProcessor(); + + unsigned int set(unsigned int id, ConfigInfo * info); + ConfigInfo *get(unsigned int id); + void release(unsigned int id, ConfigInfo * data); + +public: + volatile ConfigInfo *infos[MAX_CONFIGS]; + volatile int ninfos; +}; + + +extern ConfigProcessor configProcessor; + +#endif diff --git a/proxy/README-stats.otl b/proxy/README-stats.otl new file mode 100644 index 00000000..98f4013c --- /dev/null +++ b/proxy/README-stats.otl @@ -0,0 +1,615 @@ +--------------------------------------------------------------------------------- + STATS + +--------------------------------------------------------------------------------- +The following are the list of problems associated with the +existing stat system: +1) atomicity issues +2) consistency and coupling issues +3) clearing +4) persistence +5) aggregation and derivation +6) relationship with manager. + +Specifically, some of the stats reported seemed incorrect. +In the cases where individual stats were incorrect (e.g. +number of bytes transferred), it is suspected that atomicity +issues played a role. For example, if the stat variable was +64 bits long, were all 64 bits being read and written atomically? +Is there the possibility that while the lower/higher 32 bits +were being accessed, the other 32 bits were being changed? + +In stats which were computed based on other stats (e.g. hit +rate is ratio of number of cache hits over total number of +cache lookups), it is suspected that there were coupling problems. +For example, if the number of cache hits is read and then +before the number of cache lookups can be read, it is updated, +the hit rate may appear incorrect. + +Some stats are interrelated with other stats (e.g. number of +client requests and number of cache lookups). Inconsistencies +between such stats may show up if for example one of the +values is accessed and before the other value is accessed, it +is allowed to change. A single client request may then, for example, +show two cache lookups. + +These issues can be aggravated by allowing administrators to +clear stat values. This lead us to introduce persistence: +disallow clearing of stats. While this does deal with the problems +associated with clearing, it does not address the coupling, +inconsistency or atomicity problems. Those remain. + +The remaining issues, those of aggregation and interaction with +the manager did not suffer from any fundamental design problems. +They were more implementation related issues. + +A new stat system which deals correctly with the issues of +atomicity, consistency and coupling will automatically address +the clearing and persistence problem. Atomicity can be handled +very simply by either of two techniques: +1) make ALL accesses to stat variable atomic operations or +2) protect ALL accesses to stat variables by placing them + within critical regions. + +The inconsistency and coupling problem is two-fold in nature. +There is the problem of grouping - in that related stats (either +indirectly, as illustrated by the inconsistency example, or +directly as illustrated by the coupling example), may be grouped +together. Access to either one of them, then, if controlled, will +guarantee that the other is not concurrently modified. So, this +will prevent values from changing while related values are being +accessed. It will not, however, solve the problem of maintaining +"transactional" consistency. Look at the number of request/ +number of cache lookup example again. If the stat for the number +of requests is updated. Then the stat for the number of cache +lookups is updated, with both updates being within critical regions, +if the values of both stats are accessed in the time between when +one is updated and when the other is updated, the inconsistency +problem remains. So, even though the stats are grouped together in +that they are accessed through the same mutex, for example, the +inconsistency problem remains. It can be solved only if we introduce +the notion of a transaction. All stats which are for the same +transaction must be updated together. The values of these stats +at any time, then, will be consistent. This is a more difficult +problem, because not only does it introduce grouping in space, +it introduces grouping in time as well. Unfortunately, an implementation +requires the notion of "local" and "global" stats. + +Now, stats fall into three categories: +1) transactional (dyanmic) stats: e.g. number of current origin server + connections, +2) incremental stats: number of bytes from origin server, +3) transactional stats: number of requests served. + +Stats of type 1) need to just be accessed atomically. They do not +need to be cleared. Stats of type 2) need to also be accessed atomically, +and may need to be cleared. They are not related to other stats, so they +do not need to be grouped. Stats of type 3) need to be accessed atomically, +but they are grouped and so must be accessed simultaneously in space-time. + +The three types of stats can be implemented with three different mechanisms, +or a single mechanism can be defined which handles all three types. The latter +approach is more elegant, but it raises questions about performance. + +Since transactional stats have to be accessed together, it is logical to +control access to them through a single lock. A stat structure, then, can +be defined to have a lock which controls access. For individual stats which +require just atomic access, however, it may be better to allow direct +access, without getting a lock. This may reduce lock contention. + +We ran two experiments to investigate the performance issue. +The existing stat system allows for individual atomic access to all stats. +We compared the performance of this system with a system where instead of +atomic access, all access requires getting a single lock. The results from +inkbench are as follows. + +[keep_alive =4, 100% Hit rate, 4 client machines, 40 simultaneous users ] +atomic: 526 ops/sec +mutex: 499 ops/sec + +Changing the setup to proxy-only, which reduces the number of +simultaneous accesses, gave: + +[keep_alive =4, proxy-only, 4 client machines, 40 simultaneous users ] +atomic: 284 ops/sec +mutex: 282 ops/sec + +We also ran the test with stats turned off, which gave unexpected results. +It is unclear, however, how much we really turn the stats off (there were +even compile-time problems and many of the stat reading/writing routines +were still being called, etc.). + +In addition to the tests mentioned above, we spoke to Prof. Dirk +Grunwald. He said that the most expensive operations are the memory +barriers. On the Alphas, atomic operations are implemented with +load-locked, store- conditional and memory-barrier instructions. I +think each operation is implemented with 2 mbs. Locks and Releases +have one mb each. So, the number of mbs is much higher with atomic +updates. Both atomic updates and mutex-based updates will have to pay +similar cache loading costs (if we assume that the loads for the +test-and-set and the loads for reads will fail, the stores will +obviously hit). The difference, if any, will come from the contention +for locks while all of the group elements are being updated and that +has to be compared with the cost of as many mbs as the stats are being +atomically updated. Context-switching while holding the lock may also +result in a performance hit, but it may be possible to address this by +doing "lazy" updates of global structures. + +The consensus, then is to have a single mechanism for access to stats: +mutexes. This combined with a grouping scheme solves the atomicity, +consistency, coupling, clearing and persistence problems. + + +--------------------------------------------------------------------------------- +Brian's Rant: +------------- +In any case, I want to change the stats system once to address all the issues +of clearing, persistence, monotonicity, coupled computations, cluster +aggregation, etc. Let's be sure we all understand the design issues and do +the right thing one time. We've gone through lots of band-aids in the past +which got us nowhere, so let's get the design right. +--------------------------------------------------------------------------------- +Issues: +------- +1) Clearing +2) Persistence +3) Monotonicity +4) Coupled computations +5) Cluster aggregation +6) Inconsistencies between related stats + +- Want to be able to clear stats +- Do not want to see inconsistencies between stats + +stats which increase and decrease (e.g. current open connections should +not be clearable) + +persistent stats should not be clearable + +related stats should be updated together (updated/cleared) + +divide stats into 2 groups: +1) dynamic stats - not clearable, read,written singly, atomically +2) grouped stats - must be updated together + +--------------------------------------------------------------------------------- +Types Of Stats: +--------------- +* event system stats + ** average idle time per thread + ** variance of idle time per thread + ** average event exec rate per thread + ** variance of event exec rate per thread + ** average execution time per event + ** variance of execution time per event + ** average failed mutexes per event + ** variance of failed mutexes per event + ** average time lag per event + ** variance of time lag per event + +* socks processor stats + ** connections unsuccessful + ** connections successful + ** connections currently open + +--------------------------------------------------------------------------------- +* cache stats + *** total size in bytes + *** # cache operations in progress + *** Read bandwidth from the disk + *** Write bandwidth to the disk + *** RAM cache hit-rate. + *** Read operations per second. + *** Write operations per second. + *** Update operations per second. + *** Delete operations per second. + *** Operations per second. + +--------------------------------------------------------------------------------- +* ICP Stats +proxy.process.icp.config_mgmt_callouts + - Manager callouts for ICP config changes + +proxy.process.icp.reconfig_polls + - ICP config change periodic polls + +proxy.process.icp.reconfig_events + - ICP config change polls which detected config changes + +proxy.process.icp.invalid_poll_data + - Negative event callouts with invalid poll data + +proxy.process.icp.no_data_read + - Read on ICP socket returned <= 0 bytes + +proxy.process.icp.short_read + - ICP msg len != bytes read + +proxy.process.icp.invalid_sender + - ICP msg sender unknown + +proxy.process.icp.read_not_v2_icp + - Sent ICP msg not version 2 + +(UI) proxy.process.icp.icp_remote_query_requests + - Remote ICP query requests received + + proxy.process.icp.icp_remote_responses + - ICP replies received for locally generated queries + +(UI) proxy.process.icp.cache_lookup_success + - ICP queries resulting in Cache lookup success + +(UI) proxy.process.icp.cache_lookup_fail + - ICP queries resulting in Cache lookup failure + +(UI) proxy.process.icp.query_response_write + - ICP query responses sent + +proxy.process.icp.query_response_partial_write + - ICP query responses which were short writes + +proxy.process.icp.no_icp_request_for_response + - Received ICP query responses associated with no ICP request + +proxy.process.icp.icp_response_request_nolock + - ICP request lock acquire miss + +proxy.process.icp.icp_start_icpoff + - Local ICP queries aborted due to ICP off + +proxy.process.icp.send_query_partial_write + - ICP query sends which were short writes + +proxy.process.icp.icp_queries_no_expected_replies + - Local ICP queries sent where no response was expected + +(UI) proxy.process.icp.icp_query_hits + - ICP hits received for locally generated queries + +(UI) proxy.process.icp.icp_query_misses + - ICP misses received for locally generated queries + +proxy.process.icp.invalid_icp_query_response + - ICP responses with invalid opcodes + +(UI) proxy.process.icp.icp_query_requests + - Locally generated ICP requests + +(UI) proxy.process.icp.total_icp_response_time + - Avg response time of each locally generated ICP query + +(UI) proxy.process.icp.total_udp_send_queries + - Total ICP query sends + +(UI) proxy.process.icp.total_icp_request_time + - Overall avg response time of locally generated ICP request +--------------------------------------------------------------------------------- +* hostdb/dns stats + ** hostdb + *** total entries + *** total number of lookups + *** total number of hits + *** total number of misses + *** hit rate??? (or do we just compute this) + // to help tuning + *** average TTL remaining for hosts looked up + *** total number re-DNS because of re-DNS on reload + *** total number re-DNS because TTL expired + ** dns + *** total number of lookups + *** total number of hits + *** total number of misses + *** average service time + // to help tuning + *** total number of retries + *** total number which failed with too many retries +--------------------------------------------------------------------------------- +* network stats +> ** incoming connections stats + shouldn't these stats be by protocol??? +> *** average b/w for each connection + at the net level, I don't always know when I should be expecting bytes. + for example, a keepalive connection may expect more bytes and then not + get them. When do I start and stop the timer??? This needs some thought +> *** average latency for each connection + same as above. perhaps + *** latency to first byte on an accept + however for "latency to first by of a response" I would need to know when + the request was done, but that is a protocol level issue. +> *** number of documents/connection (keep-alive) + this is a protocol issue (http) +> *** number aborted + I could record how many received a do_io(VIO::ABORT) for what that + is worth... maybe this is also a protocol issue + *** high/low watermark number of simultaneous connections + *** high/low watermark number of connection time + is this last one useful?? +> ** outgoing connections stats +> *** average b/w for each connection +> *** average latency for each connection +> *** number of documents/connection (keep-alive) +> *** number aborted + see above + *** high/low watermark number of simultaneous connections + *** high/low watermark number of connection time +> ** incoming connections stats + what does this mean?? +> *** average b/w for each connection +> *** average latency for each connection +> *** number aborted + see above +> *** high/low watermark number of simultaneous connections +> *** high/low watermark number of connection time + +--------------------------------------------------------------------------------- +* Http Stats + ** protocol stats + *** number of HTTP requests (need for ua->ts, ts->os) + **** GETs + **** HEADs + **** TRACEs + **** OPTIONs + **** POSTs + **** DELETEs + **** CONNECTs + *** number of invalid requests + *** number of broken client connections + *** number of proxied requests + **** user-specified + **** method-specified + **** config specified (config file) + *** number of requests with Cookies + *** number of cache lookups + **** number of alternates + *** number of cache hits + cache hits, misses, etc. stats should be catagorized + the same way they are categorized in WUTS (squid logs). + **** fresh hits + **** stale hits + ***** heuristically stale + ***** expired/max-aged + *** number of cache writes + *** number of cache updates + *** number of cache deletes + *** number of valid responses + *** number of invalid responses + *** number of retried requests + *** number of broken server connections + + *** For each response code, count the number of responses (need for ua->ts, ts->os) + *** Histogram of http version (need for ua->ts, ts->os) + *** number of responses with expires + *** number of responses with last-modified + *** number of responses with age + *** number of responses indicating server clock skew + *** number of responses preventing cache store + **** Set-Cookie + **** Cache-Control: no-store + *** number of responses proxied directly + ** Timeouts and connection errors: + *** accept timeout (ua -> proxy only) + *** background fill timeout (os -> proxy only) + *** normal inactive timeout (both ua -> proxy and proxy -> os) + *** normal activity timeout (both ua -> proxy and proxy -> os) + *** keep-alive idle timeout (both ua -> proxy and proxy -> os) + ** Connections and transactions time: + *** average requests count per connection (both ua and os). + *** average connection lifetime (both ua and os). + *** average connection utilization (connection time / transactions count). + *** average transaction time (from transaction start until transaction end). + *** average transaction time histogram per document sizes. + sizes are: + <= 100 bytes, <= 1K, <= 3K, <= 5K, <= 10L, <= 1M, <= infinity + *** average transaction processing time (think time). + *** average transaction processing time (think time) histogram per document sizes. + ** Transfer rate: + *** bytes per second ua connection and os connection. + *** bytes per second ua connection and os connection histogram per document size. + ** Cache Stats + *** cache lookup time hit + *** cache lookup time miss + *** cache open read time + *** cache open write time +--------------------------------------------------------------------------------- +* loggin stats +// bytes moved +STAT(Sum, log2_stat_bytes_buffered), +STAT(Sum, log2_stat_bytes_written_to_disk), +STAT(Sum, log2_stat_bytes_sent_to_network), +STAT(Sum, log2_stat_bytes_received_from_network), +// I/O +STAT(Count, log2_stat_log_files_open), UI +STAT(Count, log2_stat_log_files_space_used), UI +// events +STAT(Count, log2_stat_event_log_error), UI +STAT(Count, log2_stat_event_log_access), UI +STAT(Count, log2_stat_event_log_access_fail), +STAT(Count, log2_stat_event_log_access_skip), UI + +--------------------------------------------------------------------------------- +------------ +Here's my version of the 20-stats list for the UI. I gathered all of the +stats proposed from our meeting last Thursday, added requests from Tait +Kirkham and Brian Totty, then added a few based on pilot site questions and +customer's monitoring scripts. Not all of these additional requests are +necessarily possible to measure. Sorted the proposed statistics into groups +based on the kind of information they provide the proxy administrator. Then I +picked the ones that seemed most important to me for the top 20 list. From +the top-level statistics page there should be links to pages with more detail +in each operational area. + +A few notes: +"Average" statistics should be calculated over an interval configurable as 1 +minute, 5 minutes or 15 minutes. This includes the cache hit rate. Probably +the cache detail info page should have a value for the overall average. +Numbers and measurements in the user interface are presented for the +convenience of the customer, and should be organized to suit customer needs +and interests. Statistics from the operating system, the HTTP state machine, +and anywhere else may be combined to create info presented in the UI. +----------------------------------------------------------- + + Statistics in the Traffic Manager UI + Top "20" Recommended List + +Client Responsiveness +avg/max total transaction time -- request received to last byte sent. +number of client aborts +network bytes/sec/client + +Proxy Activity +total/max active client connections +total/max active server connections +total/max active cache connections +total/max active parent proxy connections +average transaction rate +total transaction count per protocol {dns, http, rtsp} +total bytes served to clients +total bytes from origin servers +total bytes from parent proxies +bandwidth savings: % -- bandwidth per interface, per route options? + +Cache +cache utilization % +avg cache hit rate +cache revalidates + +----------------------------------------------------------------------------------------------------------------- + + Statistics in the Traffic Manager + The Whole List + +Client Responsiveness +avg/max time to first byte -- request received to first byte sent. +avg/max total transaction time -- request received to last byte sent. +avg transaction time by type of transaction: + cache write + non-cached + client revalidate + proxy revalidate + proxy refresh +number of client aborts +network bytes/sec/client + +Proxy Activity +total/max active client connections +total/max active server connections +total/max active cache connections +number of active connections by connection status: ESTABLISHED, CLOSE_WAIT, +TIME_WAIT, ... +total transaction count per protocol {dns, http, rtsp} +total/max active parent proxy connections +total bytes served to clients +total bytes from origin servers +total bytes from parent proxies +bandwidth savings: bytes / % +number of TCP retransmits per client +ps-like status report of Traffic Server operations + +System Utilization +proxy network utilization % +cpu utilization % +disk utilization % +memory (RAM) utilization % + +Cache +total cache free space +cache utilization % +avg cache hit rate +cache revalidates: + client-specified + expired (expire/max-age) + expired (heuristic) +cache miss time +cache hit time + +Logging +total logging space used + +Cluster +cluster network utilization % + +ICP +total icp responses +icp hit rate +total icp requests +--------------------------------------------------------------------------------- +Subject: Re: Simple UI for TS100 +Date: Thu, 26 Mar 1998 11:48:15 -0800 + +>From a Support standpoint, I do have some reservations about hacking +information and function out of the Traffic Manager for TS Lite. Less +information in the Monitor makes it more difficult to observe Traffic Server +operation. Less functionality in Configure means more manual editting of +config files and greater chance of admin errors. These factors could greatly +increase our support problems and cost for "Lite" customers. + +Perhaps the TS Lite UI should just remove all cluster-related information +and controls, and material related to any other features that simply will +not be offered on TS Lite, like the maximum network connection limit. Other +counters and controls that relate to functions and features that are +operational in TS Lite could be left alone. There're already present in TS +Classic, so it costs us nothing extra. + +----------------------------------- + +Within the framework of Adam's proposal, the "Monitor" manager reduces to a +single screen. Great! With only one screen, gotta be sure that the key +top-level statistics are visible. I suggest that cache free is not really a +very interesting value for most sites. Bandwidth savings is the value we +really want to emphasize, so it must not disappear. So the Dashboard should +have its current "More Info" stats plus + cache size + DNS Hit rate + Bandwidth savings + tps count (the tps meter is nice, but can't be read very precisely) +The More/Less detail option itself can disappear. The word "cluster" should +not occur anywhere in the TS Lite UI. + +In Configure: Server the node on/off switch and the cluster restart button +are redundant in TS Lite. Probably ought to lose the cluster button. A +configurable Traffic Server name also seems useless when you can't have a +cluster. + +For Configure: Logging, perhaps custom log formatting should not be offered +for TS Lite? + +With reduced UI configuration capability, it may be appropriate to remove +the Configure: Snapshots screen. + +Adam Beguelin wrote: + +> For TS100 we need a simplified UI. Here's a first cut on how we should +> simplify the UI. +> +> For most of the removed pages we will simply use the installed defaults. +> +> Comments? +> +> Adam +> +> On the dashboard add these stats: +> o Cahce Free Space +> o Cache Size +> o DNS Hit rate +> +> Remove these monitor pages: +> o node +> o Graphs +> o Protocols +> o Cache +> o Other +> +> Remove these sections under configure: +> o Server/Throttling of Network Connections +> o Protocols/HTTP timeouts (Leave anon and IP) +> o Protocols/SSL +> o Cache/Storage +> o Cache/Garbage Collection +> o Cache/Freshness +> o Cache/Variable Content +> o HostDB page +> o Logging/Log Collation +--------------------------------------------------------------------------------- +--------------------------------------------------------------------------------- +--------------------------------------------------------------------------------- diff --git a/proxy/RegressionSM.cc b/proxy/RegressionSM.cc new file mode 100644 index 00000000..ab68a938 --- /dev/null +++ b/proxy/RegressionSM.cc @@ -0,0 +1,259 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "P_EventSystem.h" +#include "RegressionSM.h" + +#define REGRESSION_SM_RETRY (100*HRTIME_MSECOND) + +void RegressionSM::set_status(int astatus) +{ + ink_assert(astatus != REGRESSION_TEST_INPROGRESS); + // INPROGRESS < NOT_RUN < PASSED < FAILED + if (status != REGRESSION_TEST_FAILED) { + if (status == REGRESSION_TEST_PASSED) { + if (astatus != REGRESSION_TEST_NOT_RUN) + status = astatus; + } else { + // INPROGRESS or NOT_RUN + status = astatus; + } + } // else FAILED is FAILED +} + +void RegressionSM::done(int astatus) +{ + if (pending_action) { + pending_action->cancel(); + pending_action = 0; + } + set_status(astatus); + if (pstatus) *pstatus = status; + if (parent) parent->child_done(status); +} + +void RegressionSM::run(int *apstatus) +{ + pstatus = apstatus; + run(); +} + +void RegressionSM::xrun(RegressionSM *aparent) +{ + parent = aparent; + parent->nwaiting++; + run(); +} + +void RegressionSM::run_in(int *apstatus, ink_hrtime t) +{ + pstatus = apstatus; + SET_HANDLER(&RegressionSM::regression_sm_start); + eventProcessor.schedule_in(this, t); +} + +void RegressionSM::child_done(int astatus) +{ + MUTEX_LOCK(l, mutex, this_ethread()); + ink_assert(nwaiting > 0); + --nwaiting; + set_status(astatus); +} + +int RegressionSM::regression_sm_waiting(int event, void *data) +{ + NOWARN_UNUSED(event); + if (!nwaiting) { + done(REGRESSION_TEST_NOT_RUN); + delete this; + return EVENT_DONE; + } + if (par || nwaiting > 1) { + ((Event*)data)->schedule_in(REGRESSION_SM_RETRY); + return EVENT_CONT; + } + run(); + return EVENT_DONE; +} + +int RegressionSM::regression_sm_start(int event, void *data) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + run(); + return EVENT_CONT; +} + +RegressionSM *r_sequential(RegressionTest *t, RegressionSM* sm, ...) +{ + RegressionSM *new_sm = new RegressionSM(t); + va_list ap; + va_start(ap, sm); + new_sm->par = false; + new_sm->rep = false; + new_sm->ichild = 0; + new_sm->nchildren = 0; + new_sm->nwaiting = 0; + while (0 != sm) { + new_sm->children(new_sm->nchildren++) = sm; + sm = va_arg(ap, RegressionSM*); + } + new_sm->n = new_sm->nchildren; + va_end(ap); + return new_sm; +} + +RegressionSM *r_sequential(RegressionTest *t, int an, RegressionSM *sm) +{ + RegressionSM *new_sm = new RegressionSM(t); + new_sm->par = false; + new_sm->rep = true; + new_sm->ichild = 0; + new_sm->nchildren = 1; + new_sm->children(0) = sm; + new_sm->nwaiting = 0; + new_sm->n = an; + return new_sm; +} + +RegressionSM *r_parallel(RegressionTest *t, RegressionSM *sm, ...) +{ + RegressionSM *new_sm = new RegressionSM(t); + va_list ap; + va_start(ap, sm); + new_sm->par = true; + new_sm->rep = false; + new_sm->ichild = 0; + new_sm->nchildren = 0; + new_sm->nwaiting = 0; + while (sm) { + new_sm->children(new_sm->nchildren++) = sm; + sm = va_arg(ap, RegressionSM*); + } + new_sm->n = new_sm->nchildren; + va_end(ap); + return new_sm; +} + +RegressionSM *r_parallel(RegressionTest *t, int an, RegressionSM *sm) +{ + RegressionSM *new_sm = new RegressionSM(t); + new_sm->par = true; + new_sm->rep = true; + new_sm->ichild = 0; + new_sm->nchildren = 1; + new_sm->children(0) = sm; + new_sm->nwaiting = 0; + new_sm->n = an; + return new_sm; +} + +void RegressionSM::run() +{ + // TODO: Why introduce another scope here? + { + MUTEX_TRY_LOCK(l, mutex, this_ethread()); + if (!l || nwaiting > 1) + goto Lretry; + RegressionSM *x = 0; + while (ichild < n) { + if (!rep) + x = children[ichild]; + else { + if (ichild != n-1) + x = children[(intptr_t)0]->clone(); + else + x = children[(intptr_t)0]; + } + if (!ichild) nwaiting++; + x->xrun(this); + ichild++; + if (!par && nwaiting > 1) + goto Lretry; + } + } + nwaiting--; + if (!nwaiting) { + done(REGRESSION_TEST_NOT_RUN); + delete this; + return; + } +Lretry: + SET_HANDLER(&RegressionSM::regression_sm_waiting); + pending_action = eventProcessor.schedule_in(this, REGRESSION_SM_RETRY); +} + +RegressionSM::RegressionSM(const RegressionSM &ao) +{ + RegressionSM &o = *(RegressionSM*)&ao; + t = o.t; + status = o.status; + pstatus = o.pstatus; + parent = &o; + nwaiting = o.nwaiting; + nchildren = o.nchildren; + for (intptr_t i = 0; i < nchildren; i++) + children(i) = o.children[i]->clone(); + n = o.n; + ichild = o.ichild; + par = o.par; + rep = o.rep; + pending_action = o.pending_action; + ink_assert(status == REGRESSION_TEST_INPROGRESS); + ink_assert(nwaiting == 0); + ink_assert(ichild == 0); + mutex = new_ProxyMutex(); +} + +struct ReRegressionSM: public RegressionSM +{ + virtual void run() { + if (time(NULL) < 1) { // example test + rprintf(t,"impossible"); + done(REGRESSION_TEST_FAILED); + } else + done(REGRESSION_TEST_PASSED); + } + ReRegressionSM(RegressionTest *at) : RegressionSM(at) {} + virtual RegressionSM *clone() { return new ReRegressionSM(*this); } + ReRegressionSM(const ReRegressionSM &o) { + t = o.t; + } +}; + +REGRESSION_TEST(RegressionSM)(RegressionTest *t, int atype, int *pstatus) +{ + NOWARN_UNUSED(atype); + r_sequential( + t, + r_parallel(t, new ReRegressionSM(t), new ReRegressionSM(t), NULL_PTR), + r_sequential(t, new ReRegressionSM(t), new ReRegressionSM(t), NULL_PTR), + r_parallel(t, 3, new ReRegressionSM(t)), + r_sequential(t, 3, new ReRegressionSM(t)), + r_parallel( + t, + r_sequential(t, 2, new ReRegressionSM(t)), + r_parallel(t, 2, new ReRegressionSM(t)), + NULL_PTR), + NULL_PTR)->run(pstatus); +} diff --git a/proxy/RegressionSM.h b/proxy/RegressionSM.h new file mode 100644 index 00000000..72c9c060 --- /dev/null +++ b/proxy/RegressionSM.h @@ -0,0 +1,80 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _RegressionSM_h +#define _RegressionSM_h + +#include "I_EventSystem.h" + +/* + Regression Test Composition State Machine + + See RegressionSM.cc at the end for an example +*/ + +struct RegressionSM : public Continuation { + + RegressionTest *t; // for use with rprint + + // methods to override + virtual void run(); // replace with leaf regression + virtual RegressionSM *clone() { return new RegressionSM(*this); } // replace for run_xxx(int n,...); + + // public API + void done(int status = REGRESSION_TEST_NOT_RUN); + void run(int *pstatus); + void run_in(int *pstatus, ink_hrtime t); + + // internal + int status; + int *pstatus; + RegressionSM *parent; + int nwaiting; + int nchildren; + DynArray children; + intptr_t n, ichild; + bool par, rep; + Action *pending_action; + + int regression_sm_start(int event, void *data); + int regression_sm_waiting(int event, void *data); + void set_status(int status); + void child_done(int status); + void xrun(RegressionSM *parent); + + RegressionSM(RegressionTest *at = NULL) : + t(at), status(REGRESSION_TEST_INPROGRESS), + pstatus(0), parent(0), nwaiting(0), nchildren(0), children(0), ichild(0), par(false), rep(false), + pending_action(0) + { + mutex = new_ProxyMutex(); + } + RegressionSM(const RegressionSM &); +}; + +RegressionSM *r_sequential(RegressionTest *t, int n, RegressionSM *sm); +RegressionSM *r_sequential(RegressionTest *t, RegressionSM *sm, ...); // terminate list in NULL +RegressionSM *r_parallel(RegressionTest *t, int n, RegressionSM *sm); +RegressionSM *r_parallel(RegressionTest *t, RegressionSM *sm, ...); // terminate list in NULL + +#endif diff --git a/proxy/ReverseProxy.cc b/proxy/ReverseProxy.cc new file mode 100644 index 00000000..e9631c3e --- /dev/null +++ b/proxy/ReverseProxy.cc @@ -0,0 +1,241 @@ +/** @file + + Definitions for reverse proxy + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section details Details + + Implements code necessary for Reverse Proxy which mostly consists of + general purpose hostname substitution in URLs. + + */ + +#include "libts.h" +#include +#include "Main.h" +#include "Error.h" +#include "P_EventSystem.h" +#include "StatSystem.h" +#include "P_Cache.h" +#include "ProxyConfig.h" +#include "ReverseProxy.h" +#include "MatcherUtils.h" +#include "Tokenizer.h" +#include "api/ts/remap.h" +#include "RemapPluginInfo.h" +#include "RemapProcessor.h" +#include "UrlRewrite.h" +#include "UrlMapping.h" +#include "StringHash.h" +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ + +/** Time till we free the old stuff after a reconfiguration. */ +#define URL_REWRITE_TIMEOUT (HRTIME_SECOND*60) + +// Global Ptrs +static Ptr reconfig_mutex = NULL; +UrlRewrite *rewrite_table = NULL; +remap_plugin_info *remap_pi_list; // We never reload the remap plugins, just append to 'em. + +// Tokens for the Callback function +#define FILE_CHANGED 0 +#define REVERSE_CHANGED 1 +#define TSNAME_CHANGED 2 +#define AC_PORT_CHANGED 3 +#define TRANS_CHANGED 4 +#define DEFAULT_TO_PAC_CHANGED 5 +#define DEFAULT_TO_PAC_PORT_CHANGED 7 +#define URL_REMAP_MODE_CHANGED 8 +#define HTTP_DEFAULT_REDIRECT_CHANGED 9 + +int url_remap_mode; + +// +// Begin API Functions +// + +int +init_reverse_proxy() +{ + ink_assert(rewrite_table == NULL); + reconfig_mutex = new_ProxyMutex(); + rewrite_table = NEW(new UrlRewrite("proxy.config.url_remap.filename")); + + if (!rewrite_table->is_valid()) { + Warning("Can not load the remap table, exiting out!"); + // TODO: For now, I _exit() out of here, because otherwise we'll keep generating + // core files (if enabled) when starting up with a bad remap.config file. + _exit(-1); + } + + REVERSE_RegisterConfigUpdateFunc("proxy.config.url_remap.filename", url_rewrite_CB, (void *) FILE_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.proxy_name", url_rewrite_CB, (void *) TSNAME_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.reverse_proxy.enabled", url_rewrite_CB, (void *) REVERSE_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.admin.autoconf_port", url_rewrite_CB, (void *) AC_PORT_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.url_remap.default_to_server_pac", url_rewrite_CB, (void *) DEFAULT_TO_PAC_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.url_remap.default_to_server_pac_port", url_rewrite_CB, (void *) DEFAULT_TO_PAC_PORT_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.url_remap.url_remap_mode", url_rewrite_CB, (void *) URL_REMAP_MODE_CHANGED); + REVERSE_RegisterConfigUpdateFunc("proxy.config.http.referer_default_redirect", url_rewrite_CB, (void *) HTTP_DEFAULT_REDIRECT_CHANGED); + return 0; +} + +// TODO: This function needs to be rewritten (or replaced) with something that uses the new +// Remap Processor properly. Right now, we effectively don't support "remap" rules on a few +// odd ball configs, for example if you use the "CONNECT" method, or if you set +// set proxy.config.url_remap.url_remap_mode to "2" (which is a completely undocumented "feature"). +bool +request_url_remap(HttpTransact::State * s, HTTPHdr * request_header, char **redirect_url, char **orig_url, + unsigned int filter_mask) +{ + NOWARN_UNUSED(s); + NOWARN_UNUSED(request_header); + NOWARN_UNUSED(redirect_url); + NOWARN_UNUSED(orig_url); + NOWARN_UNUSED(filter_mask); + return false; + // return rewrite_table ? rewrite_table->Remap(s, request_header, redirect_url, orig_url, tag, filter_mask) : false; +} + +/** + This function is used to figure out if a URL needs to be remapped + according to the rules in remap.config. +*/ +mapping_type +request_url_remap_redirect(HTTPHdr *request_header, URL *redirect_url, char **orig_url) +{ + return rewrite_table ? rewrite_table->Remap_redirect(request_header, redirect_url, orig_url) : NONE; +} + +bool +response_url_remap(HTTPHdr *response_header) +{ + return rewrite_table ? rewrite_table->ReverseMap(response_header) : false; +} + + +// +// +// End API Functions +// + +/** Used to read the remap.config file after the manager signals a change. */ +struct UR_UpdateContinuation; +typedef int (UR_UpdateContinuation::*UR_UpdContHandler) (int, void *); +struct UR_UpdateContinuation: public Continuation +{ + int file_update_handler(int etype, void *data) + { + NOWARN_UNUSED(etype); + NOWARN_UNUSED(data); + + reloadUrlRewrite(); + delete this; + return EVENT_DONE; + } + UR_UpdateContinuation(ProxyMutex * m) + : Continuation(m) + { + SET_HANDLER((UR_UpdContHandler) & UR_UpdateContinuation::file_update_handler); + } +}; + +struct UR_FreerContinuation; +typedef int (UR_FreerContinuation::*UR_FreerContHandler) (int, void *); + +/** Used to free url rewrite class. */ +struct UR_FreerContinuation: public Continuation +{ + UrlRewrite *p; + int freeEvent(int event, Event * e) + { + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + Debug("url_rewrite", "Deleting old remap.config table"); + delete p; + delete this; + return EVENT_DONE; + } + UR_FreerContinuation(UrlRewrite * ap):Continuation(new_ProxyMutex()), p(ap) + { + SET_HANDLER((UR_FreerContHandler) & UR_FreerContinuation::freeEvent); + } +}; + +/** + Called when the remap.config file changes. Since it called infrequently, + we do the load of new file as blocking I/O and lock aquire is also + blocking. + +*/ +void +reloadUrlRewrite() +{ + UrlRewrite *newTable; + + Debug("url_rewrite", "remap.config updated, reloading..."); + newTable = new UrlRewrite("proxy.config.url_remap.filename"); + if (newTable->is_valid()) { + eventProcessor.schedule_in(new UR_FreerContinuation(rewrite_table), URL_REWRITE_TIMEOUT, ET_TASK); + Debug("url_rewrite", "remap.config done reloading!"); + ink_atomic_swap_ptr(&rewrite_table, newTable); + } else { + static const char* msg = "failed to reload remap.config, not replacing!"; + delete newTable; + Debug("url_rewrite", msg); + Warning(msg); + } +} + +int +url_rewrite_CB(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data_type); + int my_token = (int) (long) cookie; + + switch (my_token) { + case REVERSE_CHANGED: + rewrite_table->SetReverseFlag(data.rec_int); + break; + + case TSNAME_CHANGED: + case DEFAULT_TO_PAC_CHANGED: + case DEFAULT_TO_PAC_PORT_CHANGED: + case FILE_CHANGED: + case HTTP_DEFAULT_REDIRECT_CHANGED: + eventProcessor.schedule_imm(NEW(new UR_UpdateContinuation(reconfig_mutex)), ET_TASK); + break; + + case AC_PORT_CHANGED: + // The AutoConf port does not current change on manager except at restart + break; + + case URL_REMAP_MODE_CHANGED: + // You need to restart TS. + break; + + default: + ink_assert(0); + break; + } + + return 0; +} + diff --git a/proxy/ReverseProxy.h b/proxy/ReverseProxy.h new file mode 100644 index 00000000..07ee6143 --- /dev/null +++ b/proxy/ReverseProxy.h @@ -0,0 +1,72 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/***************************************************************************** + * + * ReverseProxy.h - Interface to code necessary for Reverse Proxy + * (which mostly consists of general purpose + * hostname substitution in URLs) + * + * + ****************************************************************************/ + +#ifndef _REVERSE_PROXY_H_ +#define _REVERSE_PROXY_H_ + +#include "P_RecProcess.h" + +#include "ink_hash_table.h" +#include "ink_port.h" +#include "HttpTransact.h" +#include "RemapPluginInfo.h" +#include "UrlRewrite.h" +#include "UrlMapping.h" + +#define EMPTY_PORT_MAPPING (int32_t)~0 + +class url_mapping; +struct host_hdr_info; + +// Variables for the CDN URL Remapping Feature +extern int url_remap_mode; + +extern UrlRewrite *rewrite_table; +extern remap_plugin_info *remap_pi_list; + +// API Functions +int init_reverse_proxy(); + +// Both Return true if a remapping was made and false otherwise +// ebalsa@ Y! -- this happens in the remapProcessor now for the reverse proxy case (not CDN or BlindTunnel) +bool request_url_remap(HttpTransact::State *s, HTTPHdr *request_header, char **redirect_url, char **orig_url, + unsigned int filter_mask = URL_REMAP_FILTER_NONE); + +mapping_type request_url_remap_redirect(HTTPHdr *request_header, URL *redirect_url, char **orig_url); +bool response_url_remap(HTTPHdr *response_header); + +// Reload Functions +void reloadUrlRewrite(); + +int url_rewrite_CB(const char *name, RecDataT data_type, RecData data, void *cookie); + +#endif diff --git a/proxy/Show.h b/proxy/Show.h new file mode 100644 index 00000000..b9b1ad66 --- /dev/null +++ b/proxy/Show.h @@ -0,0 +1,141 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + Show.h + + + ****************************************************************************/ + +#ifndef _Show_h_ +#define _Show_h_ + +#include "StatPages.h" + +#define STREQ_PREFIX(_x,_s) (!strncasecmp(_x,_s,sizeof(_s)-1)) + +struct ShowCont; +typedef int (ShowCont::*ShowContEventHandler) (int event, Event * data); +struct ShowCont: public Continuation +{ + Action action; + char *buf, *start, *ebuf; + int iarg; + char *sarg; + + int show(const char *s, ...) + { + va_list aap, va_scratch; + int l = ebuf - buf; + va_start(aap, s); + va_copy(va_scratch, aap); + int done = vsnprintf(buf, l, s, aap); + va_end(va_scratch); + if (done > l - 256) + { + char *start2 = (char *) xrealloc(start, (ebuf - start) * 2); + ebuf = start2 + (ebuf - start) * 2; + buf = start2 + (buf - start); + start = start2; + l = ebuf - buf; + done = vsnprintf(buf, l, s, aap); + if (done > l - 256) + { + va_end(aap); + return EVENT_DONE; + } + buf += done; + } else + buf += done; + + va_end(aap); + return EVENT_CONT; + } + +#define CHECK_SHOW(_x) if (_x == EVENT_DONE) return complete_error(event,e); + + int complete(int event, Event * e) + { + CHECK_SHOW(show("\n\n")); + if (!action.cancelled) { + StatPageData data(start, buf - start); + action.continuation->handleEvent(STAT_PAGE_SUCCESS, &data); + start = 0; + } else { + xfree(start); + start = NULL; + } + return done(VIO::CLOSE, event, e); + } + + int complete_error(int event, Event * e) + { + xfree(start); + start = NULL; + if (!action.cancelled) + action.continuation->handleEvent(STAT_PAGE_FAILURE, NULL); + return done(VIO::ABORT, event, e); + } + + int begin(const char *name) + { + return show("\n%s\n" + "\n" "

%s

\n", name, name); + } + + int showError(int event, Event * e) + { + return complete_error(event, e); + } + + virtual int done(int e, int event, void *data) + { + NOWARN_UNUSED(e); + NOWARN_UNUSED(event); + NOWARN_UNUSED(data); + if (sarg) { + xfree(sarg); + sarg = NULL; + } + delete this; + return EVENT_DONE; + } + +ShowCont(Continuation * c, HTTPHdr * h): + Continuation(NULL), iarg(0), sarg(0) { + NOWARN_UNUSED(h); + mutex = c->mutex; + action = c; + buf = (char *) xmalloc(32000); + start = buf; + ebuf = buf + 32000; + } + ~ShowCont() { + if (start) + xfree(start); + } +}; + + +#endif diff --git a/proxy/SimpleHttp.cc b/proxy/SimpleHttp.cc new file mode 100644 index 00000000..31587016 --- /dev/null +++ b/proxy/SimpleHttp.cc @@ -0,0 +1,890 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include +#include +#include "libts.h" +#include "P_Cache.h" +#include "P_Net.h" +#include "P_HostDB.h" +#include "ProxyConfig.h" +#include "Diags.h" +#include "HTTP.h" + +// TODO: This should be changed later to use TS_HAS_TESTS, but currently, the test +// most likely isn't functional. +#if COMPILE_SIMPLE_HTTP + +#define HISTORY_SIZE 0 +#define HISTORY_DECL +#define HISTORY_MARK() + + +static int enabled = 0; +static int port = 8888; +static int buffer_size = 32 * 1024; +static int buffer_size_idx = BUFFER_SIZE_INDEX_32K; + + +class AcceptCont:public Continuation +{ +public: + AcceptCont(); + + int handle_event(int event, void *edata); +}; + + +class SimpleCont:public Continuation +{ +public: + SimpleCont(); + + static SimpleCont *create(); + void destroy(); + + void start(NetVConnection * ua); + void parse_ua_req(int eof); + void cache_read(void); + void cache_ua_tunnel(void); + void dns_lookup(void); + void os_connect(unsigned int addr); + void os_write_req(void); + void os_read_resp(void); + void parse_os_resp(int eof); + void ua_write_resp(void); + void cache_write(void); + void os_ua_tunnel(void); + void ua_close(void); + void cache_close(void); + void cache_abort(void); + + int ua_read_req_event(int event, void *edata); + int cache_read_event(int event, void *edata); + int cache_ua_tunnel_event(int event, void *edata); + int dns_event(int event, void *edata); + int os_connect_event(int event, void *edata); + int os_write_event(int event, void *edata); + int os_read_resp_event(int event, void *edata); + int cache_write_event(int event, void *edata); + int os_ua_tunnel_event(int event, void *edata); + +public: + HTTPParser m_parser; + Action *m_pending_action; + + NetVConnection *m_ua_vc; + MIOBuffer *m_ua_read_buf; + IOBufferReader *m_ua_reader; + VIO *m_ua_read_vio; + VIO *m_ua_write_vio; + HTTPHdr m_ua_req; + + MIOBuffer *m_ua_write_buf; + int m_ua_resp_size; + + const char *m_os_name; + int m_os_port; + NetVConnection *m_os_vc; + MIOBuffer *m_os_write_buf; + VIO *m_os_write_vio; + VIO *m_os_read_vio; + + MIOBuffer *m_os_read_buf; + IOBufferReader *m_os_reader; + HTTPHdr m_os_resp; + + CacheKey m_key; + VConnection *m_cache_read_vc; + VIO *m_cache_read_vio; + VConnection *m_cache_write_vc; + VIO *m_cache_write_vio; + + HISTORY_DECL}; + + +static ClassAllocator simpleContAllocator("simpleContAllocator"); + + +AcceptCont::AcceptCont() +:Continuation(NULL) +{ + SET_HANDLER(&AcceptCont::handle_event); +} + +int +AcceptCont::handle_event(int event, void *edata) +{ + if (event == NET_EVENT_ACCEPT) { + SimpleCont *sm = SimpleCont::create(); + sm->start((NetVConnection *) edata); + } + return 0; +} + + +SimpleCont::SimpleCont() +:Continuation(NULL), +m_pending_action(NULL), +m_ua_vc(NULL), +m_ua_read_buf(NULL), +m_ua_reader(NULL), +m_ua_read_vio(NULL), +m_ua_write_vio(NULL), +m_ua_req(), +m_ua_write_buf(NULL), +m_ua_resp_size(0), +m_os_name(NULL), +m_os_port(0), +m_os_vc(NULL), +m_os_write_buf(NULL), +m_os_write_vio(NULL), +m_os_read_vio(NULL), +m_os_read_buf(NULL), +m_os_reader(NULL), +m_os_resp(), m_cache_read_vc(NULL), m_cache_read_vio(NULL), m_cache_write_vc(NULL), m_cache_write_vio(NULL) +{ +} + +SimpleCont * +SimpleCont::create() +{ + return simpleContAllocator.alloc(); +} + +void +SimpleCont::destroy() +{ + if (m_pending_action) { + m_pending_action->cancel(); + } + + if (m_ua_vc) { + m_ua_vc->do_io_close(); + } + if (m_os_vc) { + m_os_vc->do_io_close(); + } + if (m_cache_read_vc) { + m_cache_read_vc->do_io_close(1); + } + if (m_cache_write_vc) { + m_cache_write_vc->do_io_close(1); + } + + if (m_ua_read_buf) { + free_MIOBuffer(m_ua_read_buf); + } + if (m_ua_write_buf) { + free_MIOBuffer(m_ua_write_buf); + } + if (m_os_write_buf) { + free_MIOBuffer(m_os_write_buf); + } + if (m_os_read_buf) { + free_MIOBuffer(m_os_read_buf); + } + + m_ua_req.destroy(); + m_os_resp.destroy(); + + mutex = NULL; + + simpleContAllocator.free(this); +} + +void +SimpleCont::start(NetVConnection * ua) +{ + mutex = this_ethread()->mutex; + + http_parser_init(&m_parser); + + m_ua_vc = ua; + m_ua_read_buf = new_MIOBuffer(buffer_size_idx); + m_ua_reader = m_ua_read_buf->alloc_reader(); + + SET_HANDLER(&SimpleCont::ua_read_req_event); + + m_ua_read_vio = m_ua_vc->do_io_read(this, INT64_MAX, m_ua_read_buf); +} + +void +SimpleCont::parse_ua_req(int eof) +{ + const char *start, *p; + const char *end; + int avail; + int err; + + for (;;) { + avail = m_ua_reader->block_read_avail(); + if (!avail) { + if (eof) { + destroy(); + } + return; + } + p = start = m_ua_reader->start(); + end = start + avail; + + err = m_ua_req.parse_req(&m_parser, &p, end, eof); + + m_ua_reader->consume(p - start); + + if (err == PARSE_DONE) { + if (is_debug_tag_set("simple_http")) { + m_ua_req.print(NULL, 0, NULL, NULL); + } + m_ua_read_vio->nbytes = m_ua_read_vio->ndone; + cache_read(); + return; + } + + if (err == PARSE_ERROR) { + destroy(); + return; + } + } + + m_ua_read_vio->reenable(); +} + +void +SimpleCont::cache_read() +{ + URL url; + INK_MD5 md5; + Action *action; + + url = m_ua_req.url_get(); + url.MD5_get(&md5); + m_key.set(md5); + + SET_HANDLER(&SimpleCont::cache_read_event); + + action = cacheProcessor.open_read(this, &m_key); + if (action != ACTION_RESULT_DONE) { + m_pending_action = action; + } +} + +void +SimpleCont::cache_ua_tunnel() +{ + int length; + + length = 0; + m_cache_read_vc->get_data(CACHE_DATA_SIZE, &length); + + m_ua_write_buf = new_empty_MIOBuffer(buffer_size_idx); + m_ua_reader = m_ua_write_buf->alloc_reader(); + + SET_HANDLER(&SimpleCont::cache_ua_tunnel_event); + + Debug("simple_http", "cache-ua tunnel %d", m_ua_reader->read_avail()); + + m_cache_read_vio = m_cache_read_vc->do_io_read(this, length, m_ua_write_buf); + m_ua_write_vio = m_ua_vc->do_io_write(this, length, m_ua_reader); +} + +void +SimpleCont::dns_lookup() +{ + URL url; + Action *action; + + url = m_ua_req.url_get(); + m_os_name = url.host_get(); + m_os_port = url.port_get(); + + SET_HANDLER(&SimpleCont::dns_event); + + action = hostDBProcessor.getbyname_re(this, (char *) m_os_name, 0, m_os_port); + if (action != ACTION_RESULT_DONE) { + m_pending_action = action; + } +} + +void +SimpleCont::os_connect(unsigned int addr) +{ + Action *action; + + SET_HANDLER(&SimpleCont::os_connect_event); + + action = netProcessor.connect_re(this, addr, m_os_port); + if (action != ACTION_RESULT_DONE) { + m_pending_action = action; + } +} + +void +SimpleCont::os_write_req() +{ + HTTPHdr req; + URL url; + IOBufferReader *reader; + IOBufferBlock *blk; + int bufindex; + int tmp, dumpoffset; + int done; + + req.create(); + req.copy(m_ua_req); + + url = req.url_get(); + url.scheme_set(NULL); + url.host_set(NULL); + + m_os_write_buf = new_empty_MIOBuffer(buffer_size_idx); + reader = m_os_write_buf->alloc_reader(); + + dumpoffset = 0; + do { + blk = m_os_write_buf->get_current_block(); + if (!blk) { + m_os_write_buf->add_block(); + } + blk = m_os_write_buf->get_current_block(); + + bufindex = 0; + tmp = dumpoffset; + + done = req.print(blk->end(), blk->write_avail(), &bufindex, &tmp); + + dumpoffset += bufindex; + m_os_write_buf->fill(bufindex); + } while (!done); + + req.destroy(); + + SET_HANDLER(&SimpleCont::os_write_event); + + m_os_write_vio = m_os_vc->do_io_write(this, reader->read_avail(), reader); +} + +void +SimpleCont::os_read_resp() +{ + http_parser_init(&m_parser); + + m_os_read_buf = new_MIOBuffer(buffer_size_idx); + m_os_reader = m_os_read_buf->alloc_reader(); + + SET_HANDLER(&SimpleCont::os_read_resp_event); + + m_os_read_vio = m_os_vc->do_io_read(this, INT64_MAX, m_os_read_buf); +} + +void +SimpleCont::parse_os_resp(int eof) +{ + const char *start, *p; + const char *end; + int avail; + int err; + + for (;;) { + avail = m_os_reader->block_read_avail(); + if (!avail) { + if (eof) { + destroy(); + } + return; + } + p = start = m_os_reader->start(); + end = start + avail; + + err = m_os_resp.parse_resp(&m_parser, &p, end, eof); + + m_os_reader->consume(p - start); + + if (err == PARSE_DONE) { + if (is_debug_tag_set("simple_http")) { + m_os_resp.print(NULL, 0, NULL, NULL); + } + m_os_read_vio->nbytes = m_os_read_vio->ndone; + ua_write_resp(); + return; + } + + if (err == PARSE_ERROR) { + destroy(); + return; + } + } + + + m_os_read_vio->reenable(); +} + +void +SimpleCont::ua_write_resp() +{ + IOBufferBlock *blk; + int bufindex; + int tmp, dumpoffset; + int done; + + m_ua_write_buf = new_empty_MIOBuffer(buffer_size_idx); + m_ua_reader = m_ua_write_buf->alloc_reader(); + + dumpoffset = 0; + do { + blk = m_ua_write_buf->get_current_block(); + if (!blk) { + m_ua_write_buf->add_block(); + } + blk = m_ua_write_buf->get_current_block(); + + bufindex = 0; + tmp = dumpoffset; + + done = m_os_resp.print(blk->end(), blk->write_avail(), &bufindex, &tmp); + + dumpoffset += bufindex; + m_ua_write_buf->fill(bufindex); + } while (!done); + + m_ua_write_buf->write(m_os_reader); + m_ua_resp_size = m_ua_reader->read_avail(); + + cache_write(); +} + +void +SimpleCont::cache_write() +{ + Action *action; + MIMEField field; + int i, count; + + field = m_os_resp.field_retrieve(MIME_FIELD_CACHE_CONTROL); + count = field.values_count(); + for (i = 0; i < count; i++) { + if (field.value_get(i) == HTTP_VALUE_NO_CACHE) { + os_ua_tunnel(); + return; + } + } + + SET_HANDLER(&SimpleCont::cache_write_event); + + action = cacheProcessor.open_write(this, 32 * 1024, &m_key, CACHE_FRAG_TYPE_HTTP); + if (action != ACTION_RESULT_DONE) { + m_pending_action = action; + } +} + +void +SimpleCont::os_ua_tunnel() +{ + SET_HANDLER(&SimpleCont::os_ua_tunnel_event); + + m_os_read_vio = m_os_vc->do_io_read(this, INT64_MAX, m_ua_write_buf); + if (m_cache_write_vc) { + m_cache_write_vio = m_cache_write_vc->do_io_write(this, INT64_MAX, m_ua_reader->clone()); + } + m_ua_write_vio = m_ua_vc->do_io_write(this, INT64_MAX, m_ua_reader); +} + +void +SimpleCont::ua_close() +{ + m_ua_vc->do_io_close(); + m_ua_vc = NULL; + m_ua_write_vio = NULL; + + if (!m_ua_vc && !m_cache_write_vc) { + destroy(); + } +} + +void +SimpleCont::cache_close() +{ + m_cache_write_vc->do_io_close(); + m_cache_write_vc = NULL; + m_cache_write_vio = NULL; + + if (!m_ua_vc && !m_cache_write_vc) { + destroy(); + } +} + +void +SimpleCont::cache_abort() +{ + m_cache_write_vc->do_io_close(1); + m_cache_write_vc = NULL; + m_cache_write_vio = NULL; + + if (!m_ua_vc && !m_cache_write_vc) { + destroy(); + } +} + +int +SimpleCont::ua_read_req_event(int event, void *edata) +{ + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + HISTORY_MARK(); + Debug("simple_http", "read event %d", event); + parse_ua_req((event == VC_EVENT_EOS) || (event == VC_EVENT_READ_COMPLETE)); + break; + case VC_EVENT_ERROR: + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::cache_read_event(int event, void *edata) +{ + switch (event) { + case CACHE_EVENT_OPEN_READ: + HISTORY_MARK(); + m_pending_action = NULL; + Debug("simple_http", "cache read success"); + m_cache_read_vc = (VConnection *) edata; + cache_ua_tunnel(); + break; + case CACHE_EVENT_OPEN_READ_FAILED: + HISTORY_MARK(); + m_pending_action = NULL; + Debug("simple_http", "cache read failure"); + dns_lookup(); + break; + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::cache_ua_tunnel_event(int event, void *edata) +{ + switch (event) { + case VC_EVENT_READ_READY: + HISTORY_MARK(); + Debug("simple_http", "cache read ready"); + m_ua_write_vio->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + Debug("simple_http", "cache read complete"); + m_ua_resp_size += m_cache_read_vio->ndone; + m_cache_read_vc->do_io_close(); + m_cache_read_vc = NULL; + m_cache_read_vio = NULL; + + m_ua_write_vio->nbytes = m_ua_resp_size; + + if (m_ua_write_vio->ndone == m_ua_write_vio->nbytes) { + HISTORY_MARK(); + Debug("simple_http", "ua write complete"); + ua_close(); + } else { + HISTORY_MARK(); + m_ua_write_vio->reenable(); + } + break; + case VC_EVENT_WRITE_READY: + HISTORY_MARK(); + Debug("simple_http", "ua write ready"); + if (m_cache_read_vc) { + m_cache_read_vio->reenable(); + } + break; + case VC_EVENT_WRITE_COMPLETE: + HISTORY_MARK(); + Debug("simple_http", "ua write complete"); + ua_close(); + break; + case VC_EVENT_ERROR: + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::dns_event(int event, void *edata) +{ + switch (event) { + case EVENT_HOST_DB_LOOKUP: + m_pending_action = NULL; + if (edata) { + HostDBInfo *r = (HostDBInfo *) edata; + HostDBInfo *rr = NULL; + + Debug("simple_http", "dns lookup success"); + + if (r->round_robin) { + Debug("simple_http", "dns round robin"); + rr = r->rr()->select_best(0); + } else { + rr = r; + } + + if (rr) { + HISTORY_MARK(); + os_connect(rr->ip()); + } else { + HISTORY_MARK(); + Debug("simple_http", "dns error"); + destroy(); + } + } else { + HISTORY_MARK(); + Debug("simple_http", "dns lookup failure"); + destroy(); + } + break; + case EVENT_HOST_DB_IP_REMOVED: + m_pending_action = NULL; + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::os_connect_event(int event, void *edata) +{ + switch (event) { + case NET_EVENT_OPEN: + HISTORY_MARK(); + m_pending_action = NULL; + Debug("simple_http", "os connect success"); + m_os_vc = (NetVConnection *) edata; + os_write_req(); + break; + case NET_EVENT_OPEN_FAILED: + HISTORY_MARK(); + m_pending_action = NULL; + Debug("simple_http", "os connect failure"); + destroy(); + break; + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::os_write_event(int event, void *edata) +{ + switch (event) { + case VC_EVENT_WRITE_READY: + HISTORY_MARK(); + Debug("simple_http", "os write ready"); + m_os_write_vio->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + HISTORY_MARK(); + Debug("simple_http", "os write complete"); + os_read_resp(); + break; + case VC_EVENT_ERROR: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::os_read_resp_event(int event, void *edata) +{ + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + HISTORY_MARK(); + Debug("simple_http", "read event %d", event); + parse_os_resp((event == VC_EVENT_EOS) || (event == VC_EVENT_READ_COMPLETE)); + break; + case VC_EVENT_ERROR: + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::cache_write_event(int event, void *edata) +{ + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + HISTORY_MARK(); + Debug("simple_http", "cache write success"); + m_cache_write_vc = (VConnection *) edata; + os_ua_tunnel(); + break; + case CACHE_EVENT_OPEN_WRITE_FAILED: + HISTORY_MARK(); + Debug("simple_http", "cache write failure"); + os_ua_tunnel(); + break; + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + +int +SimpleCont::os_ua_tunnel_event(int event, void *edata) +{ + switch (event) { + case VC_EVENT_READ_READY: + HISTORY_MARK(); + Debug("simple_http", "os read ready"); + m_ua_write_vio->reenable(); + if (m_cache_write_vio) { + m_cache_write_vio->reenable(); + } + break; + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + HISTORY_MARK(); + Debug("simple_http", "os read complete"); + m_ua_resp_size += m_os_read_vio->ndone; + m_os_vc->do_io_close(); + m_os_vc = NULL; + m_os_read_vio = NULL; + + if (m_cache_write_vio) { + m_cache_write_vio->nbytes = m_ua_resp_size; + if (m_cache_write_vio->ndone == m_cache_write_vio->nbytes) { + Debug("simple_http", "cache write complete"); + cache_close(); + } else { + m_cache_write_vio->reenable(); + } + } + + m_ua_write_vio->nbytes = m_ua_resp_size; + if (m_ua_write_vio->ndone == m_ua_write_vio->nbytes) { + Debug("simple_http", "ua write complete"); + ua_close(); + } else { + m_ua_write_vio->reenable(); + } + break; + case VC_EVENT_WRITE_READY: + if ((VIO *) edata == m_ua_write_vio) { + HISTORY_MARK(); + Debug("simple_http", "ua write ready"); + } else if ((VIO *) edata == m_cache_write_vio) { + HISTORY_MARK(); + Debug("simple_http", "cache write ready"); + } + + if (m_os_vc) { + m_os_read_vio->reenable(); + } + break; + case VC_EVENT_WRITE_COMPLETE: + if ((VIO *) edata == m_ua_write_vio) { + HISTORY_MARK(); + Debug("simple_http", "ua write complete"); + ua_close(); + } else if ((VIO *) edata == m_cache_write_vio) { + HISTORY_MARK(); + Debug("simple_http", "cache write complete"); + cache_close(); + } + break; + case VC_EVENT_ERROR: + if ((VIO *) edata == m_cache_write_vio) { + HISTORY_MARK(); + Debug("simple_http", "cache error"); + cache_abort(); + break; + } + default: + HISTORY_MARK(); + Debug("simple_http", "unexpected event %d", event); + destroy(); + break; + } + return 0; +} + + +void +run_SimpleHttp() +{ + if (is_action_tag_set("simple_http")) { + + RecReadConfigInteger(port, "proxy.config.simple.http.port"); + RecReadConfigInteger(buffer_size, "proxy.config.simple.http.buffer_size"); + buffer_size_idx = buffer_size_to_index(buffer_size); + + Note("simple http running on port %d", port); + netProcessor.main_accept(NEW(new AcceptCont()), NO_FD, port); + } + + return; +} + +#else + +void +run_SimpleHttp() +{ + if (is_action_tag_set("simple_http")) { + Error("simple http not implemented for new headers"); + } + return; +} + +#endif diff --git a/proxy/Socks.h b/proxy/Socks.h new file mode 100644 index 00000000..cf9f6821 --- /dev/null +++ b/proxy/Socks.h @@ -0,0 +1,197 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#ifndef _SOCKS_H_ +#define _SOCKS_H_ + +#include "ParentSelection.h" +#include "IOBuffer.h" +#include "Action.h" +#include "Event.h" +#include "IPRange.h" + +#define SOCKS_DEFAULT_VERSION 0 //defined the configuration variable +#define SOCKS4_VERSION 4 +#define SOCKS5_VERSION 5 +#define SOCKS_CONNECT 1 +#define SOCKS4_REQ_LEN 9 +#define SOCKS4_REP_LEN 8 +#define SOCKS5_REP_LEN 262 //maximum possible +#define SOCKS4_REQ_GRANTED 90 +#define SOCKS4_CONN_FAILED 91 +#define SOCKS5_REQ_GRANTED 0 +#define SOCKS5_CONN_FAILED 1 + +enum +{ + //types of events for Socks auth handlers + SOCKS_AUTH_OPEN, + SOCKS_AUTH_WRITE_COMPLETE, + SOCKS_AUTH_READ_COMPLETE, + SOCKS_AUTH_FILL_WRITE_BUF +}; + +enum +{ + //For these two, we need to pick two values which are not used for any of the + //"commands" (eg: CONNECT, BIND) in SOCKS protocols. + NORMAL_SOCKS = 0, + NO_SOCKS = 48 +}; + +enum +{ + SOCKS_ATYPE_NONE = 0, + SOCKS_ATYPE_IPV4 = 1, + SOCKS_ATYPE_FQHN = 3, + SOCKS_ATYPE_IPV6 = 4 +}; + +struct socks_conf_struct +{ + int socks_needed; + int server_connect_timeout; + int socks_timeout; + unsigned char default_version; + IPRange ip_range; + char *user_name_n_passwd; + int user_name_n_passwd_len; + + int per_server_connection_attempts; + int connection_attempts; + + //the following ports are used by SocksProxy + int accept_enabled; + int accept_port; + unsigned short http_port; + + socks_conf_struct():user_name_n_passwd(NULL), user_name_n_passwd_len(0) + { +}} + ; + +extern struct socks_conf_struct *g_socks_conf_stuff; + +void start_SocksProxy(int port); + +int loadSocksAuthInfo(int fd, socks_conf_struct * socks_stuff); + +// umm.. the following typedef should take _its own_ type as one of the args +// not possible with C +// Right now just use a generic fn ptr and hide casting in an inline fn. +typedef int (*SocksAuthHandler) (int event, unsigned char *buf, void (**h_ptr) (void)); + +inline int +invokeSocksAuthHandler(SocksAuthHandler & h, int arg1, unsigned char *arg2) +{ + return (h) (arg1, arg2, (void (**)(void)) (&h)); +} + +void loadSocksConfiguration(socks_conf_struct * socks_conf_stuff); +int socks5BasicAuthHandler(int event, unsigned char *p, void (**)(void)); +int socks5PasswdAuthHandler(int event, unsigned char *p, void (**)(void)); +int socks5ServerAuthHandler(int event, unsigned char *p, void (**)(void)); + + +struct SocksAddrType +{ + unsigned char type; + union + { + //mostly it is ipv4. in other cases we will xalloc(). + unsigned char ipv4[4]; + unsigned char *buf; + } addr; + + void reset() + { + if (type != SOCKS_ATYPE_IPV4 && addr.buf) { + xfree(addr.buf); + } + addr.buf = 0; + type = SOCKS_ATYPE_NONE; + } + + SocksAddrType() +: type(SOCKS_ATYPE_NONE) { + addr.buf = 0; + }; + ~SocksAddrType() { + reset(); + } +}; + +class UnixNetVConnection; +typedef UnixNetVConnection SocksNetVC; + +struct SocksEntry:public Continuation +{ //enum { SOCKS_INIT=0, SOCKS_SEND, SOCKS_RECV }; + + MIOBuffer *buf; + IOBufferReader *reader; + + SocksNetVC *netVConnection; + + //VIO * read_vio; + + unsigned int ip; // ip address in the original request + int port; // port number in the original request + + unsigned int server_ip; + int server_port; + int nattempts; + + Action action_; + //int state; + int lerrno; + Event *timeout; + unsigned char version; + + bool write_done; + + SocksAuthHandler auth_handler; + unsigned char socks_cmd; + + //socks server selection: + ParentConfigParams *server_params; + HttpRequestData req_data; //We dont use any http specific fields. + ParentResult server_result; + + int startEvent(int event, void *data); + int mainEvent(int event, void *data); + void findServer(); + void init(ProxyMutex * m, SocksNetVC * netvc, unsigned char socks_support, unsigned char ver); + void free(); + + SocksEntry():Continuation(NULL), netVConnection(0), lerrno(0), timeout(0), auth_handler(NULL) + { +}} + ; + +typedef int (SocksEntry::*SocksEntryHandler) (int, void *); + +extern ClassAllocator socksAllocator; + + +#endif //_SOCKS_H_ diff --git a/proxy/SocksProxy.cc b/proxy/SocksProxy.cc new file mode 100644 index 00000000..a7cb9ca4 --- /dev/null +++ b/proxy/SocksProxy.cc @@ -0,0 +1,574 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + This implements SOCKS server. We intecept the http traffic and send it + through HTTP. Others are tunneled through directly to the socks server. + + +*/ +#include "libts.h" +#include "StatSystem.h" +#include "P_Net.h" +#include "I_OneWayTunnel.h" +#include "HttpAccept.h" + +enum +{ + socksproxy_http_connections_stat, + socksproxy_tunneled_connections_stat, + + socksproxy_stat_count +}; +static RecRawStatBlock *socksproxy_stat_block; + +#define SOCKSPROXY_INC_STAT(x) \ + RecIncrRawStat(socksproxy_stat_block, mutex->thread_holding, x) + +struct SocksProxy: public Continuation +{ + typedef int (SocksProxy::*EventHandler) (int event, void *data); + + enum + { SOCKS_INIT = 1, SOCKS_ACCEPT, AUTH_DONE, SERVER_TUNNEL, + HTTP_REQ, RESP_TO_CLIENT, ALL_DONE, SOCKS_ERROR + }; + + SocksProxy() + : Continuation(), + clientVC(0), clientVIO(0), buf(0), timeout(0), + auth_handler(0), version(0), state(SOCKS_INIT), recursion(0), pending_action(NULL) + { + } + ~SocksProxy() + { + } + + + //int startEvent(int event, void * data); + int mainEvent(int event, void *data); + int setupHttpRequest(unsigned char *p); + //int setupServerTunnel(unsigned char * p); + + int sendResp(bool granted); + + void init(NetVConnection * netVC); + void free(); + +private: + + NetVConnection * clientVC; + VIO *clientVIO; + + MIOBuffer *buf; + IOBufferReader *reader; + Event *timeout; + + SocksAuthHandler auth_handler; + + unsigned char version; + + int state; + int recursion; + Action *pending_action; +}; + +ClassAllocator socksProxyAllocator("socksProxyAllocator"); + +void +SocksProxy::init(NetVConnection * netVC) +{ + mutex = new_ProxyMutex(); + buf = new_MIOBuffer(); + reader = buf->alloc_reader(); + + MUTEX_LOCK(lock, mutex, this_ethread()); + + SET_HANDLER((EventHandler) & SocksProxy::mainEvent); + + mainEvent(NET_EVENT_ACCEPT, netVC); +} + +void +SocksProxy::free() +{ + if (buf) + free_MIOBuffer(buf); + + mutex = NULL; + + socksProxyAllocator.free(this); +} + +int +SocksProxy::mainEvent(int event, void *data) +{ + int ret = EVENT_DONE; + unsigned char *p; + + VIO *vio; + int64_t n_read_avail; + //int n_consume; + + recursion++; + + switch (event) { + + case NET_EVENT_ACCEPT: + state = SOCKS_ACCEPT; + Debug("SocksProxy", "Proxy got accept event\n"); + + clientVC = (NetVConnection *) data; + clientVC->socks_addr.reset(); + //Fall through: + case VC_EVENT_WRITE_COMPLETE: + + switch (state) { + case HTTP_REQ:{ + //This is a WRITE_COMPLETE. vio->nbytes == vio->ndone is true + + SOCKSPROXY_INC_STAT(socksproxy_http_connections_stat); + Debug("SocksProxy", "Handing over the HTTP request\n"); + + HttpAccept http_accept(clientVC->attributes); + http_accept.mainEvent(NET_EVENT_ACCEPT, clientVC); + state = ALL_DONE; + break; + } + + case RESP_TO_CLIENT: + state = SOCKS_ERROR; + break; + + default: + buf->reset(); + timeout = this_ethread() + ->schedule_in(this, HRTIME_SECONDS(netProcessor.socks_conf_stuff->socks_timeout)); + clientVC->do_io_read(this, INT64_MAX, buf); + } + + break; + + case VC_EVENT_WRITE_READY: + Debug("SocksProxy", "Received unexpected write_ready\n"); + break; + + case VC_EVENT_READ_COMPLETE: + Debug("SocksProxy", "Oops! We should never get Read_Complete.\n"); + // FALLTHROUGH + case VC_EVENT_READ_READY:{ + unsigned char *port_ptr = 0; + + ret = EVENT_CONT; + vio = (VIO *) data; + + n_read_avail = reader->block_read_avail(); + ink_assert(n_read_avail == reader->read_avail()); + p = (unsigned char *) reader->start(); + + if (n_read_avail >= 2) { + + Debug(state == SOCKS_ACCEPT ? "SocksProxy" : "", "Accepted connection from a version %d client\n", (int) p[0]); + + //Most of the time request is just a single packet + switch (p[0]) { + + case SOCKS4_VERSION: + ink_assert(state == SOCKS_ACCEPT); + + if (n_read_avail > 8) { + //read the user name + int i = 8; + while (p[i] != 0 && n_read_avail > i) + i++; + + if (p[i] == 0) { + port_ptr = &p[2]; + clientVC->socks_addr.type = SOCKS_ATYPE_IPV4; + reader->consume(i + 1); + //n_consume = i+1; + ret = EVENT_DONE; + } + } + break; + + case SOCKS5_VERSION: + + if (state == SOCKS_ACCEPT) { + if (n_read_avail >= 2 + p[1]) { + auth_handler = &socks5ServerAuthHandler; + ret = EVENT_DONE; + } + } else { + ink_assert(state == AUTH_DONE); + + if (n_read_avail >= 5) { + int req_len; + + switch (p[3]) { + case SOCKS_ATYPE_IPV4: + req_len = 10; + break; + case SOCKS_ATYPE_FQHN: + req_len = 7 + p[4]; + break; + case SOCKS_ATYPE_IPV6: + req_len = 22; + break; + default: + req_len = INT_MAX; + Debug("SocksProxy", "Illegal address type(%d)\n", (int) p[3]); + } + + if (n_read_avail >= req_len) { + port_ptr = &p[req_len - 2]; + clientVC->socks_addr.type = p[3]; + auth_handler = NULL; + reader->consume(req_len); + ret = EVENT_DONE; + } + } + } + break; + + default: + Warning("Wrong version for Socks: %d\n", p[0]); + state = SOCKS_ERROR; + } + } + + if (ret == EVENT_DONE) { + timeout->cancel(this); + timeout = 0; + + if (auth_handler) { + + /* disable further reads */ + vio->nbytes = vio->ndone; + + //There is some auth stuff left. + if (invokeSocksAuthHandler(auth_handler, SOCKS_AUTH_READ_COMPLETE, p) >= 0) { + buf->reset(); + p = (unsigned char *) buf->start(); + + int n_bytes = invokeSocksAuthHandler(auth_handler, + SOCKS_AUTH_FILL_WRITE_BUF, p); + ink_assert(n_bytes > 0); + + buf->fill(n_bytes); + + clientVC->do_io_write(this, n_bytes, reader, 0); + + state = AUTH_DONE; + } else { + Debug("SocksProxy", "Auth_handler returned error\n"); + state = SOCKS_ERROR; + } + + } else { + int port = port_ptr[0] * 256 + port_ptr[1]; + version = p[0]; + + if (port == netProcessor.socks_conf_stuff->http_port && p[1] == SOCKS_CONNECT) { + + /* disable further reads */ + vio->nbytes = vio->ndone; + + ret = setupHttpRequest(p); + sendResp(true); + state = HTTP_REQ; + + } else { + SOCKSPROXY_INC_STAT(socksproxy_tunneled_connections_stat); + Debug("SocksProxy", "Tunnelling the connection for port %d", port); + + if (clientVC->socks_addr.type != SOCKS_ATYPE_IPV4) { + //We dont support other kinds of addresses for tunnelling + //if this is a hostname we could do host look up here + mainEvent(NET_EVENT_OPEN_FAILED, NULL); + break; + } + + uint32_t ip; + memcpy(&ip, &p[4], 4); + + state = SERVER_TUNNEL; + clientVIO = vio; // used in the tunnel + + //tunnel the connection. + + NetVCOptions vc_options; + vc_options.socks_support = p[1]; + vc_options.socks_version = version; + + Action *action = netProcessor.connect_re(this, ip, port, &vc_options); + if (action != ACTION_RESULT_DONE) { + ink_assert(pending_action == NULL); + pending_action = action; + } + } + } + } //if (ret == EVENT_DONE) + + break; + } + + case NET_EVENT_OPEN:{ + pending_action = NULL; + ink_assert(state == SERVER_TUNNEL); + Debug("SocksProxy", "open to Socks server succeeded\n"); + + NetVConnection *serverVC; + serverVC = (NetVConnection *) data; + + OneWayTunnel *c_to_s = OneWayTunnel::OneWayTunnel_alloc(); + OneWayTunnel *s_to_c = OneWayTunnel::OneWayTunnel_alloc(); + + c_to_s->init(clientVC, serverVC, NULL, clientVIO, reader); + s_to_c->init(serverVC, clientVC, /*aCont = */ NULL, 0 /*best guess */ , + c_to_s->mutex); + + OneWayTunnel::SetupTwoWayTunnel(c_to_s, s_to_c); + + buf = 0; // do not free buf. Tunnel will do that. + state = ALL_DONE; + break; + } + + case NET_EVENT_OPEN_FAILED: + pending_action = NULL; + sendResp(false); + state = RESP_TO_CLIENT; + Debug("SocksProxy", "open to Socks server failed\n"); + break; + + case EVENT_INTERVAL: + timeout = 0; + Debug("SocksProxy", "SocksProxy timeout, state = %d\n", state); + state = SOCKS_ERROR; + break; + + case VC_EVENT_ERROR: + case VC_EVENT_INACTIVITY_TIMEOUT: + case VC_EVENT_ACTIVE_TIMEOUT: + case VC_EVENT_EOS: + Debug("SocksProxy", "VC_EVENT (state: %d error: %s)\n", state, get_vc_event_name(event)); + state = SOCKS_ERROR; + break; + + default: + ink_assert(!"bad case value\n"); + state = SOCKS_ERROR; + } + + if (state == SOCKS_ERROR) { + if (pending_action) + pending_action->cancel(); + + if (timeout) + timeout->cancel(this); + + if (clientVC) { + Debug("SocksProxy", "Closing clientVC on error\n"); + clientVC->do_io_close(); + clientVC = NULL; + } + + state = ALL_DONE; + } + + recursion--; + + if (state == ALL_DONE && recursion == 0) { + free(); + } + + return ret; +} + +int +SocksProxy::sendResp(bool granted) +{ + int n_bytes; + + // In SOCKS 4, IP addr and Dest Port fields are ignored. + // In SOCKS 5, IP addr and Dest Port are the ones we use to connect to the + // real host. In our case, it does not make sense, since we may not + // connect at all. Set these feilds to zeros. Any socks client which uses + // these breaks caching. + + + buf->reset(); + unsigned char *p = (unsigned char *) buf->start(); + + if (version == SOCKS4_VERSION) { + p[0] = 0; + p[1] = (granted) ? SOCKS4_REQ_GRANTED : SOCKS4_CONN_FAILED; + n_bytes = 8; + } else { + p[0] = SOCKS5_VERSION; + p[1] = (granted) ? SOCKS5_REQ_GRANTED : SOCKS5_CONN_FAILED; + p[2] = 0; + p[3] = SOCKS_ATYPE_IPV4; + p[4] = p[5] = p[6] = p[7] = p[8] = p[9] = 0; + n_bytes = 10; + } + + buf->fill(n_bytes); + clientVC->do_io_write(this, n_bytes, reader, 0); + + return n_bytes; +} + + +int +SocksProxy::setupHttpRequest(unsigned char *p) +{ + int ret = EVENT_DONE; + + SocksAddrType *a = &clientVC->socks_addr; + + //read the ip addr buf + //In both SOCKS4 and SOCKS5 addr starts after 4 octets + switch (a->type) { + + case SOCKS_ATYPE_IPV4: + a->addr.ipv4[0] = p[4]; + a->addr.ipv4[1] = p[5]; + a->addr.ipv4[2] = p[6]; + a->addr.ipv4[3] = p[7]; + break; + + case SOCKS_ATYPE_FQHN: + //This is stored as a zero terminicated string + a->addr.buf = (unsigned char *) xmalloc(p[4] + 1); + memcpy(a->addr.buf, &p[5], p[4]); + a->addr.buf[p[4]] = 0; + break; + case SOCKS_ATYPE_IPV6: + //a->addr.buf = (unsigned char *) xmalloc(16); + //memcpy(a->addr.buf, &p[4], 16); + //dont think we will use "proper" IPv6 addr anytime soon. + //just use the last 4 octets as IPv4 addr: + a->type = SOCKS_ATYPE_IPV4; + a->addr.ipv4[0] = p[16]; + a->addr.ipv4[0] = p[17]; + a->addr.ipv4[0] = p[18]; + a->addr.ipv4[0] = p[19]; + + break; + default: + ink_assert(!"bad case value"); + } + + return ret; +} + + + + +static void +new_SocksProxy(NetVConnection * netVC) +{ + SocksProxy *proxy = socksProxyAllocator.alloc(); + proxy->init(netVC); +} + +struct SocksAccepter: public Continuation +{ + + typedef int (SocksAccepter::*SocksAccepterHandler) (int, void *); + + int mainEvent(int event, NetVConnection * netVC) + { + + ink_assert(event == NET_EVENT_ACCEPT); + //Debug("Socks", "Accepter got ACCEPT event\n"); + + new_SocksProxy(netVC); + + return EVENT_CONT; + } + + //There is no state used we dont need a mutex + SocksAccepter():Continuation(NULL) + { + SET_HANDLER((SocksAccepterHandler) & SocksAccepter::mainEvent); + } +}; + +void +start_SocksProxy(int port) +{ + Debug("SocksProxy", "Accepting SocksProxy connections on port %d\n", port); + NetProcessor::AcceptOptions opt; + opt.port = port; + netProcessor.main_accept(NEW(new SocksAccepter), NO_FD, 0, 0, false, false, opt); + + socksproxy_stat_block = RecAllocateRawStatBlock(socksproxy_stat_count); + + if (socksproxy_stat_block) { + RecRegisterRawStat(socksproxy_stat_block, RECT_PROCESS, + "proxy.process.socks.proxy.http_connections", + RECD_INT, RECP_NULL, socksproxy_http_connections_stat, RecRawStatSyncCount); + + RecRegisterRawStat(socksproxy_stat_block, RECT_PROCESS, + "proxy.process.socks.proxy.tunneled_connections", + RECD_INT, RECP_NULL, socksproxy_tunneled_connections_stat, RecRawStatSyncCount); + } +} + +int +socks5ServerAuthHandler(int event, unsigned char *p, void (**h_ptr) (void)) +{ + + int ret = 0; + //bool no_auth_needed=true; + + switch (event) { + + case SOCKS_AUTH_READ_COMPLETE: + + ink_assert(p[0] == SOCKS5_VERSION); + Debug("SocksProxy", "Socks read initial auth info\n"); + //do nothing + break; + + case SOCKS_AUTH_FILL_WRITE_BUF: + Debug("SocksProxy", "No authentication is required\n"); + p[0] = SOCKS5_VERSION; + p[1] = 0; //no authentication necessary + ret = 2; + // FALLTHROUGH + case SOCKS_AUTH_WRITE_COMPLETE: + //nothing to do + *h_ptr = NULL; + break; + + default: + ink_assert(!"bad case value"); + ret = -1; + } + + return ret; +} diff --git a/proxy/StatPages.cc b/proxy/StatPages.cc new file mode 100644 index 00000000..5dfe8b2e --- /dev/null +++ b/proxy/StatPages.cc @@ -0,0 +1,273 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + StatPages.cc + + + ****************************************************************************/ + +#include "ink_config.h" +#include "ProxyConfig.h" +#include "StatPages.h" +#include "HdrUtils.h" +#include "MatcherUtils.h" + +#define MAX_STAT_PAGES 32 + + +// Globals +StatPagesManager statPagesManager; + +static struct +{ + char *module; + StatPagesFunc func; +} stat_pages[MAX_STAT_PAGES]; + +static volatile int n_stat_pages = 0; + +void +StatPagesManager::init() +{ + REC_EstablishStaticConfigInt32(m_enabled, "proxy.config.http_ui_enabled"); +} + +void +StatPagesManager::register_http(const char *module, StatPagesFunc func) +{ + ink_release_assert(n_stat_pages < MAX_STAT_PAGES); + + stat_pages[n_stat_pages].module = (char *) xmalloc(strlen(module) + 3); + snprintf(stat_pages[n_stat_pages].module, strlen(module) + 3, "{%s}", module); + stat_pages[n_stat_pages++].func = func; +} + +Action * +StatPagesManager::handle_http(Continuation * cont, HTTPHdr * header, int client_ip) +{ + NOWARN_UNUSED(client_ip); + URL *url = header->url_get(); + + if (((m_enabled == 1 || m_enabled == 3) && is_cache_inspector_page(url)) || + ((m_enabled == 2 || m_enabled == 3) && is_stat_page(url) && !is_cache_inspector_page(url))) { + int host_len; + char host[1024]; + const char *h; + int i; + + h = url->host_get(&host_len); + ink_strncpy(host, h, host_len >= 1023 ? 1024 : host_len + 1); + host_len = unescapifyStr(host); + + for (i = 0; i < n_stat_pages; i++) { + if (ptr_len_cmp(host, host_len, stat_pages[i].module) == 0) { + return stat_pages[i].func(cont, header); + } + } + } + + cont->handleEvent(STAT_PAGE_FAILURE, 0); + return ACTION_RESULT_DONE; +} + +bool StatPagesManager::is_stat_page(URL * url) +{ + int length; + const char *h = url->host_get(&length); + char host[1024]; + + if (h == NULL || length < 2) + return false; + + ink_strncpy(host, h, length >= 1023 ? 1024 : length + 1); + length = unescapifyStr(host); + + if ((host[0] == '{') && (host[length - 1] == '}')) + return true; + + return false; +} + +bool StatPagesManager::is_cache_inspector_page(URL * url) +{ + int length; + const char *h = url->host_get(&length); + char host[1024]; + + if (h == NULL || length < 2) + return false; + + ink_strncpy(host, h, length >= 1023 ? 1024 : length + 1); + host[length] = '\0'; + length = unescapifyStr(host); + + if (strncmp(host, "{cache}", length) == 0) + return true; + else + return false; + +} + +void +BaseStatPagesHandler::resp_clear() +{ + if (response) { + xfree(response); + } + + response = NULL; + response_size = 0; + response_length = 0; +} + +void +BaseStatPagesHandler::resp_add(const char *fmt, ...) +{ + va_list args; + char buf[16384]; + int length; + int size; + + va_start(args, fmt); + length = vsnprintf(buf, 16384, fmt, args); + va_end(args); + + size = response_size; + if (size == 0) { + size = 1024; + } + while ((response_length + length + 1) > size) { + size *= 2; + } + + if (size != response_size) { + if (!response) { + response = (char *) xmalloc(size); + } else { + response = (char *) xrealloc(response, size); + } + response_size = size; + } + + memcpy(&response[response_length], buf, length + 1); + response_length += length; +} + +void +BaseStatPagesHandler::resp_add_sep() +{ + resp_add("
\n"); +} + +void +BaseStatPagesHandler::resp_begin(const char *title) +{ + resp_clear(); + resp_add("\n" + "%s\n" + "\n", title); +} + +void +BaseStatPagesHandler::resp_end() +{ + resp_add("\n" "\n"); +} + +void +BaseStatPagesHandler::resp_begin_numbered() +{ + resp_add("
    \n"); +} + +void +BaseStatPagesHandler::resp_end_numbered() +{ + resp_add("
\n"); +} + +void +BaseStatPagesHandler::resp_begin_unnumbered() +{ + resp_add("
    \n"); +} + +void +BaseStatPagesHandler::resp_end_unnumbered() +{ + resp_add("
\n"); +} + +void +BaseStatPagesHandler::resp_begin_item() +{ + resp_add("
  • \n"); +} + +void +BaseStatPagesHandler::resp_end_item() +{ + resp_add("
  • \n"); +} + +void +BaseStatPagesHandler::resp_begin_table(int border, int columns, int percent) +{ + resp_add("\n", border, columns, percent); +} + +void +BaseStatPagesHandler::resp_end_table() +{ + resp_add("
    \n"); +} + +void +BaseStatPagesHandler::resp_begin_row() +{ + resp_add("\n"); +} + +void +BaseStatPagesHandler::resp_end_row() +{ + resp_add("\n"); +} + +void +BaseStatPagesHandler::resp_begin_column(int percent, const char *align) +{ + if (percent == -1) { + resp_add("\n", align ? "align=" : "", align ? align : ""); + } else { + resp_add("\n", percent, align ? "align=" : "", align ? align : ""); + } +} + +void +BaseStatPagesHandler::resp_end_column() +{ + resp_add("\n"); +} diff --git a/proxy/StatPages.h b/proxy/StatPages.h new file mode 100644 index 00000000..0e2ac0fd --- /dev/null +++ b/proxy/StatPages.h @@ -0,0 +1,137 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + StatPages.h + + + ****************************************************************************/ + +#ifndef _StatPages_h_ +#define _StatPages_h_ +#include "P_EventSystem.h" + +#include "HTTP.h" + +// SPECIAL URLs +// +// +// 1. Access from Browswers +// +// By special URLS: +// +// http://{module}/component/sub-component/request-type?arguments +// +// Note how the hostname is the module to be queried with "{}" surrounding. +// +// Running Example: +// +// http://{http}/groups/dump?comp.compilers +// +// 2. What sort of things should be available? +// +// A. The type of data should default to HTML or match the +// extension type e.g.: +// +// http://{http}/groups/use_graph.gif?august +// +// B. Each protocol/sybsystem should have their own information. +// For example + +#define STAT_PAGE_SUCCESS STAT_PAGES_EVENTS_START+0 +#define STAT_PAGE_FAILURE STAT_PAGES_EVENTS_START+1 + +typedef Action *(*StatPagesFunc) (Continuation * cont, HTTPHdr * header); + +struct StatPageData +{ + char *data; + char *type; + int length; + + StatPageData():data(NULL), type(NULL), length(0) + { + } + StatPageData(char *adata):data(adata), type(NULL) + { + length = strlen(adata); + } + StatPageData(char *adata, int alength):data(adata), type(NULL), length(alength) + { + } +}; + +struct StatPagesManager +{ + void init(); + + inkcoreapi void register_http(const char *hostname, StatPagesFunc func); + + // Private + Action *handle_http(Continuation * cont, HTTPHdr * header, int client_ip); + bool is_stat_page(URL * url); + bool is_cache_inspector_page(URL * url); + int m_enabled; +}; + +inkcoreapi extern StatPagesManager statPagesManager; + +// Stole Pete's code for formatting the page and slapped it here +// for easy reuse +class BaseStatPagesHandler:public Continuation +{ +public: + BaseStatPagesHandler(ProxyMutex * amutex):Continuation(amutex), response(NULL), response_size(0), response_length(0) + { + }; + ~BaseStatPagesHandler() { + resp_clear(); + }; + +protected: + + inkcoreapi void resp_clear(void); + inkcoreapi void resp_add(const char *fmt, ...); + inkcoreapi void resp_add_sep(void); + inkcoreapi void resp_begin(const char *title); + inkcoreapi void resp_end(void); + void resp_begin_numbered(void); + void resp_end_numbered(void); + inkcoreapi void resp_begin_unnumbered(void); + inkcoreapi void resp_end_unnumbered(void); + inkcoreapi void resp_begin_item(void); + void resp_end_item(void); + inkcoreapi void resp_begin_table(int border, int columns, int percent); + inkcoreapi void resp_end_table(); + inkcoreapi void resp_begin_row(); + inkcoreapi void resp_end_row(); + inkcoreapi void resp_begin_column(int percent = -1, const char *align = NULL); + inkcoreapi void resp_end_column(); + + char *response; + int response_size; + int response_length; +}; + +#endif diff --git a/proxy/StatSystem.cc b/proxy/StatSystem.cc new file mode 100644 index 00000000..0cfe9b75 --- /dev/null +++ b/proxy/StatSystem.cc @@ -0,0 +1,835 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + StatSystem.cc -- + Created On : Fri Apr 3 19:41:39 1998 + ****************************************************************************/ +#include "Main.h" +#include "StatSystem.h" +#include "P_EventSystem.h" +#include "Error.h" +#include "ProcessManager.h" +#include "ProxyConfig.h" +#include "StatPages.h" +#include "HTTP.h" +#include "I_Layout.h" + +// defines + +#define SNAP_USAGE_PERIOD HRTIME_SECONDS(2) + + +// variables + +#ifdef DEBUG +ink_mutex http_time_lock; +time_t last_http_local_time; +#endif +ink_stat_lock_t global_http_trans_stat_lock; +ink_unprot_global_stat_t global_http_trans_stats[MAX_HTTP_TRANS_STATS]; +#ifndef USE_LOCKS_FOR_DYN_STATS +inkcoreapi ink_unprot_global_stat_t global_dyn_stats[MAX_DYN_STATS - DYN_STAT_START]; +#else +inkcoreapi ink_prot_global_stat_t global_dyn_stats[MAX_DYN_STATS - DYN_STAT_START]; +#endif + +Ptr rusage_snap_mutex; +struct rusage rusage_snap; +struct rusage rusage_snap_old; +ink_hrtime rusage_snap_time; +ink_hrtime rusage_snap_time_old; +int snap_stats_every = 60; + +ink_hrtime http_handler_times[MAX_HTTP_HANDLER_EVENTS]; +int http_handler_counts[MAX_HTTP_HANDLER_EVENTS]; + + +char snap_filename[PATH_NAME_MAX+1] = DEFAULT_SNAP_FILENAME; + +#define DEFAULT_PERSISTENT + +#ifndef DEFAULT_PERSISTENT +static int persistent_stats[] = { + http_incoming_requests_stat +}; +#else +static int non_persistent_stats[] = { + //////////////////////////// + // Start of Cluster stats + //////////////////////////// + cluster_connections_open_stat, + cluster_connections_openned_stat, + cluster_con_total_time_stat, + cluster_ctrl_msgs_sent_stat, + cluster_slow_ctrl_msgs_sent_stat, + cluster_ctrl_msgs_recvd_stat, + cluster_slow_ctrl_msgs_recvd_stat, + cluster_ctrl_msgs_send_time_stat, + cluster_ctrl_msgs_recv_time_stat, + cluster_read_bytes_stat, + cluster_write_bytes_stat, + cluster_op_delayed_for_lock_stat, + cluster_connections_locked_stat, + cluster_connections_bumped_stat, + cluster_nodes_stat, + cluster_net_backup_stat, + cluster_machines_allocated_stat, + cluster_machines_freed_stat, + cluster_configuration_changes_stat, + cluster_delayed_reads_stat, + cluster_byte_bank_used_stat, + cluster_alloc_data_news_stat, + cluster_write_bb_mallocs_stat, + cluster_partial_reads_stat, + cluster_partial_writes_stat, + cluster_cache_outstanding_stat, + cluster_remote_op_timeouts_stat, + cluster_remote_op_reply_timeouts_stat, + cluster_chan_inuse_stat, + cluster_open_delays_stat, + cluster_open_delay_time_stat, + cluster_cache_callbacks_stat, + cluster_cache_callback_time_stat, + cluster_cache_rmt_callbacks_stat, + cluster_cache_rmt_callback_time_stat, + cluster_cache_lkrmt_callbacks_stat, + cluster_cache_lkrmt_callback_time_stat, + cluster_thread_steal_expires_stat, + cluster_local_connections_closed_stat, + cluster_local_connection_time_stat, + cluster_remote_connections_closed_stat, + cluster_remote_connection_time_stat, + cluster_rdmsg_assemble_time_stat, + cluster_ping_time_stat, + cluster_setdata_no_clustervc_stat, + cluster_setdata_no_tunnel_stat, + cluster_setdata_no_cachevc_stat, + cluster_setdata_no_cluster_stat, + cluster_vc_write_stall_stat, + cluster_no_remote_space_stat, + cluster_level1_bank_stat, + cluster_multilevel_bank_stat, + cluster_vc_cache_insert_lock_misses_stat, + cluster_vc_cache_inserts_stat, + cluster_vc_cache_lookup_lock_misses_stat, + cluster_vc_cache_lookup_hits_stat, + cluster_vc_cache_lookup_misses_stat, + cluster_vc_cache_scans_stat, + cluster_vc_cache_scan_lock_misses_stat, + cluster_vc_cache_purges_stat, + cluster_write_lock_misses_stat, + ///////////////////////////////////// + // Start of Scheduled Update stats + ///////////////////////////////////// + // DNS + //dns_success_time_stat +}; +#endif + +#define _HEADER \ +DynamicStatsString_t DynamicStatsStrings[] = { + +#define _FOOTER }; +#define _D(_x) { _x, #_x }, + +#include "DynamicStats.h" +#undef _HEADER +#undef _FOOTER +#undef _D + + + +// functions + +static int +persistent_stat(int i) +{ +#ifndef DEFAULT_PERSISTENT + for (int j = 0; j < (int) SIZE(persistent_stats); j++) + if (persistent_stats[j] == i) + return 1; + return 0; +#else + for (int j = 0; j < (int) SIZE(non_persistent_stats); j++) + if (non_persistent_stats[j] == i) + return 0; + return 1; +#endif +} + +static int +open_stats_snap() +{ + int fd = socketManager.open(snap_filename, + O_CREAT | O_RDWR | _O_ATTRIB_NORMAL); + if (fd < 0) { + Warning("unable to open %s: %s", snap_filename, strerror(-fd)); + return -1; + } + return fd; +} + +static void +clear_stats() +{ + int i = 0; + + int stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS - 1; + for (i = 0; i < stats_size; i++) { + if (persistent_stat(i + NO_HTTP_TRANS_STATS)) { + global_http_trans_stats[i].sum = 0; + global_http_trans_stats[i].count = 0; + } + } + stats_size = MAX_DYN_STATS - NO_DYN_STATS - 1; + for (i = 0; i < stats_size; i++) { + if (persistent_stat(i + NO_DYN_STATS)) { + global_dyn_stats[i].sum = 0; + global_dyn_stats[i].count = 0; + } + } + + socketManager.unlink(snap_filename); + Debug("stats", "clear_stats: clearing statistics"); +} + +static void +read_stats_snap() +{ + unsigned int version; + unsigned int version_read; + int count; + int fd = -1; + int i = 0; + int stats_size = -1; + + version = STATS_MAJOR_VERSION; + + if ((fd = open_stats_snap()) < 0) + goto Lmissmatch; + + // read and verify snap + if (socketManager.read(fd, (char *) &version_read, sizeof(version_read)) + != sizeof(version_read)) + goto Lmissmatch; + if (version != version_read) + goto Lmissmatch; + stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS + MAX_DYN_STATS - NO_DYN_STATS; + if (socketManager.read(fd, (char *) &count, sizeof(count)) != sizeof(count)) + goto Lmissmatch; + if (count != stats_size) + goto Lmissmatch; + + stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS; + for (i = 0; i < stats_size; i++) { + if (socketManager.read(fd, (char *) &global_http_trans_stats[i].sum, sizeof(global_http_trans_stats[i].sum)) + != sizeof(global_http_trans_stats[i].sum)) + goto Lmissmatch; + if (socketManager.read(fd, (char *) &global_http_trans_stats[i].count, sizeof(global_http_trans_stats[i].count)) + != sizeof(global_http_trans_stats[i].count)) + goto Lmissmatch; + } + stats_size = MAX_DYN_STATS - NO_DYN_STATS; + for (i = 0; i < stats_size; i++) { + if (socketManager.read(fd, (char *) &global_dyn_stats[i].sum, sizeof(global_dyn_stats[i].sum)) + != sizeof(global_dyn_stats[i].sum)) + goto Lmissmatch; + if (socketManager.read(fd, (char *) &global_dyn_stats[i].count, sizeof(global_dyn_stats[i].count)) + != sizeof(global_dyn_stats[i].count)) + goto Lmissmatch; + } + Debug("stats", "read_stats_snap: read statistics"); + + // close(fd); + socketManager.close(fd); + return; + +Lmissmatch: + Note("clearing statistics"); + clear_stats(); + //close(fd); + socketManager.close(fd); +} + +static void +write_stats_snap() +{ + int fd = 0; + int version = STATS_MAJOR_VERSION; + char *buf = NULL; + + if ((fd = open_stats_snap()) < 0) + goto Lerror; + + { + int stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS + MAX_DYN_STATS - NO_DYN_STATS; + int buf_size = sizeof(unsigned int) * 3 + stats_size * (sizeof(global_dyn_stats[0].sum) + sizeof(global_dyn_stats[0].count)); + buf = (char *) xmalloc(buf_size); + char *p = buf; + int i = 0; + + memcpy(p, (char *) &version, sizeof(version)); + p += sizeof(version); + memcpy(p, (char *) &stats_size, sizeof(stats_size)); + p += sizeof(stats_size); + + stats_size = MAX_HTTP_TRANS_STATS - NO_HTTP_TRANS_STATS; + STAT_LOCK_ACQUIRE(&(global_http_trans_stat_lock)); + for (i = 0; i < stats_size; i++) { + memcpy(p, (char *) &global_http_trans_stats[i].sum, sizeof(global_http_trans_stats[i].sum)); + p += sizeof(global_http_trans_stats[i].sum); + memcpy(p, (char *) &global_http_trans_stats[i].count, sizeof(global_http_trans_stats[i].count)); + p += sizeof(global_http_trans_stats[i].count); + } + STAT_LOCK_RELEASE(&(global_http_trans_stat_lock)); + stats_size = MAX_DYN_STATS - NO_DYN_STATS; + for (i = 0; i < stats_size; i++) { + // INKqa09981 (Clearing Host Database and DNS Statistics) + ink_statval_t count, sum; + READ_GLOBAL_DYN_STAT(i, count, sum); + memcpy(p, (char *) &sum, sizeof(sum)); + p += sizeof(sum); + memcpy(p, (char *) &count, sizeof(count)); + p += sizeof(count); + } + memcpy(p, (char *) &version, sizeof(version)); + p += sizeof(version); + + if (socketManager.write(fd, buf, buf_size) != buf_size) + goto Lerror; + } + if (buf) + xfree(buf); + //close(fd); + socketManager.close(fd); + Debug("stats", "snapped stats"); + return; +Lerror: + if (buf) + xfree(buf); + Warning("unable to snap statistics"); + //close(fd); + socketManager.close(fd); +} + +struct SnapStatsContinuation: public Continuation +{ + int mainEvent(int event, Event * e) + { + NOWARN_UNUSED(event); + write_stats_snap(); + e->schedule_every(HRTIME_SECONDS(snap_stats_every)); + return EVENT_CONT; + } + SnapStatsContinuation():Continuation(new_ProxyMutex()) + { + SET_HANDLER(&SnapStatsContinuation::mainEvent); + } +}; + +static void +take_rusage_snap() +{ + rusage_snap_old = rusage_snap; + rusage_snap_time_old = rusage_snap_time; + int retries = 3; + while (retries--) { + if (getrusage(RUSAGE_SELF, &rusage_snap) < 0) { + if (errno == EINTR) + continue; + Note("getrusage [%d %s]", errno, strerror(errno)); + } else + rusage_snap_time = ink_get_hrtime(); + break; + } + Debug("rusage", "took rusage snap %d", rusage_snap_time); +} + +struct SnapCont; +typedef int (SnapCont::*SnapContHandler) (int, void *); + +struct SnapCont: public Continuation +{ + int mainEvent(int event, Event * e) + { + NOWARN_UNUSED(event); + take_rusage_snap(); + e->schedule_every(SNAP_USAGE_PERIOD); + return EVENT_CONT; + } + SnapCont(ProxyMutex * m):Continuation(m) + { + SET_HANDLER((SnapContHandler) & SnapCont::mainEvent); + } +}; + +void +start_stats_snap() +{ + eventProcessor.schedule_every(NEW(new SnapCont(rusage_snap_mutex)), SNAP_USAGE_PERIOD, ET_CALL); + if (snap_stats_every) + eventProcessor.schedule_every(NEW(new SnapStatsContinuation()), HRTIME_SECONDS(snap_stats_every), ET_CALL); + else + Warning("disabling statistics snap"); +} + +static Action * +stat_callback(Continuation * cont, HTTPHdr * header) +{ + URL *url; + int length; + const char *path; + char *result = NULL; + int result_size; + bool empty; + + url = header->url_get(); + path = url->path_get(&length); + + + char *buffer = NULL; + int buffer_len = 0; + int num_prefix_buffer; + + char *var_prefix = (char *) xmalloc((length + 1) * sizeof(char)); + memset(var_prefix, 0, ((length + 1) * sizeof(char))); + strncpy(var_prefix, path, length); + + num_prefix_buffer = RecGetRecordPrefix_Xmalloc(var_prefix, &buffer, &buffer_len); + empty = (num_prefix_buffer == 0); + xfree(var_prefix); + + if (!empty) { + + result_size = (buffer_len + 16) * sizeof(char); + result = (char *) xmalloc(result_size); + memset(result, 0, result_size); + + snprintf(result, result_size - 7, "
    \n%s", buffer);
    +  }
    +
    +
    +  if (!empty) {
    +    StatPageData data;
    +
    +    strncat(result, "
    \n", result_size - strlen(result) - 1); + + data.data = result; + data.length = strlen(result); + cont->handleEvent(STAT_PAGE_SUCCESS, &data); + } else { + if (result) { + xfree(result); + } + cont->handleEvent(STAT_PAGE_FAILURE, NULL); + } + + if (buffer) + xfree(buffer); + + return ACTION_RESULT_DONE; +} + +static Action * +testpage_callback(Continuation * cont, HTTPHdr *) +{ + const int buf_size = 64000; + char *buffer = (char *) xmalloc(buf_size); + + if (buffer) { + for (int i = 0; i < buf_size; i++) { + buffer[i] = (char) ('a' + (i % 26)); + } + buffer[buf_size - 1] = '\0'; + + StatPageData data; + + data.data = buffer; + data.length = strlen(buffer); + cont->handleEvent(STAT_PAGE_SUCCESS, &data); + } else { + cont->handleEvent(STAT_PAGE_FAILURE, NULL); + } + return ACTION_RESULT_DONE; +} + +static void +testpage_callback_init() +{ + statPagesManager.register_http("test", testpage_callback); +} + +void +initialize_all_global_stats() +{ + int istat, i; + char snap_file[PATH_NAME_MAX + 1]; + char local_state_dir[PATH_NAME_MAX + 1]; + + // Jira TS-21 + REC_ReadConfigString(local_state_dir, "proxy.config.local_state_dir", PATH_NAME_MAX); + if (local_state_dir[0] != '/') { + // Not an absolute path + Layout::get()->relative(local_state_dir, sizeof(local_state_dir), local_state_dir); + } + if (access(local_state_dir, R_OK | W_OK) == -1) { + ink_strlcpy(local_state_dir, system_runtime_dir, sizeof(local_state_dir)); + if (access(local_state_dir, R_OK | W_OK) == -1) { + Warning("Unable to access() local state directory '%s': %d, %s", local_state_dir, errno, strerror(errno)); + Warning(" Please set 'proxy.config.local_state_dir' to allow statistics collection"); + } + } + REC_ReadConfigString(snap_file, "proxy.config.stats.snap_file", PATH_NAME_MAX); + Layout::relative_to(snap_filename, sizeof(snap_filename), + local_state_dir, snap_file); + Debug("stats", "stat snap filename %s", snap_filename); + + statPagesManager.register_http("stat", stat_callback); + + testpage_callback_init(); + + read_stats_snap(); + rusage_snap_mutex = new_ProxyMutex(); + take_rusage_snap(); + take_rusage_snap(); // fill in _old as well + + STAT_LOCK_INIT(&(global_http_trans_stat_lock), "Global Http Stats Lock"); + + for (istat = NO_HTTP_TRANS_STATS; istat < MAX_HTTP_TRANS_STATS; istat++) { + if (!persistent_stat(istat)) { + INITIALIZE_GLOBAL_TRANS_STATS(global_http_trans_stats[istat]); + } + } + + for (istat = NO_DYN_STATS; istat < MAX_DYN_STATS; istat++) { + if (!persistent_stat(istat)) { + i = istat - DYN_STAT_START; + INITIALIZE_GLOBAL_DYN_STATS(global_dyn_stats[i], "Dyn Stat Lock"); + } + } + + // TODO: HMMMM, wtf does this do? The following is that this + // function does: + // ink_atomic_swap_ptr(&this->f_update_lock, (void *) func) + // + // pmgmt->record_data->registerUpdateLockFunc(tmp_stats_lock_function); + +#ifdef DEBUG + ink_mutex_init(&http_time_lock, "Http Time Function Lock"); + last_http_local_time = 0; +#endif + + clear_http_handler_times(); +} + +//void * +//tmp_stats_lock_function(UpdateLockAction action) +//{ +// stats_lock_function((void *) (&global_http_trans_stat_lock), action); +// +// return NULL; +//} + +//void * +//stats_lock_function(void *data, UpdateLockAction action) +//{ +// if (action == UPDATE_LOCK_ACQUIRE) { +// STAT_LOCK_ACQUIRE((ink_stat_lock_t *) data); +// } else { +// STAT_LOCK_RELEASE((ink_stat_lock_t *) data); +// } +// +// return NULL; +//} + +void * +dyn_stats_int_msecs_to_float_seconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_DYN_STAT((long) data, count, sum); + + float r; + if (count == 0) { + r = 0.0; + } else { + r = ((float) sum) / 1000.0; + } + *(float *) res = r; + return res; +} + +void * +dyn_stats_count_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_DYN_STAT((long) data, count, sum); + NOWARN_UNUSED(sum); + //*(ink_statval_t *)res = count; + ink_atomic_swap64((ink_statval_t *) res, count); + return res; +} + +void * +dyn_stats_sum_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_DYN_STAT((long) data, count, sum); + NOWARN_UNUSED(count); + //*(ink_statval_t *)res = sum; + ink_atomic_swap64((ink_statval_t *) res, sum); + return res; +} + +void * +dyn_stats_avg_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_DYN_STAT((long) data, count, sum); + if (count == 0) { + *(float *) res = 0.0; + } else { + *(float *) res = (float) sum / (float) count; + } + return res; +} + +void * +dyn_stats_fsum_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_DYN_STAT((long) data, count, sum); + NOWARN_UNUSED(count); + *(float *) res = *(double *) ∑ + return res; +} + +void * +dyn_stats_favg_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_DYN_STAT((long) data, count, sum); + if (count == 0) { + *(float *) res = 0.0; + } else { + *(float *) res = *(double *) &sum / *(double *) &count; + } + return res; +} + +void * +dyn_stats_time_seconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + float r; + READ_DYN_STAT((long) data, count, sum); + if (count == 0) { + r = 0.0; + } else { + r = (float) sum / (float) count; + r = r / (float) HRTIME_SECOND; + } + *(float *) res = r; + return res; +} + +void * +dyn_stats_time_mseconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + float r; + READ_DYN_STAT((long) data, count, sum); + if (count == 0) { + r = 0.0; + } else { + r = (float) sum / (float) count; + r = r / (float) HRTIME_MSECOND; + } + *(float *) res = r; + return res; +} + +void * +dyn_stats_time_useconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + float r; + READ_DYN_STAT((long) data, count, sum); + if (count == 0) { + r = 0.0; + } else { + r = (float) sum / (float) count; + r = r / (float) HRTIME_USECOND; + } + *(float *) res = r; + return res; +} + +// http trans stat functions +// there is the implicit assumption that the lock has +// been acquired. +void * +http_trans_stats_int_msecs_to_float_seconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_HTTP_TRANS_STAT((long) data, count, sum); + + float r; + if (count == 0) { + r = 0.0; + } else { + r = ((float) sum) / 1000.0; + } + *(float *) res = r; + return res; +} + +void * +http_trans_stats_count_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_HTTP_TRANS_STAT((long) data, count, sum); + NOWARN_UNUSED(sum); + //*(ink_statval_t *)res = count; + ink_atomic_swap64((ink_statval_t *) res, count); + return res; +} + +void * +http_trans_stats_sum_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_HTTP_TRANS_STAT((long) data, count, sum); + NOWARN_UNUSED(count); + //*(ink_statval_t *)res = sum; + ink_atomic_swap64((ink_statval_t *) res, sum); + return res; +} + +void * +http_trans_stats_avg_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_HTTP_TRANS_STAT((long) data, count, sum); + if (count == 0) { + *(float *) res = 0.0; + } else { + *(float *) res = (float) sum / (float) count; + } + return res; +} + +void * +http_trans_stats_fsum_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_HTTP_TRANS_STAT((long) data, count, sum); + NOWARN_UNUSED(count); + *(float *) res = *(double *) ∑ + return res; +} + +void * +http_trans_stats_favg_cb(void *data, void *res) +{ + ink_statval_t count, sum; + READ_HTTP_TRANS_STAT((long) data, count, sum); + if (count == 0) { + *(float *) res = 0.0; + } else { + *(float *) res = *(double *) &sum / *(double *) &count; + } + return res; +} + +void * +http_trans_stats_time_seconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + float r; + READ_HTTP_TRANS_STAT((long) data, count, sum); + if (count == 0) { + r = 0.0; + } else { + r = (float) sum / (float) count; + r = r / (float) HRTIME_SECOND; + } + *(float *) res = r; + return res; +} + +void * +http_trans_stats_time_mseconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + float r; + READ_HTTP_TRANS_STAT((long) data, count, sum); + if (count == 0) { + r = 0.0; + } else { + r = (float) sum / (float) count; + r = r / (float) HRTIME_MSECOND; + } + *(float *) res = r; + return res; +} + +void * +http_trans_stats_time_useconds_cb(void *data, void *res) +{ + ink_statval_t count, sum; + float r; + READ_HTTP_TRANS_STAT((long) data, count, sum); + if (count == 0) { + r = 0.0; + } else { + r = (float) sum / (float) count; + r = r / (float) HRTIME_USECOND; + } + *(float *) res = r; + return res; +} + +////////////////////////////////////////////////////////////////////////////// +// +// TransactionMilestones::TransactionMilestones() +// +////////////////////////////////////////////////////////////////////////////// +TransactionMilestones::TransactionMilestones() +: +ua_begin(0), ua_read_header_done(0), ua_begin_write(0), ua_close(0), server_first_connect(0), server_connect(0), + // server_connect_end(0), + // server_begin_write(0), + server_first_read(0), server_read_header_done(0), server_close(0), cache_open_read_begin(0), cache_open_read_end(0), + // cache_read_begin(0), + // cache_read_end(0), + // cache_open_write_begin(0), + // cache_open_write_end(0), + // cache_write_begin(0), + // cache_write_end(0), + dns_lookup_begin(0), dns_lookup_end(0), sm_start(0), // init + sm_finish(0) // kill_this +{ + return; +} diff --git a/proxy/StatSystem.h b/proxy/StatSystem.h new file mode 100644 index 00000000..093dfff4 --- /dev/null +++ b/proxy/StatSystem.h @@ -0,0 +1,682 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + StatSystem.h -- + Created On : Fri Apr 3 19:41:39 1998 + ****************************************************************************/ +#if !defined (_StatSystem_h_) +#define _StatSystem_h_ + +#include "ink_platform.h" +#include "ink_hrtime.h" +#include "ink_atomic.h" +#ifdef USE_LOCKS_FOR_DYN_STATS +#include "Lock.h" +#endif + +#include "ink_apidefs.h" + +#define STATS_MAJOR_VERSION 6 // increment when changing the stats! +#define DEFAULT_SNAP_FILENAME "stats.snap" + +///////////////////////////////////////////////////////////// +// +// class TransactionMilestones +// +///////////////////////////////////////////////////////////// +class TransactionMilestones +{ +public: + //////////////////////////////////////////////////////// + // user agent: // + // user_agent_begin represents the time this // + // transaction started. If this is the first // + // transaction in a connection, then user_agent_begin // + // is set to accept time. otherwise it is set to // + // first read time. // + //////////////////////////////////////////////////////// + ink_hrtime ua_begin; + ink_hrtime ua_read_header_done; + ink_hrtime ua_begin_write; + ink_hrtime ua_close; + + //////////////////////////////////////////////////////// + // server (origin_server , parent, blind tunnnel // + //////////////////////////////////////////////////////// + ink_hrtime server_first_connect; + ink_hrtime server_connect; + // ink_hrtime server_connect_end; + // ink_hrtime server_begin_write; // http only + ink_hrtime server_first_read; // http only + ink_hrtime server_read_header_done; // http only + ink_hrtime server_close; + + ///////////////////////////////////////////// + // cache: // + // all or some variables may not be set in // + // certain conditions // + ///////////////////////////////////////////// + ink_hrtime cache_open_read_begin; + ink_hrtime cache_open_read_end; + // ink_hrtime cache_read_begin; + // ink_hrtime cache_read_end; + // ink_hrtime cache_open_write_begin; + // ink_hrtime cache_open_write_end; + // ink_hrtime cache_write_begin; + // ink_hrtime cache_write_end; + + ink_hrtime dns_lookup_begin; + ink_hrtime dns_lookup_end; + + /////////////////// + // state machine // + /////////////////// + ink_hrtime sm_start; + ink_hrtime sm_finish; + + TransactionMilestones(); +#ifdef DEBUG + bool invariant(); +#endif +}; + +typedef enum +{ + NO_HTTP_TRANSACTION_MILESTONES = 0, + client_accept_time, // u_a_accept - u_a_begin + client_header_read_time, // u_a_read_header_done - u_a_begin_read + client_response_write_time, // u_a_close - u_a_begin_write + // + cache_lookup_time, // cache_lookup_end - cache_lookup_begin + cache_update_time, // cache_update_end - cache_update_begin + cache_open_read_time, // cache_open_read_end - cache_open_read_begin + cache_read_time, // cache_read_end - cache_read_begin + cache_open_write_time, // cache_open_write_end - cache_open_write_begin + cache_write_time, // cache_write_end - cache_write_begin + // + server_open_time, // o_s_open_end - o_s_open_begin + server_response_time, // o_s_begin_read - o_s_begin_write + server_read_time, // o_s_read_header_done - o_s_begin_read + // + TOTAL_HTTP_TRANSACTION_MILESTONES +} HttpTransactionMilestone_t; + +extern ink_hrtime GlobalHttpMilestones[TOTAL_HTTP_TRANSACTION_MILESTONES]; +extern ink_hrtime TenSecondHttpMilestones[TOTAL_HTTP_TRANSACTION_MILESTONES]; + + +// Modularization Project: Build w/o thread-local-dyn-stats +// temporarily until we switch over to librecords. Revert to old +// non-thread-local system so that TS will still build and run. + +//---------------------------------------------------------------------// +// Welcome to enum land! // +//---------------------------------------------------------------------// + +// Before adding a stat variable, decide whether it is of +// a "transaction" type or if it is of a "dynamic" type. +// Then add the stat variable to the appropriate enumeration +// type. Make sure that DYN_STAT_START is large enough +// (read comment below). + +// +// Http Transaction Stats +// +#define _HEADER \ +typedef enum { \ + NO_HTTP_TRANS_STATS = 0, + +#define _FOOTER \ + MAX_HTTP_TRANS_STATS \ +} HttpTransactionStat_t; + +#if defined(freebsd) +#undef _D +#endif +#define _D(_x) _x, + +#include "HttpTransStats.h" +#undef _HEADER +#undef _FOOTER +#undef _D + +struct HttpTransactionStatsString_t +{ + HttpTransactionStat_t i; + char *name; +}; + +// +// Note: DYN_STAT_START needs to be at least the next +// power of 2 bigger than the value of MAX_HTTP_TRANS_STATS +// +#define DYN_STAT_START 2048 +#define DYN_STAT_MASK (~(2047UL)) +// +// Dynamic Stats +// +#define _HEADER \ +typedef enum { \ + NO_DYN_STATS = DYN_STAT_START, + +#define _FOOTER \ + MAX_DYN_STATS \ +} DynamicStat_t; + +#define _D(_x) _x, + +#include "DynamicStats.h" + +#undef _HEADER +#undef _FOOTER +#undef _D + +struct DynamicStatsString_t +{ + DynamicStat_t i; + const char *name; +}; + +extern HttpTransactionStatsString_t HttpTransactionStatsStrings[]; +extern DynamicStatsString_t DynamicStatsStrings[]; + +//---------------------------------------------------------------------// +// Typedefs, etc. // +//---------------------------------------------------------------------// + +// For now, use mutexes. May later change to spin_locks, try_locks. +#define ink_stat_lock_t ink_mutex + +typedef int64_t ink_statval_t; + +struct ink_local_stat_t +{ + ink_statval_t count; + ink_statval_t value; +}; + +struct ink_prot_global_stat_t +{ + ink_stat_lock_t access_lock; + ink_statval_t count; + ink_statval_t sum; + + ink_prot_global_stat_t() + : count(0), sum(0) + { + ink_mutex_init(&access_lock, "Stats Access Lock"); + } +}; + +struct ink_unprot_global_stat_t +{ + ink_statval_t count; + ink_statval_t sum; + ink_unprot_global_stat_t():count(0), sum(0) + { + } +}; + + +//---------------------------------------------------------------------// +// External interface macros // +//---------------------------------------------------------------------// + +// Set count and sum to 0. +#define CLEAR_DYN_STAT(X) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + CLEAR_GLOBAL_DYN_STAT(X-DYN_STAT_START); \ +} + +#define DECREMENT_DYN_STAT(X) SUM_DYN_STAT(X, (ink_statval_t)-1) + +#define COUNT_DYN_STAT(X,C) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + ADD_TO_GLOBAL_DYN_COUNT((X-DYN_STAT_START), C); \ +} + +#define FSUM_DYN_STAT(X, S) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + ADD_TO_GLOBAL_DYN_FSUM((X-DYN_STAT_START), S); \ +} + +// Increment the count, sum. +#define INCREMENT_DYN_STAT(X) SUM_DYN_STAT(X, (ink_statval_t)1) + +// Get the count and sum in a single lock acquire operation. +// Would it make sense to have three functions - a combined +// read of the count and sum, and two more functions - one +// to read just the count and the other to read just the sum? +#define READ_DYN_STAT(X,C,S) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + READ_GLOBAL_DYN_STAT((X-DYN_STAT_START),C,S); \ +} + +#define READ_DYN_COUNT(X,C) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + READ_GLOBAL_DYN_COUNT((X-DYN_STAT_START),C); \ +} + +#define READ_DYN_SUM(X,S) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + READ_GLOBAL_DYN_SUM((X-DYN_STAT_START),S); \ +} + +// set the stat.count to a specific value +#define SET_DYN_COUNT(X, V) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + SET_GLOBAL_DYN_COUNT((X-DYN_STAT_START), V); \ +} + +// set the stat.count stat.sum to specific values +#define SET_DYN_STAT(X, C, S) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + SET_GLOBAL_DYN_STAT((X-DYN_STAT_START), C, S); \ +} + +// Add a specific value to the sum. +#define SUM_DYN_STAT(X,S) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + ADD_TO_GLOBAL_DYN_SUM((X-DYN_STAT_START), S); \ +} + +// Add a specific value to the sum. +#define SUM_GLOBAL_DYN_STAT(X,S) \ +{ \ + ink_assert (X & DYN_STAT_MASK); \ + ADD_TO_GLOBAL_GLOBAL_DYN_SUM((X-DYN_STAT_START), S); \ +} + +#define __CLEAR_TRANS_STAT(local_stat_struct_, X) \ +{ \ + ink_assert (!(X & DYN_STAT_MASK)); \ + local_stat_struct_[X].count = (ink_statval_t)0; \ + local_stat_struct_[X].value = (ink_statval_t)0; \ +} + +#define __DECREMENT_TRANS_STAT(local_stat_struct_, X) __SUM_TRANS_STAT(local_stat_struct_, X, (ink_statval_t)-1) + +#define __FSUM_TRANS_STAT(local_stat_struct_, X, S) \ +{ \ + ink_assert (!(X & DYN_STAT_MASK)); \ + local_stat_struct_[X].count++; \ + (*(double *)&local_stat_struct_[X].value) += S; \ +} + +// Increment the count, sum. +#define __INCREMENT_TRANS_STAT(local_stat_struct_, X) __SUM_TRANS_STAT(local_stat_struct_, X, (ink_statval_t)1); + +#define __INITIALIZE_LOCAL_STAT_STRUCT(local_stat_struct_, X) __CLEAR_TRANS_STAT(local_stat_struct_, X) + +#define INITIALIZE_GLOBAL_TRANS_STATS(X) \ +{ \ + X.count = (ink_statval_t)0; \ + X.sum = (ink_statval_t)0; \ +} + +// Get the count and sum in a single lock acquire operation. +// Would it make sense to have three functions - a combined +// read of the count and sum, and two more functions - one +// to read just the count and the other to read just the sum? +#define READ_HTTP_TRANS_STAT(X,C,S) \ +{ \ + ink_assert (!(X & DYN_STAT_MASK)); \ + READ_GLOBAL_HTTP_TRANS_STAT(X,C,S); \ +} + +// set the stat.count to a specific value +#define __SET_TRANS_COUNT(local_stat_struct_, X, V) \ +{ \ + ink_assert (!(X & DYN_STAT_MASK)); \ + local_stat_struct_[X].value = (ink_statval_t)V; \ +} + +// set the stat.count and the stat.sum to specific values +#define __SET_TRANS_STAT(local_stat_struct_, X, C, S) \ +{ \ + ink_assert (!(X & DYN_STAT_MASK)); \ + local_stat_struct_[X].value = (ink_statval_t)S; \ +} + +// Add a specific value to local stat. +// Both ADD_TO_SUM_STAT and ADD_TO_COUNT_STAT do the same thing +// to the local copy of the transaction stat. +#define __SUM_TRANS_STAT(local_stat_struct_, X,S) \ +{ \ + ink_assert (!(X & DYN_STAT_MASK)); \ + local_stat_struct_[X].count += 1; \ + local_stat_struct_[X].value += S; \ +} + +#define UPDATE_HTTP_TRANS_STATS(local_stat_struct_) \ +{ \ + int i; \ + STAT_LOCK_ACQUIRE(&(global_http_trans_stat_lock)); \ + for (i=NO_HTTP_TRANS_STATS; ithread_holding->global_dyn_stats[X].count += (C) + +#define ADD_TO_GLOBAL_DYN_SUM(X,S) \ +mutex->thread_holding->global_dyn_stats[X].count ++; \ +mutex->thread_holding->global_dyn_stats[X].sum += (S) + +#define ADD_TO_GLOBAL_GLOBAL_DYN_SUM(X,S) \ +ink_atomic_increment64(&global_dyn_stats[X].count,(ink_statval_t)1); \ +ink_atomic_increment64(&global_dyn_stats[X].sum,S) +/* + * global_dyn_stats[X].count ++; \ + * global_dyn_stats[X].sum += (S) + */ + +#define ADD_TO_GLOBAL_DYN_FSUM(X,S) \ +mutex->thread_holding->global_dyn_stats[X].count++; \ +mutex->thread_holding->global_dyn_stats[X].sum += (S) + +#define CLEAR_GLOBAL_DYN_STAT(X) \ +global_dyn_stats[X].count = 0; \ +global_dyn_stats[X].sum = 0 + +#ifdef _WIN32 + +#define READ_GLOBAL_DYN_STAT(X,C,S) do { \ + ink_unprot_global_stat_t _s = global_dyn_stats[X]; \ + for (int _e = 0; _e < eventProcessor.get_thread_count() ; _e++) { \ + _s.count += eventProcessor._all_ethreads[_e]->global_dyn_stats[X].count; \ + _s.sum += eventProcessor._all_ethreads[_e]->global_dyn_stats[X].sum; \ + } \ + C = _s.count; \ + S = _s.sum; \ +} while (0) + +#define READ_GLOBAL_DYN_COUNT(X,C) do { \ + ink_statval_t _s = global_dyn_stats[X].count; \ + for (int _e = 0; _e < eventProcessor.get_thread_count() ; _e++) \ + _s += eventProcessor._all_ethreads[_e]->global_dyn_stats[X].count; \ + C = _s; \ +} while (0) + +#define READ_GLOBAL_DYN_SUM(X,S) do { \ + ink_statval_t _s = global_dyn_stats[X].sum; \ + for (int _e = 0; _e < eventProcessor.get_thread_count() ; _e++) \ + _s += eventProcessor._all_ethreads[_e]->global_dyn_stats[X].sum; \ + S = _s; \ +} while (0) + +#else + +#define READ_GLOBAL_DYN_STAT(X,C,S) do { \ + ink_unprot_global_stat_t _s = global_dyn_stats[X]; \ + for (int _e = 0; _e < eventProcessor.n_ethreads ; _e++) { \ + _s.count += eventProcessor.all_ethreads[_e]->global_dyn_stats[X].count; \ + _s.sum += eventProcessor.all_ethreads[_e]->global_dyn_stats[X].sum; \ + } \ + C = _s.count; \ + S = _s.sum; \ +} while (0) + +#define READ_GLOBAL_DYN_COUNT(X,C) do { \ + ink_statval_t _s = global_dyn_stats[X].count; \ + for (int _e = 0; _e < eventProcessor.n_ethreads ; _e++) \ + _s += eventProcessor.all_ethreads[_e]->global_dyn_stats[X].count; \ + C = _s; \ +} while (0) + +#define READ_GLOBAL_DYN_SUM(X,S) do { \ + ink_statval_t _s = global_dyn_stats[X].sum; \ + for (int _e = 0; _e < eventProcessor.n_ethreads ; _e++) \ + _s += eventProcessor.all_ethreads[_e]->global_dyn_stats[X].sum; \ + S = _s; \ +} while (0) + +#endif + +#define READ_GLOBAL_HTTP_TRANS_STAT(X,C,S) \ +{ \ + C = global_http_trans_stats[X].count; \ + S = global_http_trans_stats[X].sum; \ +} + +#define SET_GLOBAL_DYN_COUNT(X,V) \ +global_dyn_stats[X].count = V + +#define SET_GLOBAL_DYN_STAT(X,C,S) \ +global_dyn_stats[X].count = C; \ +global_dyn_stats[X].sum = S + +#define INITIALIZE_GLOBAL_DYN_STATS(X, T) \ +{ \ + X.count = (ink_statval_t)0; \ + X.sum = (ink_statval_t)0; \ +} + +#else + +#define ADD_TO_GLOBAL_DYN_COUNT(X,C) \ +ink_atomic_increment64(&global_dyn_stats[X].count,C) + +#define ADD_TO_GLOBAL_DYN_SUM(X,S) \ +ink_atomic_increment64(&global_dyn_stats[X].count,(ink_statval_t)1); \ +ink_atomic_increment64(&global_dyn_stats[X].sum,S) + +#define ADD_TO_GLOBAL_GLOBAL_DYN_SUM(X,S) \ +ink_atomic_increment64(&global_dyn_stats[X].count,(ink_statval_t)1); \ +ink_atomic_increment64(&global_dyn_stats[X].sum,S) + +#define ADD_TO_GLOBAL_DYN_FSUM(X,S) \ +ink_atomic_increment64(&global_dyn_stats[X].count,(ink_statval_t)1); \ +(*(double *)&global_dyn_stats[X].sum) += S + +#define CLEAR_GLOBAL_DYN_STAT(X) \ +global_dyn_stats[X].count = 0; \ +global_dyn_stats[X].sum = 0 + +#define READ_GLOBAL_DYN_STAT(X,C,S) \ +C = global_dyn_stats[X].count; \ +S = global_dyn_stats[X].sum + +#define READ_GLOBAL_DYN_COUNT(X,C) \ +C = global_dyn_stats[X].count; + +#define READ_GLOBAL_DYN_SUM(X,S) \ +S = global_dyn_stats[X].sum; + +#define READ_GLOBAL_HTTP_TRANS_STAT(X,C,S) \ +{ \ + C = global_http_trans_stats[X].count; \ + S = global_http_trans_stats[X].sum; \ +} + +#define SET_GLOBAL_DYN_COUNT(X,V) \ +global_dyn_stats[X].count = V + +#define SET_GLOBAL_DYN_STAT(X,C,S) \ +global_dyn_stats[X].count = C; \ +global_dyn_stats[X].sum = S + +#define INITIALIZE_GLOBAL_DYN_STATS(X, T) \ +{ \ + X.count = (ink_statval_t)0; \ + X.sum = (ink_statval_t)0; \ +} + +#endif /* USE_THREAD_LOCAL_DYN_STATS */ + +#else /* USE_LOCKS_FOR_DYN_STATS */ + +#define ADD_TO_GLOBAL_DYN_COUNT(X,C) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count += C; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} +#define ADD_TO_GLOBAL_DYN_SUM(X,S) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count += 1; \ + global_dyn_stats[X].sum += S; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} +#define ADD_TO_GLOBAL_GLOBAL_DYN_SUM(X,S) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count += 1; \ + global_dyn_stats[X].sum += S; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} +#define ADD_TO_GLOBAL_DYN_FSUM(X,S) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count += (ink_statval_t)1; \ + (*(double *)&global_dyn_stats[X].sum) += S; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} +#define CLEAR_GLOBAL_DYN_STAT(X) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count = (ink_statval_t)0; \ + global_dyn_stats[X].sum = (ink_statval_t)0; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} +#define READ_GLOBAL_DYN_STAT(X,C,S) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + C = global_dyn_stats[X].count; \ + S = global_dyn_stats[X].sum; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} +#define READ_GLOBAL_HTTP_TRANS_STAT(X,C,S) \ +{ \ + C = global_http_trans_stats[X].count; \ + S = global_http_trans_stats[X].sum; \ +} +#define SET_GLOBAL_DYN_COUNT(X,V) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count = V; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} + +#define SET_GLOBAL_DYN_STAT(X,C,S) \ +{ \ + STAT_LOCK_ACQUIRE(&(global_dyn_stats[X].access_lock)); \ + global_dyn_stats[X].count = C; \ + global_dyn_stats[X].sum = S; \ + STAT_LOCK_RELEASE(&(global_dyn_stats[X].access_lock)); \ +} + +#define INITIALIZE_GLOBAL_DYN_STATS(X, T) \ +{ \ + STAT_LOCK_INIT(&(X.access_lock), T); \ + X.count = (ink_statval_t)0; \ + X.sum = (ink_statval_t)0; \ +} + +#endif /* USE_LOCKS_FOR_DYN_STATS */ + +//---------------------------------------------------------------------// +// Function prototypes // +//---------------------------------------------------------------------// +extern void start_stats_snap(void); +void initialize_all_global_stats(); + +// TODO: I don't think these are necessary any more, but double check. +//void *tmp_stats_lock_function(UpdateLockAction action); +//void *stats_lock_function(void *data, UpdateLockAction action); + +void *http_trans_stats_count_cb(void *data, void *res); +void *http_trans_stats_sum_cb(void *data, void *res); +void *http_trans_stats_avg_cb(void *data, void *res); +void *http_trans_stats_fsum_cb(void *data, void *res); +void *http_trans_stats_favg_cb(void *data, void *res); +void *http_trans_stats_time_seconds_cb(void *data, void *res); +void *http_trans_stats_time_mseconds_cb(void *data, void *res); +void *http_trans_stats_time_useconds_cb(void *data, void *res); + +void *dyn_stats_count_cb(void *data, void *res); +inkcoreapi void *dyn_stats_sum_cb(void *data, void *res); +void *dyn_stats_avg_cb(void *data, void *res); +void *dyn_stats_fsum_cb(void *data, void *res); +void *dyn_stats_favg_cb(void *data, void *res); +void *dyn_stats_time_seconds_cb(void *data, void *res); +void *dyn_stats_time_mseconds_cb(void *data, void *res); +void *dyn_stats_time_useconds_cb(void *data, void *res); +void *dyn_stats_int_msecs_to_float_seconds_cb(void *data, void *res); +//---------------------------------------------------------------------// +// Global variables declaration. // +//---------------------------------------------------------------------// +extern ink_stat_lock_t global_http_trans_stat_lock; +extern ink_unprot_global_stat_t global_http_trans_stats[MAX_HTTP_TRANS_STATS]; +#ifndef USE_LOCKS_FOR_DYN_STATS +extern inkcoreapi ink_unprot_global_stat_t global_dyn_stats[MAX_DYN_STATS - DYN_STAT_START]; +#else +extern inkcoreapi ink_prot_global_stat_t global_dyn_stats[MAX_DYN_STATS - DYN_STAT_START]; +#endif + +#ifdef DEBUG +extern ink_mutex http_time_lock; +extern time_t last_http_local_time; +#endif + +#define MAX_HTTP_HANDLER_EVENTS 25 +extern void clear_http_handler_times(); +extern void print_http_handler_time(int event); +extern void print_all_http_handler_times(); +#ifdef DEBUG +extern ink_hrtime http_handler_times[MAX_HTTP_HANDLER_EVENTS]; +extern int http_handler_counts[MAX_HTTP_HANDLER_EVENTS]; +#endif + + +#endif /* _StatSystem_h_ */ diff --git a/proxy/Stuffer.cc b/proxy/Stuffer.cc new file mode 100644 index 00000000..eac3a0cb --- /dev/null +++ b/proxy/Stuffer.cc @@ -0,0 +1,744 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "Net.h" +#include "HTTP.h" +#include "HttpTransact.h" +#include "HttpTransactHeaders.h" +#include "Stuffer.h" +#include "ParentSelection.h" + +StufferHashTable *stuffer_htable; +static uint32_t *stuffer_parent_ip_array = 0; +static int stuffer_num_parents; + +static inline bool +connAllowed(uint32_t ip) +{ + if (((unsigned char *) &ip)[0] == 127) // allow localhost connetions + return true; + + int n = stuffer_num_parents; + uint32_t *ips = stuffer_parent_ip_array; + + for (int i = 0; i < n; i++) + if (ip == ips[i]) + return true; + + return false; +} + +struct StufferAccepter:Continuation +{ + StufferAccepter():Continuation(NULL) + { + SET_HANDLER(&StufferAccepter::mainEvent); + } + + int mainEvent(int event, void *data) + { + //Debug("stuffer", "received a connection"); + ink_assert(event == NET_EVENT_ACCEPT); + NetVConnection *netvc = (NetVConnection *) data; + + if (connAllowed(netvc->get_remote_ip())) { + stufferAllocator.alloc()->init(netvc); + } else { + uint32_t ip = netvc->get_remote_ip(); + unsigned char *str = (unsigned char *) &ip; + Debug("stuffer", "rejecting connection from %d.%d.%d.%d", str[0], str[1], str[2], str[3]); + netvc->do_io_close(); + } + + return EVENT_DONE; + } +}; + + +#define MAX_PARENTS 64 +static int +readIPs(ParentRecord * parentRec, uint32_t * ip_arr, int max) +{ + if (!parentRec) + return 0; + + int n = 0; + pRecord *pr = parentRec->parents; + int n_parents = parentRec->num_parents; + + for (int i = 0; i < n_parents && n < max; i++) { + ink_gethostbyname_r_data data; + + struct hostent *ent = ink_gethostbyname_r(pr[i].hostname, &data); + if (ent) + ip_arr[n++] = *(uint32_t *) ent->h_addr_list[0]; + } + + return n; +} + +static void +buildParentIPTable() +{ + uint32_t ips[MAX_PARENTS]; + int n = 0; + + ParentConfigParams *params = ParentConfig::acquire(); + + /* there is no simple way to get the parent ip addresses. + we will dig through the structures */ + + n += readIPs(params->DefaultParent, &ips[n], MAX_PARENTS - n); + +#define READ_IPS(x) if (x) \ + n += readIPs((x)->data_array, &ips[n], MAX_PARENTS-n) + + READ_IPS(params->ParentTable->reMatch); + READ_IPS(params->ParentTable->hostMatch); + READ_IPS(params->ParentTable->ipMatch); + +#undef READ_IPS + + ParentConfig::release(params); + + stuffer_num_parents = n; + if (n > 0) { + stuffer_parent_ip_array = (uint32_t *) xmalloc(n * sizeof(uint32_t)); + memcpy(stuffer_parent_ip_array, &ips[0], n * sizeof(uint32_t)); + for (int i = 0; i < n; i++) { + unsigned char *str = (unsigned char *) &ips[i]; + Debug("stuffer_parent_ips", "parent ip [%d] = %d.%d.%d.%d", i, str[0], str[1], str[2], str[3]); + } + } + + return; +} + +void +StufferInitialize(void) +{ + stuffer_htable = NEW(new StufferHashTable(512)); + + int stuffer_port; + ReadConfigInteger(stuffer_port, proxy_config_stuffer_port); + Debug("stuffer", "stuffer initialized (port = %d%s)", stuffer_port, stuffer_port ? "" : " accept disabled"); + buildParentIPTable(); + + if (stuffer_port > 0) + netProcessor.main_accept(NEW(new StufferAccepter), NO_FD, stuffer_port); +} + +ClassAllocator stufferAllocator("stufferAllocator"); +ClassAllocator stufferCacheWriterAllocator("stufferCacheWriterAllocator"); + +inline void +StufferCacheWriter::init(Stuffer * s, int64_t ntowrite) +{ + mutex = s->mutex; + SET_HANDLER(&StufferCacheWriter::mainEvent); + + stuffer = s; + + buf = new_MIOBuffer(BUFFER_SIZE_INDEX_128); + reader = buf->alloc_reader(); + + ntodo = ntowrite; +} + +inline int +StufferCacheWriter::addData(int max) +{ + int nwritten = buf->write(stuffer->reader, max); + + nadded += nwritten; + return nwritten; +} + +inline void +Stuffer::reset() +{ + ink_assert(cur_ntodo == 0); + state = STUFFER_START; +} + +void +Stuffer::free() +{ + if (active_cache_writers > 0) { + mainEvent(EVENT_INTERVAL, NULL); + return; + } + + ink_assert(active_cache_buffer == 0); + if (buf) + free_MIOBuffer(buf); + + ink_assert(!source_vc); + if (source_vc) + source_vc->do_io_close(); + + stufferAllocator.free(this); +} + +inline int +Stuffer::processInitialData() +{ + cur_ntodo = -1; + int64_t nbytes_avail = reader->read_avail(); + + if (nbytes_avail < KEEPALIVE_LEN_BYTES + 3) + return STUFFER_START; + + int size; + ink_assert(KEEPALIVE_LEN_BYTES == sizeof(size)); + reader->read((char *) &size, sizeof(size)); + cur_ntodo = ntohl(size) - KEEPALIVE_LEN_BYTES; + Debug("stuffer_keepalive", "cur doc size = %d", cur_ntodo); + INCREMENT_DYN_STAT(stuffer_total_bytes_received); + + char cbuf[3]; + reader->memcpy(cbuf, 3); + + if (strncmp(cbuf, "GET", 3) != 0) + return URL_PROMISES; + + return URL_OBJECT; +} + +int +Stuffer::mainEvent(int event, void *data) +{ + //if (data && (event == VC_EVENT_READ_READY || event == VC_EVENT_EOS)) + //Debug("stuffer_keepalive", "ndone = %d", source_vio->ndone); + + switch (event) { + + case NET_EVENT_ACCEPT: + Debug("stuffer", "accepted a new connetion on stuffer port"); + buf = new_MIOBuffer(); + reader = buf->alloc_reader(); + buf->water_mark = buf->block_write_avail(); + + source_vio = source_vc->do_io_read(this, INT64_MAX, buf); + break; + + case VC_EVENT_EOS: + case VC_EVENT_ERROR: + source_vc->do_io_close(); + source_vc = 0; + + process_read_ready: //this label reduces recursion + case VC_EVENT_READ_READY: + if (state == STUFFER_START) + state = processInitialData(); + + switch (state) { + + case URL_PROMISES:{ + int null_pos; + + while ((null_pos = reader->memchr(0)) >= 0) { + null_pos++; + + char *str = (char *) xmalloc(null_pos); + if (str) { + reader->read(str, null_pos); + stuffer_htable->add(str); + } else + reader->consume(null_pos); + + cur_ntodo -= null_pos; + if (cur_ntodo <= 0) { + INCREMENT_DYN_STAT(stuffer_total_promises); + reset(); + goto process_read_ready; + } + } + //bug: if a url is larger than block size this will + //stop reading after 1 block + break; + } + + case URL_OBJECT: + if (active_cache_writers >= MAX_CACHE_WRITERS_OUTSTANDING) { + Debug("stuffer_temp", "%d cache writers already active\n", active_cache_writers); + return EVENT_DONE; + } + + INCREMENT_DYN_STAT(stuffer_total_objects); + cache_writer = stufferCacheWriterAllocator.alloc(); + cache_writer->init(this, cur_ntodo); + active_cache_writers++; + state = CACHE_WRITE; + + //fall through + + case CACHE_WRITE:{ + if (active_cache_buffer >= MAX_KEEPALIVE_BUFFER && active_cache_writers > 1) { + Debug("stuffer_temp", "outstandig buffer(%d) exceeds the " "limit.. throttling", active_cache_buffer); + return EVENT_DONE; + } + + int nwritten = cache_writer->addData(cur_ntodo); + reader->consume(nwritten); + cur_ntodo -= nwritten; + active_cache_buffer += nwritten; + + if (cur_ntodo > 0) { + if (nwritten > 0) + cache_writer->mainEvent(VC_EVENT_READ_READY, NULL); + } else { + StufferCacheWriter *temp = cache_writer; + cache_writer = 0; + reset(); + temp->mainEvent(VC_EVENT_READ_COMPLETE, NULL); + goto process_read_ready; + } + } + } //switch(state); + + break; + + case EVENT_IMMEDIATE:{ + //one of the cache_writers called us back + int nadded = (int) data; + active_cache_buffer -= nadded; + active_cache_writers--; + ink_assert(active_cache_buffer >= 0 && active_cache_writers >= 0); + goto process_read_ready; + } + + case EVENT_INTERVAL: + if (active_cache_writers > 0) + this_ethread()->schedule_imm(this, ink_hrtime_from_msec(10)); + else + free(); + return EVENT_DONE; + + default: + ink_assert(!"unexpected event"); + free(); + return EVENT_DONE; + } + + if (source_vc) + source_vio->reenable(); + else { + ink_assert(cur_ntodo < 0 || !reader->read_avail()); + Debug("stuffer_keepalive", "closing keepalive connection " "(read_avail: %d)", reader->read_avail()); + + if (cache_writer) { + cache_writer->mainEvent(VC_EVENT_READ_COMPLETE, NULL); + cache_writer = 0; + } + free(); + } + + return EVENT_CONT; +} + +inline void +StufferCacheWriter::initCacheLookupConfig() +{ + //we should be able to use a static variable and initialize only once. + //The look up parameters are intialized in the same as it is done + //in HttpSM::init(). Any changes there should come in here. + HttpConfigParams *http_config_params = HttpConfig::acquire(); + + cache_lookup_config.cache_global_user_agent_header = http_config_params->global_user_agent_header ? true : false; + cache_lookup_config.cache_enable_default_vary_headers = http_config_params->cache_enable_default_vary_headers ? true : false; + cache_lookup_config.cache_vary_default_text = http_config_params->cache_vary_default_text; + cache_lookup_config.cache_vary_default_images = http_config_params->cache_vary_default_images; + cache_lookup_config.cache_vary_default_other = http_config_params->cache_vary_default_other; + + HttpConfig::release(http_config_params); +} + +void +StufferCacheWriter::free() +{ + if (url) { + StufferURLPromise *p = stuffer_htable->lookup(url); + if (p) + p->free(true); + xfree(url); + url = 0; + } + + ink_assert(!cache_vc); + + if (http_info.valid()) + http_info.destroy(); + http_parser_clear(&http_parser); + + free_MIOBuffer(buf); + + stuffer->mainEvent(EVENT_IMMEDIATE, (void *) nadded); + + mutex = NULL; + stufferCacheWriterAllocator.free(this); +} + +inline bool +responseIsNewer(HTTPHdr * old_resp, HTTPHdr * new_resp) +{ + time_t old_lm = old_resp->get_last_modified(); + time_t new_lm = new_resp->get_last_modified(); + + /*debug only stuff: to be removed */ + //Debug("stuffer_cache", "new last modified : %d old : %d " + //"(need to replace: %d)", new_lm, old_lm, new_lm > old_lm); + + if (new_lm > old_lm) + return true; + + if ((old_lm = old_resp->get_expires()) && old_lm < ink_cluster_time()) + return true; + + return false; +} + +int +StufferCacheWriter::mainEvent(int event, void *data) +{ + switch (event) { + + case VC_EVENT_READ_COMPLETE:{ + //Debug("stuffer_keepalive", "Writer got READ_COMPLETE"); + got_read_complete = 1; + + int64_t nread_avail = reader->read_avail(); + ink_assert(nread_avail <= ntodo); + ntodo = nread_avail; + + if (cache_vc) + cache_vio->nbytes = cache_vio->ndone + nread_avail; + } + //fall through + + case VC_EVENT_READ_READY: + //if (!got_read_complete) + //Debug("stuffer_keepalive", "Writer got READ_READY"); + + switch (state) { + + case PARSE_HEADERS:{ + + int rc = parseHeaders(); + + if (rc == PARSE_CONT) { + if (got_read_complete) + free(); + } else if (rc == PARSE_DONE && + HttpTransactHeaders::does_server_allow_response_to_be_stored(&http_info.m_alt->m_response_hdr)) { + URL u; + HTTPHdr *request = &http_info.m_alt->m_request_hdr; + request->url_get(&u); + ink_time_t now = ink_cluster_time(); + http_info.request_sent_time_set(now); + http_info.response_received_time_set(now); + + state = CACHE_READ_OPEN; + cacheProcessor.open_read(this, &u, request, &cache_lookup_config, 0); + } else { + //rc == PARSE_ERROR || object_not_cacheable + state = CACHE_WRITE; + goto check_vc_n_break; + } + break; + } + + check_vc_n_break: + case CACHE_WRITE: + if (cache_vc) + cache_vio->reenable(); + else if (got_read_complete) + free(); + else + reader->consume(reader->read_avail()); + + break; + + } //switch(state) + + break; + + case CACHE_EVENT_OPEN_READ:{ + //do some simple checks to see if we need to push the object + //right now, just dont push it. + //Debug("stuffer_cache", "open_read succeded (%s)\n", url); + + open_read_vc = (CacheVC *) data; + CacheHTTPInfo *cached_http_info; + open_read_vc->get_http_info(&cached_http_info); + + bool needs_update = responseIsNewer(&cached_http_info->m_alt->m_response_hdr, + &http_info.m_alt->m_response_hdr); + if (!needs_update) { + open_read_vc->do_io_close(); + open_read_vc = 0; + state = CACHE_WRITE; + goto check_vc_n_break; + } + http_info.m_alt->m_response_hdr.field_delete(MIME_FIELD_SET_COOKIE, MIME_LEN_SET_COOKIE); + } + case CACHE_EVENT_OPEN_READ_FAILED:{ + //Debug("stuffer_cache", "open_read failed (%s)\n", url); + + URL u; + HTTPHdr *request = &http_info.m_alt->m_request_hdr; + request->url_get(&u); + + CacheHTTPInfo *cached_http_info = 0; + if (open_read_vc) + open_read_vc->get_http_info(&cached_http_info); + + state = CACHE_WRITE_OPEN; + cacheProcessor.open_write(this, 0, &u, request, cached_http_info); + break; + } + + case CACHE_EVENT_OPEN_WRITE: + state = CACHE_WRITE; + + if (ntodo > 0) { + if (open_read_vc) + open_read_vc->do_io_close(); + + cache_vc = (CacheVC *) data; + cache_vc->set_http_info(&http_info); + + cache_vio = cache_vc->do_io_write(this, ntodo, reader); + + INCREMENT_DYN_STAT(stuffer_total_objects_pushed); + break; + } + + case CACHE_EVENT_OPEN_WRITE_FAILED: + if (open_read_vc) + open_read_vc->do_io_close(); + state = CACHE_WRITE; + goto check_vc_n_break; + + case VC_EVENT_WRITE_READY: + break; + + case VC_EVENT_WRITE_COMPLETE: + ink_assert(got_read_complete); + default: + cache_vc->do_io_close(); + cache_vc = 0; + goto check_vc_n_break; + } + + return EVENT_CONT; +} + +int +StufferCacheWriter::parseHeaders() +{ + int ret = PARSE_CONT; + int64_t nbytes_used; + + if (parse_state == PARSE_START) { + http_info.create(); + http_info.m_alt->m_request_hdr.create(HTTP_TYPE_REQUEST); + http_info.m_alt->m_response_hdr.create(HTTP_TYPE_RESPONSE); + //http_parser_clear(&http_parser); + + parse_state = PARSE_REQ; + } + + if (parse_state == PARSE_REQ && reader->read_avail()) { + HTTPHdr *request = &http_info.m_alt->m_request_hdr; + ret = request->parse_req(&http_parser, reader, &nbytes_used, false); + ntodo -= nbytes_used; + + if (ret == PARSE_DONE) { + parse_state = PARSE_RESP; + ret = PARSE_CONT; + http_parser_clear(&http_parser); + + url = request->url_get()->string_get(NULL); + Debug("stuffer_urls", "extracted url %s from the object", url); + } + } + + if (parse_state == PARSE_RESP && reader->read_avail() > 0) { + ret = http_info.m_alt->m_response_hdr.parse_resp(&http_parser, reader, &nbytes_used, false); + ntodo -= nbytes_used; + } + return ret; +} + +ClassAllocator stufferURLPromiseAllocator("stufferURLPromiseAllocator"); + +void +StufferURLPromise::free(bool obj_pushed) +{ + if (overall_timeout) + overall_timeout->cancel(); + if (cache_block_timeout) + cache_block_timeout->cancel(); + + if (head.cache_vc) { + Debug("stuffer_cache", "waking up cache_vcs waiting on %s", url); + head.cache_vc->stuffer_cache_reenable(obj_pushed ? EVENT_DONE : EVENT_CONT); + } + // inform the dynamically allocated ones + while (head.next) { + head.next->cache_vc->stuffer_cache_reenable(obj_pushed ? EVENT_DONE : EVENT_CONT); + cache_obj_list *temp = head.next; + head.next = temp->next; + delete temp; + } + + stuffer_htable->remove(this); + xfree(url); + stufferURLPromiseAllocator.free(this); +} + +void +StufferURLPromise::add_waiter(CacheVC * cache_vc) +{ + if (!head.cache_vc) // common case + head.cache_vc = cache_vc; + else { + cache_obj_list *new_elem = NEW(new cache_obj_list); + new_elem->cache_vc = cache_vc; + new_elem->next = head.next; + head.next = new_elem; + } + if (!cache_block_timeout) + cache_block_timeout = this_ethread()->schedule_in(this, ink_hrtime_from_msec(STUFFER_CACHE_BLOCK_TIMEOUT_MSECS)); +} + +int +StufferURLPromise::mainEvent(int event, void *data) +{ + ink_assert(event == EVENT_INTERVAL); + Debug("stuffer_timeouts", "%s timeout expired for promise", (data == overall_timeout) ? "overall" : "cache block"); + if (data == overall_timeout) + overall_timeout = NULL; + else if (data == cache_block_timeout) + cache_block_timeout = NULL; + free(); + return EVENT_DONE; +} + +int +StufferCacheIncomingRequest(CacheVC * cache_vc) +{ + /* extract url out of this vc. + use local buffer to avoid another xmalloc(), otherwise we could just + use url_obj->string_get() */ +#define BUF_SIZE 512 + char url[BUF_SIZE]; + int len, index = 0, offset = 0; + + /* check if this open_read is from a StufferCacheWriter */ + //if (dynamic_cast(cache_vc->_action.continuation)) + if (STUFFER_CACHE_WRITER(cache_vc->_action.continuation)) + return EVENT_CONT; + + URL *url_obj = cache_vc->request.url_get(); + + if ((len = url_obj->length_get()) >= BUF_SIZE) + return EVENT_CONT; + url_obj->print(url, BUF_SIZE - 1, &index, &offset); + url[len] = 0; + + StufferURLPromise *promise; + ProxyMutex *mutex = cache_vc->mutex; //for DYN_STATS + + MUTEX_TRY_LOCK(lock, stuffer_htable->mutex, this_ethread()); + + if (!lock || ((promise = stuffer_htable->lookup(url)) == NULL)) { + Debug("stuffer_cache", "informing cache: not expecting %s", url); + INCREMENT_DYN_STAT(stuffer_url_lookup_misses); + return EVENT_CONT; + } + + INCREMENT_DYN_STAT(stuffer_open_read_blocks); + Debug("stuffer_cache", "informing cache: %s is exptected", url); + promise->add_waiter(cache_vc); + return EVENT_DONE; +#undef BUF_SIZE +} + +//simple hash_table implementation +int +StufferHashTable::index(const char *s) +{ + int l = 1, len = strlen(s); + unsigned int hash_value = 0, i = 0; + + while (l <= len) { + i = (i << 8) | s[len - l]; + if (l % sizeof(int) == 0) + hash_value ^= i; + l++; + } + //we can neglect the first 3 letters in the worst case.. they are same + + return hash_value % size; +} + +StufferURLPromise ** +StufferHashTable::position(const char *url) +{ + StufferURLPromise **e = &array[index(url)]; + + while (*e) { + if (strcmp((*e)->url, url) == 0) + return e; + e = &(*e)->next; + } + return e; +} + +void +StufferHashTable::add(char *url) +{ + StufferURLPromise **e = position(url); + if (*e) { + //right now we just neglect the URL + xfree(url); + return; + } + + Debug("stuffer_urls", "adding promise %s to the table", url); + StufferURLPromise *up = stufferURLPromiseAllocator.alloc(); + up->init(url); + *e = up; +} + +void +StufferHashTable::remove(StufferURLPromise * p) +{ + StufferURLPromise **e = position(p->url); + ink_assert(p == *e); + + Debug("stuffer_urls", "removing promise %s from the list", p->url); + *e = p->next; +} diff --git a/proxy/Stuffer.h b/proxy/Stuffer.h new file mode 100644 index 00000000..175b1670 --- /dev/null +++ b/proxy/Stuffer.h @@ -0,0 +1,253 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +#include "NetVConnection.h" +#include "CacheInternal.h" +#include "OneWayTunnel.h" +#include "HttpTransact.h" + +/* A URL promise will be deleted if the following timeout occurs before the + corresponding data arrives */ +#define STUFFER_URL_PROMISE_TIMEOUT_MSECS 120000 + +/* We block the cache for maximum of this time while waiting for a URL data to + arrive */ +#define STUFFER_CACHE_BLOCK_TIMEOUT_MSECS 120000 + +//from Prefetch.cc +#define KEEPALIVE_LEN_BYTES sizeof(int) + +/*Note on locking: TS Micro is going to run on single processror + machines. On top of that we cannot have more than one threads for + events even if we want to due to resource contraints. For now, all + the stuffer objects and the hash table use the same mutex namely + stuffer_htable->mutex. +*/ +class StufferURLPromise; + +class StufferHashTable +{ + +public: + + StufferHashTable(int sz) + { + size = sz; + array = NEW(new StufferURLPromise *[size]); + memset(array, 0, size * sizeof(StufferURLPromise *)); + mutex = new_ProxyMutex(); + } + ~StufferHashTable() + { + delete array; + mutex = NULL; + } + + int index(const char *url); + StufferURLPromise **position(const char *url); + StufferURLPromise *lookup(const char *url) + { + return *position(url); + } + void add(char *url); + void remove(StufferURLPromise * e); + + ProxyMutexPtr mutex; + int size; + StufferURLPromise **array; +}; + +extern StufferHashTable *stuffer_htable; +class StufferCacheWriter; + +class Stuffer:public Continuation +{ + + enum + { + STUFFER_START, + URL_PROMISES, + URL_OBJECT, + CACHE_WRITE, + STUFFER_DONE + }; + +public: + + Stuffer() + : Continuation(), state(STUFFER_START), buf(0), source_vc(0), + cur_ntodo(0), cache_writer(0), active_cache_writers(0), active_cache_buffer(0) + { } + + ~Stuffer() { + mutex = NULL; + } + + int init(NetVConnection * netvc) + { + mutex = stuffer_htable->mutex; + source_vc = netvc; + SET_HANDLER(&Stuffer::mainEvent); + //this_ethread()->schedule_imm(this); + mainEvent(NET_EVENT_ACCEPT, NULL); + return EVENT_DONE; + } + + void free(); + void reset(); + + int mainEvent(int event, void *data); + int tunnel(int event, void *data); + + int processInitialData(); + + int state; + + MIOBuffer *buf; + IOBufferReader *reader; + NetVConnection *source_vc; + VIO *source_vio; + + int64_t cur_ntodo; + + StufferCacheWriter *cache_writer; + int active_cache_writers; + int active_cache_buffer; +}; + +#define MAX_CACHE_WRITERS_OUTSTANDING 10 +#define MAX_KEEPALIVE_BUFFER (200 * 1024) +#define STUFFER_CACHE_WRITER_ID 0xCAC11E0B + +class StufferCacheWriter:public Continuation +{ + + /* This class takes care of writing to the cache. This is done in + a seperate class so that we can parallelize writing to the + cache */ + enum + { + PARSE_HEADERS, + CACHE_READ_OPEN, + CACHE_WRITE_OPEN, + CACHE_WRITE, + + PARSE_START, + PARSE_REQ, + PARSE_RESP + }; + +public: + StufferCacheWriter() + : Continuation(), object_id(STUFFER_CACHE_WRITER_ID), nadded(0), + state(PARSE_HEADERS), parse_state(PARSE_START), got_read_complete(0), cache_vc(0), open_read_vc(0), url(0) + { + http_parser_init(&http_parser); + }; + + void init(Stuffer * s, int64_t ntodo); + void free(); + int addData(int max); + + int mainEvent(int event, void *data); + int parseHeaders(); + void initCacheLookupConfig(); + + unsigned int object_id; + MIOBuffer *buf; + IOBufferReader *reader; + int64_t ntodo; + int nadded; + + int state; + int parse_state; + int got_read_complete; + + Stuffer *stuffer; + + CacheVC *cache_vc; + VIO *cache_vio; + + CacheVC *open_read_vc; + + CacheHTTPInfo http_info; + HTTPParser http_parser; + + char *url; + + CacheLookupHttpConfig cache_lookup_config; +}; + +#define STUFFER_CACHE_WRITER(cont) \ +(((StufferCacheWriter *)(cont))->object_id == STUFFER_CACHE_WRITER_ID) + +extern ClassAllocator stufferAllocator; + +struct cache_obj_list +{ + cache_obj_list *next; + CacheVC *cache_vc; + + cache_obj_list():next(0), cache_vc(0) + { + } +}; + +class StufferURLPromise:public Continuation +{ + +public: + StufferURLPromise():Continuation(), url(0), next(0) + { + }; + ~StufferURLPromise() { + mutex = NULL; + }; + + int init(char *str) + { + mutex = stuffer_htable->mutex; + url = str; + SET_HANDLER(&StufferURLPromise::mainEvent); + overall_timeout = this_ethread()->schedule_in(this, ink_hrtime_from_msec(STUFFER_URL_PROMISE_TIMEOUT_MSECS)); + cache_block_timeout = 0; + return EVENT_DONE; + } + void free(bool object_pushed = false); + void add_waiter(CacheVC * cache_vc); + int mainEvent(int event, void *data); + + char *url; + + Action *overall_timeout; + Action *cache_block_timeout; + + /* We will rarely have more than one cache object waiting. + in that case we will just dynamically allocate these elements */ + cache_obj_list head; + + StufferURLPromise *next; //used for chaining in the hash table +}; + +extern ClassAllocator stufferURLPromiseAllocator; diff --git a/proxy/StufferUdpReceiver.cc b/proxy/StufferUdpReceiver.cc new file mode 100644 index 00000000..a9d64842 --- /dev/null +++ b/proxy/StufferUdpReceiver.cc @@ -0,0 +1,341 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + This is the standalone program to receive the UDP packet from the parent + and stream them to TS on local host + + Right now, if an out of order packet arrives, we just neglect it. +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define Debug(print) do { if (debug_on) printf print; } while (0) +int debug_on = 0; + +#define UDP_BUF_SIZE (64 * 1024) +#define TSPORT 39679 + +#define STREAM_TIMEOUT_SECS 6000 +typedef unsigned int uint32; + +/*taken from Prefetch.cc */ +struct prefetch_udp_header +{ + //uint32 response_flag:1, last_pkt:1, pkt_no:30; + uint32_t pkt; + uint32_t md5[4]; +}; + +#define RESPONSE_FLAG (1<<31) +#define LAST_PKT_FLAG (1<<30) +#define PKT_NUM_MASK ((1<<30)-1) + +#define PACKET_HDR_SIZE 20 + +/* statistics */ +static int number_of_packets_received = 0; +static int number_of_packets_dropped = 0; +static int number_of_connections_to_ts = 0; +static int number_of_timeouts = 0; + +/* TODO: this functions should be a signal handler ... */ +int +stufferUdpStatShow() +{ + printf("no of packets received\t:\t%d\n" + "no of packets dropped\t:\t%d\n" + "no of connections to TS\t:\t%d\n" + "no of timeouts\t\t:\t%d\n", + number_of_packets_received, number_of_packets_dropped, number_of_connections_to_ts, number_of_timeouts); + + return 0; +} + +struct Stream +{ + time_t last_activity_time; + prefetch_udp_header hdr; + int fd; //tcp connection + + Stream *next; +}; + +class StreamHashTable +{ + + Stream **array; + int size; +public: + + StreamHashTable(int sz) + { + size = sz; + array = new Stream *[size]; + memset(array, 0, size * sizeof(Stream *)); + } + ~StreamHashTable() + { + delete[]array; + } + + int index(prefetch_udp_header * hdr) + { + return hdr->md5[3] % size; + } + Stream **position(prefetch_udp_header * hdr); + Stream **position(Stream * s) + { + return position(&s->hdr); + } + Stream *lookup(prefetch_udp_header * hdr) + { + return *position(hdr); + } + void add(Stream * s); + void remove(Stream * s); + + int deleteStaleStreams(time_t now); +}; +StreamHashTable *stream_hash_table; + +Stream ** +StreamHashTable::position(prefetch_udp_header * hdr) +{ + Stream **e = &array[index(hdr)]; + + while (*e) { + prefetch_udp_header *h = &((*e)->hdr); + if (hdr->md5[0] == h->md5[0] && hdr->md5[1] == h->md5[1] && hdr->md5[2] == h->md5[2] && hdr->md5[3] == h->md5[3]) + return e; + e = &(*e)->next; + } + return e; +} + +void +StreamHashTable::add(Stream * s) +{ + Stream **e = position(s); + assert(!*e); + *e = s; +} + +void +StreamHashTable::remove(Stream * s) +{ + Stream **e = position(s); + assert(s == *e); + *e = s->next; +} + +int +StreamHashTable::deleteStaleStreams(time_t now) +{ + int nremoved = 0; + for (int i; i < size; i++) { + Stream *&e = array[i]; + while (e) { + if (e->last_activity_time < now - STREAM_TIMEOUT_SECS) { + close(e->fd); + number_of_timeouts++; + + Stream *temp = e; + e = e->next; + delete temp; + nremoved++; + } else + e = e->next; + } + } + return nremoved; +} + +int +openTSConn() +{ + int fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + //perror("socket()"); + return -1; + } + + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(TSPORT); +//#define INADDR_LOOPBACK ((209<<24)|(131<<16)|(52<<8)|48) + saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (connect(fd, (sockaddr *) & saddr, sizeof(saddr)) < 0) { + perror("connect(TS)"); + close(fd); + return -1; + } + + number_of_connections_to_ts++; + return fd; +} + +int +processPacket(const char *packet, int pkt_sz) +{ + prefetch_udp_header *hdr = (prefetch_udp_header *) packet; + uint32_t flags = ntohl(hdr->pkt); + + int close_socket = 1; + int sock_fd = -1; + + number_of_packets_received++; + + Debug(("Received packet. response_flag : %d last_pkt: %d pkt_no: %d" + " (%d)\n", (flags & RESPONSE_FLAG) ? 1 : 0, + (flags & RESPONSE_FLAG) && (flags & LAST_PKT_FLAG), + (flags & RESPONSE_FLAG) ? flags & PKT_NUM_MASK : 0, ntohl(hdr->pkt))); + + if (flags & RESPONSE_FLAG) { + Stream *s = stream_hash_table->lookup(hdr); + uint32_t pkt_no = flags & PKT_NUM_MASK; + + if (pkt_no == 0 && !(flags & LAST_PKT_FLAG)) { + if (s || !(s = new Stream)) { + number_of_packets_dropped++; + return -1; + } + s->hdr = *hdr; + s->hdr.pkt = pkt_no; + s->last_activity_time = time(NULL); + s->next = 0; + s->fd = openTSConn(); + if (s->fd < 0) { + delete s; + return -1; + } else + sock_fd = s->fd; + + close_socket = 0; + stream_hash_table->add(s); + + } else if (pkt_no > 0) { + if (!s) + return -1; + + s->last_activity_time = time(0); + sock_fd = s->fd; + + s->hdr.pkt++; + + if (s->hdr.pkt != pkt_no || flags & LAST_PKT_FLAG) { + stream_hash_table->remove(s); + delete s; + } else + close_socket = 0; + + if (s->hdr.pkt != pkt_no) { + Debug(("Received an out of order packet dropping the " + "connection expected %d but got %d\n", s->hdr.pkt, pkt_no)); + number_of_packets_dropped++; + pkt_sz = 0; // we dont want to send anything. + } + } + packet += PACKET_HDR_SIZE; + pkt_sz -= PACKET_HDR_SIZE; + } + + if (pkt_sz > 0) { + if (sock_fd < 0) { + sock_fd = openTSConn(); + if (sock_fd < 0) + return -1; + } + + Debug(("Writing %d bytes on socket %d\n", pkt_sz, sock_fd)); + while (pkt_sz > 0) { + int nsent = write(sock_fd, (char *) packet, pkt_sz); + if (nsent < 0) + break; + packet += nsent; + pkt_sz -= nsent; + } + } + + if (close_socket && sock_fd >= 0) + close(sock_fd); + + return 0; +} + +int +main(int argc, char *argv[]) +{ + int port = TSPORT; + + if (argc > 1) + debug_on = 1; + + stream_hash_table = new StreamHashTable(257); + + char *pkt_buf = (char *) malloc(UDP_BUF_SIZE); + + if (!pkt_buf) { + perror("malloc()"); + return 0; + } + + int fd = socket(PF_INET, SOCK_DGRAM, 0); + + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = INADDR_ANY; + + if ((bind(fd, (struct sockaddr *) &saddr, sizeof(saddr))) < 0) { + perror("bind(udp_fd)"); + free(pkt_buf); + return 0; + } + + time_t last_clean_up = time(0); + + while (1) { + int pkt_size = read(fd, pkt_buf, UDP_BUF_SIZE); + if (pkt_size < 0) + return 0; + + Debug(("Processing udp packet (size = %d)\n", pkt_size)); + processPacket(pkt_buf, pkt_size); + + time_t now = time(0); + if (now > last_clean_up + STREAM_TIMEOUT_SECS) + stream_hash_table->deleteStaleStreams(now); + } + + free(pkt_buf); +} diff --git a/proxy/TestClock.cc b/proxy/TestClock.cc new file mode 100644 index 00000000..f7b953d9 --- /dev/null +++ b/proxy/TestClock.cc @@ -0,0 +1,47 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "ink_hrtime.h" +#include + +void +test() +{ + ink_hrtime t = ink_get_hrtime(); + int i = 1000000; + timespec ts; + while (i--) { + clock_gettime(CLOCK_REALTIME, &ts); + } + ink_hrtime t2 = ink_get_hrtime(); + printf("time for clock_gettime %" PRId64 " nsecs\n", (t2 - t) / 1000); + + t = ink_get_hrtime(); + i = 1000000; + while (i--) { + ink_get_hrtime(); + } + t2 = ink_get_hrtime(); + printf("time for clock_gettime %" PRId64 " nsecs\n", (t2 - t) / 1000); +} diff --git a/proxy/TestClusterHash.cc b/proxy/TestClusterHash.cc new file mode 100644 index 00000000..e1da885a --- /dev/null +++ b/proxy/TestClusterHash.cc @@ -0,0 +1,122 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/**************************************************************************** + + TestClusterHash.cc + ****************************************************************************/ + +#include "Cluster.h" +#include "libts.h" + + +// +// This test function produces the table included +// in Memo.ClusterHash +// + +void +test() +{ + int n[CLUSTER_MAX_MACHINES]; + int i; + Machine *m; + int j; + ink_hrtime t, t2; + int total; + int high, low, share; + int version = 7; + + while (version > -1) { + + // the select the version + // + machineClusterHash = !!(version & 1); + boundClusterHash = !!(version & 2); + randClusterHash = !!(version & 4); + + // fabricate fake cluster + + clusterProcessor.this_cluster = new Cluster; + ClusterConfiguration *cc = new ClusterConfiguration; + cc->n_machines = 1; + cc->machines[0] = this_cluster_machine(); + memset(cc->hash_table, 0, CLUSTER_HASH_TABLE_SIZE); + clusterProcessor.this_cluster->configurations.push(cc); + + ClusterConfiguration *c = this_cluster()->current_configuration(); + + printf("hash by %s - %s - %s\n", + (machineClusterHash ? "MACHINE" : "BUCKET"), + (boundClusterHash ? "BOUNDED" : "UNBOUND"), (randClusterHash ? "RAND" : "LINEAR CONGUENCE")); + + // from 1 to 32 machines + + for (i = 1; i < 32; i++) { + m = new ClusterMachine(*this_cluster_machine()); + m->ip += i; + t = ink_get_hrtime(); + cc = configuration_add_machine(c, m); + t2 = ink_get_hrtime(); + + // + // Compute new distribution + // + high = 0; + low = CLUSTER_HASH_TABLE_SIZE + 1; + for (j = 0; j < cc->n_machines; j++) + n[j] = 0; + for (j = 0; j < CLUSTER_HASH_TABLE_SIZE; j++) { + ink_assert(cc->hash_table[j] < cc->n_machines); + n[cc->hash_table[j]]++; + } + total = CLUSTER_HASH_TABLE_SIZE; + for (j = 0; j < cc->n_machines; j++) { + total -= n[j]; + if (low > n[j]) + low = n[j]; + if (high < n[j]) + high = n[j]; + } + ink_assert(!total); + printf("n = %d:", i); + printf(" high = %d low = %d high/low = %f", high, low, (float) high / (float) low); + + // + // Compute sharing with n-1 + // + share = 0; + for (j = 0; j < CLUSTER_HASH_TABLE_SIZE; j++) { + if (c->machines[c->hash_table[j]] == cc->machines[cc->hash_table[j]]) + share++; + } + printf(" shared = %d %%%6.2f", share, (float) share / (float) CLUSTER_HASH_TABLE_SIZE); + + printf(" time = %f secs\n", ((float) (t2 - t) / (float) HRTIME_SECONDS(1))); + c = cc; + } + + version--; + } +} diff --git a/proxy/TestDNS.cc b/proxy/TestDNS.cc new file mode 100644 index 00000000..b4871bbd --- /dev/null +++ b/proxy/TestDNS.cc @@ -0,0 +1,259 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/**************************************************************************** + + TestDns.cc + + Test module to test the DNS processor + + The main state machine is encapulated in the StateMachine instance. + + + ****************************************************************************/ + +#include "DNS.h" +#include +#include +#include +#include "VConnection.h" +#include "stdio.h" +#include "libts.h" +#define N_STATE_MACHINES 1000 +#define MEASUREMENT_INTERVAL 100 +class TestDnsStateMachine; + +////////////////////////////////////////////////////////////////////////////// +// +// Globals +// +////////////////////////////////////////////////////////////////////////////// + +unsigned g_host_ip = 0; +char *in_file_name = "test_dns.in"; +char *out_file_name = "test_dns.out"; +char *rate_file_name = "rates.out"; +char *rate_misc_file_name = "rates.misc.out"; +ofstream fout; +ofstream fout_rate, fout_rate_misc; +FILE *fin; + + +////////////////////////////////////////////////////////////////////////////// +// +// TestDnsStateMachine +// +// An instance of TestDnsStateMachine is created for each host +// +////////////////////////////////////////////////////////////////////////////// +class TestDnsStateMachine:public Continuation +{ +public: + TestDnsStateMachine(char *ahost); + ~TestDnsStateMachine() + { +// cout << "StateMachine::~StateMachine(). Terminating ... " << endl; + return; + } + + const char *currentStateName(); + + int processEvent(int event, void *data); + + enum + { START, DNS_LOOKUP }; + + int m_state; + char host[100]; +}; + +TestDnsStateMachine::TestDnsStateMachine(char *ahost) + : +Continuation(new_ProxyMutex()) +{ + strcpy(host, ahost); + m_state = START; + SET_HANDLER(processEvent); + return; +} + + +inline const char * +TestDnsStateMachine::currentStateName() +{ + switch (m_state) { + case START: + return ("START"); + case DNS_LOOKUP: + return ("DNS_LOOKUP"); + default: + return ("unknown state"); + } +} + +////////////////////////////////////////////////////////////////////////////// +// +// TestDnsStateMachine::processEvent() +// +// This routine is the main callback entry point of the TestTunnel +// state machine. +// +////////////////////////////////////////////////////////////////////////////// + +int +TestDnsStateMachine::processEvent(int event, void *data) +{ + int rvalue = VC_EVENT_DONE; + void complete(); + +// printf("<<< state machine processEvent() called in state '%s' >>>\n",currentStateName()); + + switch (m_state) { + case START: + { +// cout << " started up TestDnsStateMachine" << endl; +// cout << " dns lookup for <" << host << ">" << endl; + + // + // asynchronously do DNS, calling back when done + // + + m_state = DNS_LOOKUP; + dnsProcessor.gethostbyname(this, host); + break; + } + case DNS_LOOKUP: + { + ink_assert(event == DNS_EVENT_LOOKUP); + if (!host) + ink_assert(!"Error - host has no value\n"); + if (data) { + HostEnt *ent = (HostEnt *) data; + g_host_ip = ((struct in_addr *) ent->h_addr_list[0])->s_addr; +// cout << " dns lookup is done <" << g_host_ip << ">" << endl; +// cout << "<" << host << "> <" << g_host_ip << ">\n"; + fout << "<" << host << "> <" << g_host_ip << ">\n"; +// cout << " finishing up" << endl; +// printf("*** NOTE: We Need To Somehow Free 'this' Here! How?\n"); + } else { + fout << "<" << host << "> <>\n"; + } + fout.flush(); + rvalue = VC_EVENT_DONE; + m_state = 99; // Some Undefined state value + complete(); + delete this; + break; + } + default: + { + ink_assert(!"unexpected m_state"); + break; + } + } + return (rvalue); +} + +int state_machines_created, state_machines_finished, measurement_interval; +ink_hrtime start_time, last_measurement_time; +// Following function is called to measure the throughput +void +complete() +{ + float throughput, cumul_throughput; + ink_hrtime now; + state_machines_finished++; + if (!(state_machines_finished % measurement_interval)) { + now = ink_get_hrtime(); + cumul_throughput = state_machines_finished * 1.0 * HRTIME_SECOND / (now - start_time); + throughput = measurement_interval * 1.0 * HRTIME_SECOND / (now - last_measurement_time); + last_measurement_time = now; +// cout << state_machines_finished << ": " << +// "Cumul. Thrput " << cumul_throughput << +// " per sec; Thrput for last " << measurement_interval << " requests: " +// << throughput << " per sec\n"; +// cout.flush(); +// fout_rate << state_machines_finished << ": " << +// "Cumul. Thrput " << cumul_throughput << +// " per sec; Thrput for last " << measurement_interval << " requests: " +// << throughput << " per sec\n"; + fout_rate << (now - start_time) * 1.0 / HRTIME_SECOND << " " << state_machines_finished << " " << cumul_throughput + << " " << throughput << "\n"; + fout_rate.flush(); + } + if (state_machines_finished == state_machines_created) { + now = ink_get_hrtime(); + fout_rate_misc << (now - start_time) * 1.0 / HRTIME_SECOND << "\n"; + fout_rate_misc.flush(); + fout.close(); + fout_rate.close(); + fout_rate_misc.close(); + cout << "Dns Testing Complete\n"; + exit(0); + } +// printf("%d Hosts left \n",state_machines_unfinished); +} + +////////////////////////////////////////////////////////////////////////////// +// +// test +// +// Main entry point for DNS tests +// +////////////////////////////////////////////////////////////////////////////// + +void +test() +{ + char host[100]; + ink_hrtime now; + int i; + TestDnsStateMachine *test_dns_state_machine; + printf("removing file '%s'\n", out_file_name); + unlink(out_file_name); + printf("removing file '%s'\n", rate_file_name); + unlink(rate_file_name); + printf("removing file '%s'\n", rate_misc_file_name); + unlink(rate_misc_file_name); + fin = fopen(in_file_name, "r"); // STDIO OK + fout.open(out_file_name); + fout_rate.open(rate_file_name); + fout_rate_misc.open(rate_misc_file_name); + i = 0; + state_machines_created = N_STATE_MACHINES; + state_machines_finished = 0; + measurement_interval = MEASUREMENT_INTERVAL; + start_time = ink_get_hrtime(); + last_measurement_time = ink_get_hrtime(); + while ((fscanf(fin, "%s", host) != EOF) && (i < state_machines_created)) { + test_dns_state_machine = new TestDnsStateMachine(host); + test_dns_state_machine->handleEvent(); + i++; + } + now = ink_get_hrtime(); + cout << "Finished creating all Continuations at " << + (now - start_time) / HRTIME_SECOND << " sec and " << (now - start_time) % HRTIME_SECOND << "nanosec\n"; + fout_rate_misc << (now - start_time) * 1.0 / HRTIME_SECOND << "\n"; + fout_rate_misc.flush(); +} diff --git a/proxy/TestHook.cc b/proxy/TestHook.cc new file mode 100644 index 00000000..13803793 --- /dev/null +++ b/proxy/TestHook.cc @@ -0,0 +1,504 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/**************************************************************************** + + TestHook.cc + ****************************************************************************/ + +#include "ink_config.h" +#include "ink_unused.h" +#include +#include "P_Net.h" +#include "ParseRules.h" +#include "EventName.h" + +volatile int state_machine_count = 0; + +struct Globals +{ + int accept_port; + int accept_count; + int accept_spawn; + int buffer_size; + int default_body_size; + + void get_env_int(int *var, const char *env) + { + char *s = getenv(env); + if (s) + *var = atoi(s); + } + + Globals() + { + accept_port = 38080; + accept_count = 1; + accept_spawn = true; + buffer_size = default_large_iobuffer_size; + default_body_size = 6000; + + get_env_int(&accept_port, "BRIOCORE_SERVER_ACCEPT_PORT"); + get_env_int(&accept_count, "BRIOCORE_SERVER_ACCEPT_COUNT"); + get_env_int(&accept_spawn, "BRIOCORE_SERVER_ACCEPT_SPAWN"); + get_env_int(&buffer_size, "BRIOCORE_SERVER_BUFFER_SIZE"); + get_env_int(&default_body_size, "BRIOCORE_SERVER_DEFAULT_BODY_SIZE"); + } +} + +G; + +class StateMachine; +class AcceptContinuation; + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine +// +// This continuation keeps track of the state of an HTTP +// request and response, and lives for life of the transaction. +// +//////////////////////////////////////////////////////////////////////// + +class StateMachine:public Continuation +{ +private: + char scratch_space[512]; + char url[512], *url_end, hdr[1024], *hdr_end; + int header_size, url_size, body_size, total_size; + int header_size_written, body_size_written; + int parse_mode; + +public: + VIO * ivio, *ovio; + VConnection *nvc; + MIOBuffer *ibuf, *obuf; + IOBufferReader *reader; + + int parse(); + int fill(); + int responseDataEvent(int event, void *data); + void startResponse(); + void killStateMachine(); + int computeBodySize(char *url); + int requestDataEvent(int event, void *data); + + StateMachine(NetVConnection * vc):Continuation(new_ProxyMutex()), + header_size(0), url_size(0), body_size(0), total_size(0), header_size_written(0), body_size_written(0) + { + ink_atomic_increment((int *) &state_machine_count, 1); + scratch_space[0] = url[0] = hdr[0] = 0; + bzero(history, sizeof(history)); + nvc = vc; + ivio = ovio = 0; + ibuf = new_MIOBuffer(G.buffer_size); + obuf = new_MIOBuffer(G.buffer_size); + reader = ibuf->alloc_reader(); + parse_mode = 0; + history_pos = 0; + history_start_time = ink_get_based_hrtime(); + SET_HANDLER(&StateMachine::requestDataEvent); + } + + ~StateMachine() + { + ink_atomic_increment((int *) &state_machine_count, -1); + ibuf->dealloc_all_readers(); + free_MIOBuffer(ibuf); + free_MIOBuffer(obuf); + } + + enum + { HISTORY_SIZE = 128 }; + struct HistoryItem + { + ink_hrtime time; + int line; + int event; + int ndone; + }; + HistoryItem history[HISTORY_SIZE]; + int history_pos; + ink_hrtime history_start_time; +}; + +#define REMEMBER(_e, _ndone) { \ +history[history_pos%HISTORY_SIZE].time = ((ink_get_based_hrtime()-history_start_time) / HRTIME_MSECOND); \ +history[history_pos%HISTORY_SIZE].line = __LINE__; \ +history[history_pos%HISTORY_SIZE].event = _e; \ +history[history_pos%HISTORY_SIZE].ndone = _ndone; \ +history_pos++; } +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::requestDataEvent +// +// Called back whenever there is request data available. +// Incrementally parses out the request URL and headers, +// then switches to a response mode to generate the output. +// +//////////////////////////////////////////////////////////////////////// + +int +StateMachine::requestDataEvent(int event, void *data) +{ + int done; + + REMEMBER(event, (data) ? ((VIO *) data)->ndone : -1); + + switch (event) { + case VC_EVENT_READ_READY: + case VC_EVENT_EOS: + if (ivio == 0) { + ivio = (VIO *) data; + } + done = parse(); + if (done || (event == VC_EVENT_EOS)) + startResponse(); + break; + case VC_EVENT_ERROR: + killStateMachine(); + break; + default: + printf("requestDataEvent got unexpected %s\n", event_int_to_string(event)); + break; + } + return (0); +} + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::parse +// +// Called on a chunk of bytes representing a piece of a request +// headers, stripping out the URL, headers, etc. The state of +// the parse is kept in the variable which represents +// the current parsing step. +// +//////////////////////////////////////////////////////////////////////// + +int +StateMachine::parse() +{ + char *ptr; + int n, orig_n; + + ptr = reader->start(); + n = reader->block_read_avail(); + orig_n = n; + + while (n) { +// printf("PARSE MODE %d: [",parse_mode); +// fwrite(ptr,1,n,stdout); +// printf("]\n"); + + if (parse_mode == 0) // skipping over method + { + while (*ptr != ' ' && n) { + ++ptr; + --n; + } + if (n == 0) + break; + parse_mode = 1; + } else if (parse_mode == 1) // looking for URL start + { + while (*ptr == ' ' && n) { + ++ptr; + --n; + } + if (n == 0) + break; + parse_mode = 2; + url_end = url; + } else if (parse_mode == 2) // looking for URL end + { + while (*ptr != ' ' && n) { + *url_end++ = *ptr++; + --n; + } + if (n == 0) + break; + *url_end = '\0'; +// printf("URL = '%s'\n",url); + parse_mode = 3; + } else if (parse_mode == 3) // looking for end of start line + { + while (*ptr != '\n' && n) { + ++ptr; + --n; + } + if (n == 0) + break; + ++ptr; + --n; + parse_mode = 4; + hdr_end = hdr; + } else if (parse_mode == 4) // read header until EOL + { + if (*ptr == '\r') { + ++ptr; + --n; + parse_mode = 5; + break; + } + while (*ptr != '\n' && n) { + *hdr_end++ = *ptr++; + --n; + } + if (n == 0) + break; + ++ptr; + --n; + if (*(hdr_end - 1) == '\r') + --hdr_end; + } else if (parse_mode == 5) // got empty line CR + { + ++ptr; + --n; // consume LF + } + } + + reader->consume(orig_n - n); + return (parse_mode == 5); +} + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::responseDataEvent +// +// Called back whenever there is an event and we are generating +// response data. The event can come from the read or write side. +// +//////////////////////////////////////////////////////////////////////// + +int +StateMachine::responseDataEvent(int event, void *data) +{ + int n; + + REMEMBER(event, (data) ? ((VIO *) data)->ndone : -1); + +// printf("responseDataEvent got %s\n",event_int_to_string(event)); + switch (event) { + case VC_EVENT_WRITE_READY: + fill(); + break; + case VC_EVENT_WRITE_COMPLETE: + killStateMachine(); + break; + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + n = reader->read_avail(); + reader->consume(n); + break; + case VC_EVENT_ERROR: + killStateMachine(); + break; + default: + printf("responseDataEvent got unexpected %s\n", event_int_to_string(event)); + break; + } + return (0); +} + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::fill +// +// This is the synthetic server routine that writes a header, +// and a synthetically-generated body. +// +//////////////////////////////////////////////////////////////////////// + +int +StateMachine::fill() +{ + char *ptr; + int n; + int hdr_bytes_left, body_bytes_left, copy_size; + + // TODO: I don't know if this call to obuf->write_avail() is necessary... + n = obuf->write_avail(); // used to grow blocks + n = obuf->block_write_avail(); + ptr = obuf->end(); + + hdr_bytes_left = header_size - header_size_written; + body_bytes_left = body_size - body_size_written; + + // write header + if (hdr_bytes_left) { + copy_size = min(n, hdr_bytes_left); + bcopy(scratch_space + header_size_written, ptr, copy_size); + ptr += copy_size; + header_size_written += copy_size; + hdr_bytes_left -= copy_size; + n -= copy_size; + obuf->fill(copy_size); + } + // write body + if ((hdr_bytes_left == 0) && body_bytes_left) { + copy_size = min(n, body_bytes_left); + memset(ptr, 'B', copy_size); + ptr += copy_size; + body_size_written += copy_size; + body_bytes_left -= copy_size; + n -= copy_size; + obuf->fill(copy_size); + } + + return ((hdr_bytes_left == 0) && (body_bytes_left == 0)); +} + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::startResponse +// +// Called when the request is parsed, to set up the state +// machine to generate response data. +// +//////////////////////////////////////////////////////////////////////// + +void +StateMachine::startResponse() +{ + ivio->done(); // ignore future input data + + SET_HANDLER(&StateMachine::responseDataEvent); + url_size = strlen(url); + body_size = computeBodySize(url); + snprintf(scratch_space, sizeof(scratch_space), "HTTP/1.0 200 OK\r\nContent-length: %d\r\n\r\n", body_size); + header_size = strlen(scratch_space); + + total_size = header_size + body_size; + header_size_written = 0; + body_size_written = 0; + fill(); + ovio = nvc->do_io(VIO::WRITE, this, total_size, obuf); +} + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::killStateMachine +// +// Called when the response is generated, to clean up and +// destroy the state machine. +// +//////////////////////////////////////////////////////////////////////// + +void +StateMachine::killStateMachine() +{ + nvc->do_io(VIO::CLOSE); // do I need to cancel vios first? +// printf("*** State Machine Dying **\n"); + delete this; +} + + +//////////////////////////////////////////////////////////////////////// +// +// StateMachine::computeBodySize +// +// Chooses a body size to send based on the URL. +// +//////////////////////////////////////////////////////////////////////// + +int +StateMachine::computeBodySize(char *url_str) +{ + int l; + char *p; + + for (p = url_str + strlen(url_str); (*p != '/' && p > url_str); p--); +#ifdef SENDER_IS_JTEST + // coverity[secure_coding] + if ((*p == '/') && (sscanf(p, "/%d", &l) == 1)) { + return (l); + } else + printf("Unable to get doc body size [%s]\n", url_str); +#else + // coverity[secure_coding] + if ((*p == '/') && (sscanf(p, "/length%d.html", &l) == 1)) + return (l); + else + return (G.default_body_size); +#endif +} + + +//////////////////////////////////////////////////////////////////////// +// +// AcceptContinuation +// +// This is the continuation that is notified of connection +// accepts. It spawns a state machine to handle the transaction. +// New transactions can be accepted and spawned while other +// transactions are still in progress. +// +//////////////////////////////////////////////////////////////////////// + +class AcceptContinuation:public Continuation +{ +public: + int startEvent(int event, NetVConnection * nvc) + { + if (event == NET_EVENT_ACCEPT) { +// printf("*** Got Request, %d Transactions Currently Open ***\n", +// state_machine_count); + StateMachine *sm = new StateMachine(nvc); + sm->ivio = nvc->do_io(VIO::READ, sm, INT64_MAX, sm->ibuf); + } else + { + printf("AcceptContinuation error %d\n", event); + } + return (0); + } + +AcceptContinuation():Continuation(NULL) + // Allow multi-thread callers + { + SET_HANDLER(&AcceptContinuation::startEvent); + } +}; + + +//////////////////////////////////////////////////////////////////////// +// +// Main Entry Point +// +// This is the main entry point to start the accepting server. +// +//////////////////////////////////////////////////////////////////////// + +int +run_TestHook() +{ + int i; + Continuation *c; + + printf("*** BRIOCORE Server Running ***\n"); + for (i = 1; i <= G.accept_count; i++) { + c = new AcceptContinuation(); + (void) netProcessor.accept(c, G.accept_port, G.accept_spawn); + } + return (0); +} diff --git a/proxy/TestPreProc.cc b/proxy/TestPreProc.cc new file mode 100644 index 00000000..b2d96e70 --- /dev/null +++ b/proxy/TestPreProc.cc @@ -0,0 +1,190 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "TestPreProc.h" +#include "IOBufferPool.h" +#include "IOBuffer.h" +#include "HttpPreProc.h" +#include "HttpMessage.h" +#include "HttpPreProcMessageManager.h" +#include "RawHashTable.h" +#include "ink_time.h" /* ink_time_wall_seconds() */ +#include +#include + +/* local functions prototypes */ +void dumpMessage(const HttpMessage & msg); +void testPreProc(); + +/* some global requests */ +char *request1 = "GET http://trafficserver.apache.org HTTP/1.1\r\n\ +Accept: text/*, text/html, text/html; level=1\r\n\ +Accept-Charset: iso-8859-5, unicode-1-1;q=0.8\r\n\r\n"; +char *response1 = "HTTP/1.1 200\r\n\r\n"; +////////////////////////////////////////////////////////////////////////////// +// RequestInput(). +////////////////////////////////////////////////////////////////////////////// +RequestInput::RequestInput(const char *str, IOBuffer * cb) + : +m_sp(0), +m_len(0), +m_cb(cb) +{ + m_len = strlen(str); + m_sp = request1; + + return; +} + +////////////////////////////////////////////////////////////////////////////// +// ~RequestInput() +////////////////////////////////////////////////////////////////////////////// +RequestInput::~RequestInput() +{ + return; +} + +////////////////////////////////////////////////////////////////////////////// +// run() +////////////////////////////////////////////////////////////////////////////// +void +RequestInput::run() +{ + unsigned maxBytes = 0; + + char *buff = m_cb->getWrite(&maxBytes); + unsigned writeBytes = (m_len < maxBytes) ? m_len : maxBytes; + + + strncpy(buff, m_sp, writeBytes); + m_cb->wrote(writeBytes); + + m_len -= writeBytes; + m_sp += writeBytes; + + return; +} + +////////////////////////////////////////////////////////////////////////////// +// dumpMessage() +////////////////////////////////////////////////////////////////////////////// +void +dumpMessage(const HttpMessage & msg) +{ + if (msg.isResponse()) { + cout << "Http response" << endl; + } + if (msg.isRequest()) { + cout << "Http request" << endl; + } + + cout << "Major version: " << msg.getMajorVersion() << endl; + cout << "Minor version: " << msg.getMinorVersion() << endl; + cout << "Method : "; + switch (msg.getMethod()) { + case HttpMessage::METHOD_NONE: + cout << "NONE" << endl; + case HttpMessage::METHOD_OPTIONS: + cout << "OPTIONS" << endl; + break; + case HttpMessage::METHOD_GET: + cout << "GET" << endl; + break; + case HttpMessage::METHOD_HEAD: + cout << "HEAD" << endl; + break; + case HttpMessage::METHOD_POST: + cout << "POST" << endl; + break; + case HttpMessage::METHOD_PUT: + cout << "PUT" << endl; + break; + case HttpMessage::METHOD_DELETE: + cout << "DELETE" << endl; + break; + case HttpMessage::METHOD_TRACE: + cout << "TRACE" << endl; + break; + } + + cout << "Scheme : "; + switch (msg.getScheme()) { + case HttpMessage::SCHEME_NONE: + cout << "NONE" << endl; + break; + case HttpMessage::SCHEME_HTTP: + cout << "HTTP" << endl; + break; + } + cout << "Status code: " << msg.getStatusCode() << endl; + cout << "Request URI: " << msg.getRequestURI() << endl; + + return; +} + +////////////////////////////////////////////////////////////////////////////// +// testPreProc() +////////////////////////////////////////////////////////////////////////////// +double +testPreProc(unsigned loopCount) +{ + IOBufferPool pool(96 /* bufferSize */ , 20 /* bufferCount */ ); + IOBuffer *cb = pool.newBuffer(); + + HttpPreProcMessageManager msgMgr; + + HttpPreProc pp(cb, &msgMgr); + + /* start counting time here */ + double startTime = ink_time_wall_seconds(); + + for (unsigned i = 0; i < loopCount; i++) { + + RequestInput requestInput(request1, cb); + + while (!requestInput.isDone()) { + requestInput.run(); + pp.process(); + } + } + + double endTime = ink_time_wall_seconds(); + + return (endTime - startTime); +} + +////////////////////////////////////////////////////////////////////////////// +// main(). +////////////////////////////////////////////////////////////////////////////// +main() +{ + for (unsigned lc = 1; lc < 10000; lc *= 10) { + double elapsedTime = testPreProc(lc); + cout << "Elapsed time for " << lc << "loops is " << elapsedTime << endl; + } + + + + return (0); +} diff --git a/proxy/TestPreProc.h b/proxy/TestPreProc.h new file mode 100644 index 00000000..fc39ca18 --- /dev/null +++ b/proxy/TestPreProc.h @@ -0,0 +1,51 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#if !defined (_TestPreProc_h_) +#define _TestPreProc_h_ + +class IOBuffer; + +class RequestInput +{ +public: + RequestInput(const char *str, IOBuffer * cb); + ~RequestInput(); + + void run(); + bool isDone() const + { + return (m_len == 0); + } + +private: + RequestInput(const RequestInput &); + RequestInput & operator =(const RequestInput &); + + + char *m_sp; + unsigned m_len; + IOBuffer *m_cb; +}; + +#endif diff --git a/proxy/TestProxy.cc b/proxy/TestProxy.cc new file mode 100644 index 00000000..c18595e2 --- /dev/null +++ b/proxy/TestProxy.cc @@ -0,0 +1,432 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +/**************************************************************************** + + TestProxy.cc + ****************************************************************************/ + +#include +#include "Net.h" +#include "Disk.h" +#include "Main.h" +#include "HostDB.h" +#include "Cluster.h" +#include "OneWayTunnel.h" +#include "OneWayMultiTunnel.h" +#include "Cache.h" + + +struct TestProxy:Continuation +{ + VConnection *vc; + VConnection *vconnection_vector[2]; + VConnection *remote; + MIOBuffer *inbuf; + MIOBuffer *outbuf; + VIO *clusterOutVIO; + VIO *inVIO; + char host[1024], *url, *url_end, amode; + int port; + char s[1024]; + ClusterVCToken token; + OneWayTunnel *tunnel; + char url_str[1024]; + VConnection *cachefile; + URL *url_struct; + HostDBInfo *hostdbinfo; + CacheObjInfo *objinfo; + HttpHeader *request_header; + + int done() + { + ink_assert(inbuf); + if (inbuf) + free_MIOBuffer(inbuf); + inbuf = 0; + if (outbuf) + free_MIOBuffer(outbuf); + if (vc) + vc->do_io(VIO::CLOSE); + if (remote) + remote->do_io(VIO::CLOSE); + if (cachefile) + cachefile->do_io(VIO::CLOSE); + if (tunnel) + delete tunnel; + delete this; + return EVENT_DONE; + } + + int gets(VIO * vio) + { + char *sx = s, *x; + int t, i; + for (x = vio->buffer.mbuf->start; *x && x < vio->buffer.mbuf->end; x++) { + if (x - vio->buffer.mbuf->start > 1023) + return -1; + if (*x == '\n') + break; + *sx++ = *x; + } + + t = 2; + for (i = 0; t && s[i]; i++) { + if (s[i] == ' ') + --t; + } + +// i = strrchr(s,' '); + + if (s[i - 2] == 'X') { + i -= 2; + amode = 'x'; + while (s[i] != '\0') { + s[i] = s[i + 1]; + ++i; + } + return x - vio->buffer.mbuf->start - 1; + } + return x - vio->buffer.mbuf->start; + } + + int startEvent(int event, VIO * vio) + { + char *temp; + if (event != VC_EVENT_READ_READY) { + printf("TestProxy startEvent error %d %X\n", event, (unsigned int) vio->vc_server); + return done(); + } + inVIO = vio; + vc = (NetVConnection *) vio->vc_server; + int res = 0; + char *thost = NULL; + if ((res = gets(vio))) { + if (res < 0) { + printf("TestProxy startEvent line too long\n"); + return done(); + } + //for (int i = 0; i <= res; i++) fprintf(stderr,"[%c (%d)]\n",s[i],s[i]); + s[res] = 0; + if ((res > 0) && (s[res - 1] == '\r')) + s[res - 1] = 0; + // printf("got [%s]\n",s); + if (s[4] == '/') { + url = s + 5; + url_end = strchr(url, ' '); + *url_end = 0; + SET_HANDLER(fileEvent); + diskProcessor.open_vc(this, url, O_RDONLY); + return EVENT_DONE; + } + else + thost = s + 11; // GET http + url = strchr(thost, '/'); // done before portStr stompage */ + temp = strchr(thost, ' '); + ink_assert(temp - thost < 1024); + strncpy(url_str, thost, temp - thost); + url_str[temp - thost] = '\0'; + if (!url) + return done(); + char *portStr = strchr(thost, ':'); + *url = 0; + if (portStr == NULL) { + port = 80; + strcpy(host, thost); + } else { + *portStr = '\0'; /* close off the hostname */ + port = atoi(portStr + 1); + strcpy(host, thost); + *portStr = ':'; + } + url_end = strchr(url + 1, ' '); + SET_HANDLER(dnsEvent); + *url = '/'; + hostDBProcessor.getbyname(this, host); + return EVENT_DONE; + } + return EVENT_CONT; + } + + int clusterOpenEvent(int event, void *data) + { + if (event == CLUSTER_EVENT_OPEN_FAILED) + return done(); + if (event == CLUSTER_EVENT_OPEN) { + if (!data) + return done(); + remote = (VConnection *) data; + clusterOutVIO = remote->do_io(VIO::WRITE, this, INT64_MAX, inbuf); + ink_assert(clusterOutVIO); + SET_HANDLER(tunnelEvent); + tunnel = new OneWayTunnel(remote, vc, this, TUNNEL_TILL_DONE, true, true, true); + } + return EVENT_CONT; + } + + int clusterEvent(int event, VConnection * data) + { + (void) event; + vc = data; + if (!vc) + return done(); + SET_HANDLER(startEvent); + vc->do_io(VIO::READ, this, INT64_MAX, inbuf); + return EVENT_CONT; + } + + int fileEvent(int event, DiskVConnection * aremote) + { + if (event != DISK_EVENT_OPEN) { + printf("TestProxy fileEvent error %d\n", event); + return done(); + } + remote = aremote; + SET_HANDLER(tunnelEvent); + tunnel = new OneWayTunnel(remote, vc, this, TUNNEL_TILL_DONE, true, true, true); + return EVENT_CONT; + } + + int dnsEvent(int event, HostDBInfo * info) + { + if (!info) { + printf("TestProxy dnsEvent error %d\n", event); + return done(); + } + SET_HANDLER(cacheCheckEvent); + url_struct = new URL((const char *) url_str, sizeof(url_str), true); + hostdbinfo = info; + cacheProcessor.lookup(this, url_struct); + // SET_HANDLER(connectEvent); + // netProcessor.connect(this,info->ip,port,host); + return EVENT_DONE; + } + + int cacheCheckEvent(int event, void *data) + { + if (event == CACHE_EVENT_LOOKUP) { + if (amode == 'x') { + cout << "Removing object from the cache\n"; + SET_HANDLER(NULL); + amode = 0; + cacheProcessor.remove(&(((CacheObjInfoVector *) data)->data[0])); + return done(); + } else { + cout << "Serving the object from cache\n"; + SET_HANDLER(cacheReadEvent); + cacheProcessor.open_read(this, &(((CacheObjInfoVector *) data)->data[0])); + return EVENT_CONT; + } + } else if (event == CACHE_EVENT_LOOKUP_FAILED) { + cout << "Getting the object from origin server\n"; + SET_HANDLER(cacheCreateCacheFileEvent); + objinfo = new CacheObjInfo; + request_header = new HttpHeader; + request_header->m_url = *url_struct; + objinfo->request = *request_header; + cacheProcessor.open_write(this, objinfo, CACHE_UNKNOWN_SIZE); + return EVENT_DONE; + } else { + printf("TestProxy cacheCheckEvent error %d\n", event); + return done(); + } + } + + int cacheReadEvent(int event, DiskVConnection * aremote) + { + if (event != CACHE_EVENT_OPEN_READ) { + printf("TestProxy cacheReadEvent error %d\n", event); + return done(); + } + remote = aremote; + SET_HANDLER(tunnelEvent); + new OneWayTunnel(remote, vc, this, TUNNEL_TILL_DONE, true, true, true); + return EVENT_CONT; + } + int cacheCreateCacheFileEvent(int event, VConnection * acachefile) + { + if (event != CACHE_EVENT_OPEN_WRITE) { + printf("TestProxy cacheCreateCacheFileEvent error %d\n", event); + cachefile = 0; + } else + cachefile = acachefile; + SET_HANDLER(cacheSendGetEvent); + netProcessor.connect(this, hostdbinfo->ip, port, host); + return EVENT_CONT; + } + int cacheSendGetEvent(int event, NetVConnection * aremote) + { + if (event != NET_EVENT_OPEN) { + printf("TestProxy cacheSendGetEvent error %d\n", event); + return done(); + } + remote = aremote; + outbuf = new_MIOBuffer(); + SET_HANDLER(cacheTransRemoteToCacheFileEvent); + //aremote->set_inactivity_timeout(HRTIME_MSECONDS(2000)); + //aremote->set_active_timeout(HRTIME_MSECONDS(60000)); + *url_end = 0; + sprintf(outbuf->start, "GET %s HTTP/1.0\nHost: %s\n\n", url, host); + outbuf->fill(strlen(outbuf->start) + 1); + remote->do_io(VIO::WRITE, this, INT64_MAX, outbuf); + // printf("sending [%s]\n",outbuf->start); + return EVENT_CONT; + } + int cacheTransRemoteToCacheFileEvent(int event, VIO * vio) + { + if (event != VC_EVENT_WRITE_READY) { + printf("TestProxy cacheTransRemoteToCacheFileEvent error %d\n", event); + return done(); + } + if (vio->buffer.size()) + return EVENT_CONT; + SET_HANDLER(tunnelEvent); + vconnection_vector[0] = vc; + vconnection_vector[1] = cachefile; + { + int n = cachefile ? 2 : 1; + cachefile = 0; + new OneWayMultiTunnel(remote, vconnection_vector, n, this, TUNNEL_TILL_DONE, true, true, true); + } + return EVENT_DONE; + } + + int connectEvent(int event, NetVConnection * aremote) + { + if (event != NET_EVENT_OPEN) { + printf("TestProxy connectEvent error %d\n", event); + return done(); + } + remote = aremote; + outbuf = new_MIOBuffer(); + SET_HANDLER(sendEvent); + *url_end = 0; + sprintf(outbuf->start, "GET %s HTTP/1.0\nHost: %s\n\n", url, host); + outbuf->fill(strlen(outbuf->start) + 1); + remote->do_io(VIO::WRITE, this, INT64_MAX, outbuf); + // printf("sending [%s]\n",outbuf->start); + return EVENT_CONT; + } + + int sendEvent(int event, VIO * vio) + { + if (event != VC_EVENT_WRITE_READY) { + printf("TestProxy sendEvent error %d\n", event); + return done(); + } + if (vio->buffer.size()) + return EVENT_CONT; + SET_HANDLER(tunnelEvent); + clusterOutVIO = (VIO *) - 1; // some impossible value + if (((NetVConnectionBase *) vc)->closed) { + printf("TestProxy sendEvent unexpected close %X\n", (unsigned int) vc); + vc = 0; + return done(); + } + tunnel = new OneWayTunnel(remote, vc, this, TUNNEL_TILL_DONE, true, true, true); + return EVENT_DONE; + } + + int tunnelEvent(int event, Continuation * cont) + { + (void) cont; + if ((VIO *) cont == clusterOutVIO || (VIO *) cont == inVIO) { + if (event == VC_EVENT_WRITE_COMPLETE) + return EVENT_DONE; + if (event == VC_EVENT_ERROR || event == VC_EVENT_EOS) + return EVENT_DONE; + return EVENT_CONT; + } + remote = 0; + vc = 0; + if (event != VC_EVENT_EOS) { + printf("TestProxy sendEvent error %d\n", event); + return done(); + } + // printf("successful proxy of %s\n",url); + return done(); + } + + TestProxy(MIOBuffer * abuf) +: Continuation(new_ProxyMutex()), + vc(0), remote(0), inbuf(abuf), outbuf(0), clusterOutVIO(0), + inVIO(0), url(0), url_end(0), amode(0), tunnel(0), cachefile(0) { + SET_HANDLER(startEvent); + } +}; + +struct TestAccept:Continuation +{ + int startEvent(int event, NetVConnection * e) + { + if (event == NET_EVENT_ACCEPT) { + MIOBuffer *buf = new_MIOBuffer(); + e->do_io(VIO::READ, new TestProxy(buf), INT64_MAX, buf); + } else + { + printf("TestAccept error %d\n", event); + return EVENT_DONE; + } + return EVENT_CONT; + } +TestAccept():Continuation(new_ProxyMutex()) { + SET_HANDLER(startEvent); + } +}; + +struct DumpStats:Continuation +{ + int mainEvent(int event, Event * e) + { + (void) event; + (void) e; + dump_stats(); + return EVENT_CONT; + } + DumpStats():Continuation(NULL) + { + SET_HANDLER(mainEvent); + } +}; + +void +redirect_test(Machine * m, void *data, int len) +{ + (void) m; + (void) len; + MIOBuffer *buf = new_MIOBuffer(); + TestProxy *c = new TestProxy(buf); + SET_CONTINUATION_HANDLER(c, clusterEvent); + clusterProcessor.connect(c, *(ClusterVCToken *) data); +} + +#ifndef SUB_TEST +void +test() +{ + ptest_ClusterFunction = redirect_test; + netProcessor.proxy_accept(new TestAccept); + // eventProcessor.schedule_every(new DumpStats,HRTIME_SECONDS(30)); +} +#endif diff --git a/proxy/TestRegex.cc b/proxy/TestRegex.cc new file mode 100644 index 00000000..f3a44b7c --- /dev/null +++ b/proxy/TestRegex.cc @@ -0,0 +1,31 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include "Main.h" +#include "Regex.h" + +void +test() +{ +} diff --git a/proxy/TestSimpleProxy.cc b/proxy/TestSimpleProxy.cc new file mode 100644 index 00000000..8c151214 --- /dev/null +++ b/proxy/TestSimpleProxy.cc @@ -0,0 +1,161 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "ink_unused.h" /* MAGIC_EDITING_TAG */ +#include +#include "Net.h" +#include "Disk.h" +#include "Main.h" +#include "DNS.h" +#include "OneWayTunnel.h" + +struct TestProxy:Continuation +{ + + NetVConnection *vc; + NetVConnection *remote; + MIOBuffer *inbuf; + MIOBuffer *outbuf; + char *host, *url, *url_end; + char s[256]; + + int done() + { + if (inbuf) + free_MIOBuffer(inbuf); + if (outbuf) + free_MIOBuffer(outbuf); + if (vc) + vc->do_io(VIO::CLOSE); + if (remote) + remote->do_io(VIO::CLOSE); + delete this; + return EVENT_DONE; + } + + int startEvent(int event, VIO * vio) + { + if (event != VC_EVENT_READ_READY) { + printf("TestProxy startEvent error %d\n", event); + return done(); + } + if (vio->buffer.mbuf->gets(s, 255)) { + host = s + 11; + url = strchr(host, '/'); + url_end = strchr(url, ' '); + *url = 0; + dnsProcessor.gethostbyname(host, this); + *url = '/'; + SET_HANDLER(dnsEvent); + vc = (NetVConnection *) vio->vc_server; + return EVENT_DONE; + } + return EVENT_CONT; + } + + int dnsEvent(int event, HostEnt * ent) + { + if (!ent) { + printf("TestProxy dnsEvent error %d\n", event); + return done(); + } + unsigned int ip = *(unsigned int *) ent->h_addr_list[0]; + netProcessor.connect(this, ip, 80); + SET_HANDLER(connectEvent); + return EVENT_DONE; + } + + int connectEvent(int event, NetVConnection * aremote) + { + if (!aremote) { + printf("TestProxy connectEvent error %d\n", event); + return done(); + } + remote = aremote; + outbuf = new_MIOBuffer(); + remote->do_io(VIO::WRITE, this, INT64_MAX, outbuf); + *url_end = 0; + sprintf(outbuf->start, "GET %s HTTP/1.0\n\n\n", url); + outbuf->fill(strlen(outbuf->start) + 1); + printf("sending [%s]\n", outbuf->start); + SET_HANDLER(sendEvent); + return EVENT_CONT; + } + + int sendEvent(int event, VIO * vio) + { + if (event != VC_EVENT_WRITE_READY) { + printf("TestProxy sendEvent error %d\n", event); + return done(); + } + if (vio->buffer.size()) + return EVENT_CONT; + new OneWayTunnel(remote, vc, this, TUNNEL_TILL_DONE, true, true, true); + SET_HANDLER(tunnelEvent); + return EVENT_DONE; + } + + int tunnelEvent(int event, Continuation * cont) + { + (void) cont; + if (event != VC_EVENT_EOS) { + printf("TestProxy sendEvent error %d\n", event); + return done(); + } + remote = 0; + vc = 0; + printf("sucessful proxy of %s\n", url); + return done(); + } + + TestProxy(MIOBuffer * abuf) +: Continuation(new_ProxyMutex()), vc(0), remote(0), inbuf(abuf), outbuf(0), host(0), url(0), url_end(0) { + SET_HANDLER(startEvent); + } +}; + + +struct TestAccept:Continuation +{ + int startEvent(int event, NetVConnection * e) + { + if (!event) { + MIOBuffer *buf = new_MIOBuffer(); + e->do_io(VIO::READ, new TestProxy(buf), INT64_MAX, buf); + } else + { + printf("TestAccept error %d\n", event); + return EVENT_DONE; + } + return EVENT_CONT; + } +TestAccept():Continuation(new_ProxyMutex()) { + SET_HANDLER(startEvent); + } +}; + +void +test() +{ + netProcessor.accept(new TestAccept, accept_port_number); +} diff --git a/proxy/TimeTrace.h b/proxy/TimeTrace.h new file mode 100644 index 00000000..e20ec572 --- /dev/null +++ b/proxy/TimeTrace.h @@ -0,0 +1,85 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + TimeTrace.h + + + ****************************************************************************/ + +#ifndef _TimeTrace_h_ +#define _TimeTrace_h_ + +// #define ENABLE_TIME_TRACE + +#define TIME_DIST_BUCKETS 500 +#define TIME_DIST_BUCKETS_SIZE TIME_DIST_BUCKETS+1 + +#ifdef ENABLE_TIME_TRACE +extern int cdb_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cdb_cache_callbacks; + +extern int callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cache_callbacks; + +extern int rmt_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int rmt_cache_callbacks; + +extern int lkrmt_callback_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int lkrmt_cache_callbacks; + +extern int cntlck_acquire_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cntlck_acquire_events; + +extern int immediate_events_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cnt_immediate_events; + +extern int inmsg_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int inmsg_events; + +extern int open_delay_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int open_delay_events; + +extern int cluster_send_time_dist[TIME_DIST_BUCKETS_SIZE]; +extern int cluster_send_events; +#endif // ENABLE_TIME_TRACE + +#ifdef ENABLE_TIME_TRACE +#define LOG_EVENT_TIME(_start_time, _time_dist, _time_cnt) do { \ + ink_hrtime now = ink_get_hrtime(); \ + unsigned int bucket = (now - _start_time) / HRTIME_MSECONDS(10); \ + if (bucket > TIME_DIST_BUCKETS) \ + bucket = TIME_DIST_BUCKETS; \ + ink_atomic_increment(&_time_dist[bucket], 1); \ + ink_atomic_increment(&_time_cnt, 1); \ +} while(0) + +#else // !ENABLE_TIME_TRACE +#define LOG_EVENT_TIME(_start_time, _time_dist, _time_cnt) +#endif // !ENABLE_TIME_TRACE + +#endif // _TimeTrace_h_ + +// End of TimeTrace.h diff --git a/proxy/Transform.cc b/proxy/Transform.cc new file mode 100644 index 00000000..79c3e5c0 --- /dev/null +++ b/proxy/Transform.cc @@ -0,0 +1,1218 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section thoughts Transform thoughts + + - Must be able to handle a chain of transformations. + - Any transformation in the chain may fail. + Failure options: + - abort the client (if transformed data already sent) + - serve the client the untransformed document + - remove the failing transformation from the chain and attempt the transformation again (difficult to do) + - never send untransformed document to client if client would not understand it (e.g. a set top box) + - Must be able to change response header fields up until the point that TRANSFORM_READ_READY is sent to the user. + + @section usage Transform usage + + -# transformProcessor.open (cont, hooks); - returns "tvc", a TransformVConnection if 'hooks != NULL' + -# tvc->do_io_write (cont, nbytes, buffer1); + -# cont->handleEvent (TRANSFORM_READ_READY, NULL); + -# tvc->do_io_read (cont, nbytes, buffer2); + -# tvc->do_io_close (); + + @section visualization Transform visualization + + @verbatim + +----+ +----+ +----+ +----+ + -IB->| T1 |-B1->| T2 |-B2->| T3 |-B3->| T4 |-OB-> + +----+ +----+ +----+ +----+ + @endverbatim + + Data flows into the first transform in the form of the buffer + passed to TransformVConnection::do_io_write (IB). Data flows + out of the last transform in the form of the buffer passed to + TransformVConnection::do_io_read (OB). Between each transformation is + another buffer (B1, B2 and B3). + + A transformation is a Continuation. The continuation is called with the + event TRANSFORM_IO_WRITE to initialize the write and TRANSFORM_IO_READ + to initialize the read. + +*/ + +#ifndef TS_NO_TRANSFORM + +#include "ProxyConfig.h" +#include "P_Net.h" +#include "MimeTable.h" +#include "TransformInternal.h" +#include "HttpMessageBody.h" +#include "HdrUtils.h" +#include "Log.h" + + +#define ART 1 +#define AGIF 2 + + +TransformProcessor transformProcessor; + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformProcessor::start() +{ +#ifdef PREFETCH + prefetchProcessor.start(); +#endif +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +VConnection * +TransformProcessor::open(Continuation *cont, APIHook *hooks) +{ + if (hooks) { + return NEW(new TransformVConnection(cont, hooks)); + } else { + return NULL; + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +INKVConnInternal * +TransformProcessor::null_transform(ProxyMutex *mutex) +{ + return NEW(new NullTransform(mutex)); +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +INKVConnInternal * +TransformProcessor::range_transform(ProxyMutex *mut, MIMEField *range_field, HTTPInfo *cache_obj, HTTPHdr *transform_resp, bool & b) +{ + RangeTransform *range_transform = NEW(new RangeTransform(mut, range_field, cache_obj, transform_resp)); + + b = range_transform->is_range_unsatisfiable(); + + if (b || range_transform->is_this_range_not_handled()) { + delete range_transform; + return NULL; + } + + return range_transform; +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +TransformTerminus::TransformTerminus(TransformVConnection *tvc) + : VConnection(tvc->mutex), + m_tvc(tvc), m_read_vio(), m_write_vio(), m_event_count(0), m_deletable(0), m_closed(0), m_called_user(0) +{ + SET_HANDLER(&TransformTerminus::handle_event); +} + + +#define RETRY() \ + if (ink_atomic_increment ((int*) &m_event_count, 1) < 0) { \ + ink_assert (!"not reached"); \ + } \ + eventProcessor.schedule_in (this, HRTIME_MSECONDS (10), ET_NET); \ + return 0; + + +int +TransformTerminus::handle_event(int event, void *edata) +{ + NOWARN_UNUSED(edata); + int val; + + m_deletable = ((m_closed != 0) && (m_tvc->m_closed != 0)); + + val = ink_atomic_increment((int *) &m_event_count, -1); + + Debug("transform", "[TransformTerminus::handle_event] event_count %d", m_event_count); + + if (val <= 0) { + ink_assert(!"not reached"); + } + + m_deletable = m_deletable && (val == 1); + + if (m_closed != 0 && m_tvc->m_closed != 0) { + if (m_deletable) { + Debug("transform", "TransformVConnection destroy [0x%lx]", (long) m_tvc); + delete m_tvc; + return 0; + } + } else if (m_write_vio.op == VIO::WRITE) { + if (m_read_vio.op == VIO::NONE) { + if (!m_called_user) { + Debug("transform", "TransformVConnection calling user: %d %d [0x%lx] [0x%lx]", + m_event_count, event, (long) m_tvc, (long) m_tvc->m_cont); + + m_called_user = 1; + // It is our belief this is safe to pass a reference, i.e. its scope + // and locking ought to be safe across the lifetime of the continuation. + m_tvc->m_cont->handleEvent(TRANSFORM_READ_READY, (void *)&m_write_vio.nbytes); + } + } else { + int64_t towrite; + + MUTEX_TRY_LOCK(trylock1, m_write_vio.mutex, this_ethread()); + if (!trylock1) { + RETRY(); + } + + MUTEX_TRY_LOCK(trylock2, m_read_vio.mutex, this_ethread()); + if (!trylock2) { + RETRY(); + } + + if (m_closed != 0) { + return 0; + } + + if (m_write_vio.op == VIO::NONE) { + return 0; + } + + towrite = m_write_vio.ntodo(); + if (towrite > 0) { + if (towrite > m_write_vio.get_reader()->read_avail()) { + towrite = m_write_vio.get_reader()->read_avail(); + } + if (towrite > m_read_vio.ntodo()) { + towrite = m_read_vio.ntodo(); + } + + if (towrite > 0) { + m_read_vio.get_writer()->write(m_write_vio.get_reader(), towrite); + m_read_vio.ndone += towrite; + + m_write_vio.get_reader()->consume(towrite); + m_write_vio.ndone += towrite; + } + } + + if (m_write_vio.ntodo() > 0) { + if (towrite > 0) { + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_READY, &m_write_vio); + } + } else { + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_COMPLETE, &m_write_vio); + } + + // We could have closed on the write callback + if (m_closed != 0 && m_tvc->m_closed != 0) { + return 0; + } + + if (m_read_vio.ntodo() > 0) { + if (m_write_vio.ntodo() <= 0) { + m_read_vio._cont->handleEvent(VC_EVENT_EOS, &m_read_vio); + } else if (towrite > 0) { + m_read_vio._cont->handleEvent(VC_EVENT_READ_READY, &m_read_vio); + } + } else { + m_read_vio._cont->handleEvent(VC_EVENT_READ_COMPLETE, &m_read_vio); + } + } + } else { + MUTEX_TRY_LOCK(trylock2, m_read_vio.mutex, this_ethread()); + if (!trylock2) { + RETRY(); + } + + if (m_closed != 0) { + // The terminus was closed, but the enclosing transform + // vconnection wasn't. If the terminus was aborted then we + // call the read_vio cont back with VC_EVENT_ERROR. If it + // was closed normally then we call it back with + // VC_EVENT_EOS. If a read operation hasn't been initiated + // yet and we haven't called the user back then we call + // the user back instead of the read_vio cont (which won't + // exist). + if (m_tvc->m_closed == 0) { + if (m_closed == TS_VC_CLOSE_ABORT) { + if (m_read_vio.op == VIO::NONE) { + if (!m_called_user) { + m_called_user = 1; + m_tvc->m_cont->handleEvent(VC_EVENT_ERROR, NULL); + } + } else { + m_read_vio._cont->handleEvent(VC_EVENT_ERROR, &m_read_vio); + } + } else { + if (m_read_vio.op == VIO::NONE) { + if (!m_called_user) { + m_called_user = 1; + m_tvc->m_cont->handleEvent(VC_EVENT_EOS, NULL); + } + } else { + m_read_vio._cont->handleEvent(VC_EVENT_EOS, &m_read_vio); + } + } + } + return 0; + } + } + + return 0; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +VIO * +TransformTerminus::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + m_read_vio.buffer.writer_for(buf); + m_read_vio.op = VIO::READ; + m_read_vio.set_continuation(c); + m_read_vio.nbytes = nbytes; + m_read_vio.ndone = 0; + m_read_vio.vc_server = this; + + if (ink_atomic_increment((int *) &m_event_count, 1) < 0) { + ink_assert(!"not reached"); + } + Debug("transform", "[TransformTerminus::do_io_read] event_count %d", m_event_count); + + eventProcessor.schedule_imm(this, ET_NET); + + return &m_read_vio; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +VIO * +TransformTerminus::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + // In the process of eliminating 'owner' mode so asserting against it + ink_assert(!owner); + m_write_vio.buffer.reader_for(buf); + m_write_vio.op = VIO::WRITE; + m_write_vio.set_continuation(c); + m_write_vio.nbytes = nbytes; + m_write_vio.ndone = 0; + m_write_vio.vc_server = this; + + if (ink_atomic_increment((int *) &m_event_count, 1) < 0) { + ink_assert(!"not reached"); + } + Debug("transform", "[TransformTerminus::do_io_write] event_count %d", m_event_count); + + eventProcessor.schedule_imm(this, ET_NET); + + return &m_write_vio; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformTerminus::do_io_close(int error) +{ + if (ink_atomic_increment((int *) &m_event_count, 1) < 0) { + ink_assert(!"not reached"); + } + + INK_WRITE_MEMORY_BARRIER; + + if (error != -1) { + lerrno = error; + m_closed = TS_VC_CLOSE_ABORT; + } else { + m_closed = TS_VC_CLOSE_NORMAL; + } + + m_read_vio.op = VIO::NONE; + m_read_vio.buffer.clear(); + + m_write_vio.op = VIO::NONE; + m_write_vio.buffer.clear(); + + eventProcessor.schedule_imm(this, ET_NET); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformTerminus::do_io_shutdown(ShutdownHowTo_t howto) +{ + if ((howto == IO_SHUTDOWN_READ) || (howto == IO_SHUTDOWN_READWRITE)) { + m_read_vio.op = VIO::NONE; + m_read_vio.buffer.clear(); + } + + if ((howto == IO_SHUTDOWN_WRITE) || (howto == IO_SHUTDOWN_READWRITE)) { + m_write_vio.op = VIO::NONE; + m_write_vio.buffer.clear(); + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformTerminus::reenable(VIO *vio) +{ + ink_assert((vio == &m_read_vio) || (vio == &m_write_vio)); + + if (m_event_count == 0) { + + if (ink_atomic_increment((int *) &m_event_count, 1) < 0) { + ink_assert(!"not reached"); + } + Debug("transform", "[TransformTerminus::reenable] event_count %d", m_event_count); + eventProcessor.schedule_imm(this, ET_NET); + } else { + Debug("transform", "[TransformTerminus::reenable] skipping due to " "pending events"); + } +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +TransformVConnection::TransformVConnection(Continuation *cont, APIHook *hooks) +:VConnection(cont->mutex), m_cont(cont), m_terminus(this), m_closed(0) +{ + INKVConnInternal *xform; + + SET_HANDLER(&TransformVConnection::handle_event); + + ink_assert(hooks != NULL); + + m_transform = hooks->m_cont; + while (hooks->m_link.next) { + xform = (INKVConnInternal *) hooks->m_cont; + hooks = hooks->m_link.next; + xform->do_io_transform(hooks->m_cont); + } + xform = (INKVConnInternal *) hooks->m_cont; + xform->do_io_transform(&m_terminus); + + Debug("transform", "TransformVConnection create [0x%lx]", (long) this); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +TransformVConnection::~TransformVConnection() +{ + // Clear the continuations in terminus VConnections so that + // mutex's get released (INKqa05596) + m_terminus.m_read_vio.set_continuation(NULL); + m_terminus.m_write_vio.set_continuation(NULL); + m_terminus.mutex = NULL; + this->mutex = NULL; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +TransformVConnection::handle_event(int event, void *edata) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(edata); + ink_assert(!"not reached"); + return 0; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +VIO * +TransformVConnection::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + Debug("transform", "TransformVConnection do_io_read: 0x%lx [0x%lx]", (long) c, (long) this); + + return m_terminus.do_io_read(c, nbytes, buf); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +VIO * +TransformVConnection::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + NOWARN_UNUSED(owner); + Debug("transform", "TransformVConnection do_io_write: 0x%lx [0x%lx]", (long) c, (long) this); + + return m_transform->do_io_write(c, nbytes, buf); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformVConnection::do_io_close(int error) +{ + Debug("transform", "TransformVConnection do_io_close: %d [0x%lx]", error, (long) this); + + if (error != -1) { + m_closed = TS_VC_CLOSE_ABORT; + } else { + m_closed = TS_VC_CLOSE_NORMAL; + } + + m_transform->do_io_close(error); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformVConnection::do_io_shutdown(ShutdownHowTo_t howto) +{ + ink_assert(howto == IO_SHUTDOWN_WRITE); + + Debug("transform", "TransformVConnection do_io_shutdown: %d [0x%lx]", howto, (long) this); + + m_transform->do_io_shutdown(howto); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +TransformVConnection::reenable(VIO *vio) +{ + NOWARN_UNUSED(vio); + ink_assert(!"not reached"); +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +TransformControl::TransformControl() +:Continuation(new_ProxyMutex()), m_hooks(), m_tvc(NULL), m_read_buf(NULL), m_write_buf(NULL) +{ + SET_HANDLER(&TransformControl::handle_event); + + m_hooks.append(transformProcessor.null_transform(new_ProxyMutex())); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +TransformControl::handle_event(int event, void *edata) +{ + NOWARN_UNUSED(edata); + switch (event) { + case EVENT_IMMEDIATE: + { + char *s, *e; + + ink_assert(m_tvc == NULL); + if (http_global_hooks && http_global_hooks->get(TS_HTTP_RESPONSE_TRANSFORM_HOOK)) { + m_tvc = transformProcessor.open(this, http_global_hooks->get(TS_HTTP_RESPONSE_TRANSFORM_HOOK)); + } else { + m_tvc = transformProcessor.open(this, m_hooks.get()); + } + ink_assert(m_tvc != NULL); + + m_write_buf = new_MIOBuffer(); + s = m_write_buf->end(); + e = m_write_buf->buf_end(); + + memset(s, 'a', e - s); + m_write_buf->fill(e - s); + + m_tvc->do_io_write(this, 4 * 1024, m_write_buf->alloc_reader()); + break; + } + + case TRANSFORM_READ_READY: + { + MIOBuffer *buf = new_empty_MIOBuffer(); + + m_read_buf = buf->alloc_reader(); + m_tvc->do_io_read(this, INT64_MAX, buf); + break; + } + + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + m_tvc->do_io_close(); + + free_MIOBuffer(m_read_buf->mbuf); + m_read_buf = NULL; + + free_MIOBuffer(m_write_buf); + m_write_buf = NULL; + break; + + case VC_EVENT_WRITE_COMPLETE: + break; + + default: + ink_assert(!"not reached"); + break; + } + + return 0; +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +NullTransform::NullTransform(ProxyMutex *_mutex) + : INKVConnInternal(NULL, reinterpret_cast(_mutex)), + m_output_buf(NULL), m_output_reader(NULL), m_output_vio(NULL) +{ + SET_HANDLER(&NullTransform::handle_event); + + Debug("transform", "NullTransform create [0x%lx]", (long) this); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +NullTransform::~NullTransform() +{ + if (m_output_buf) { + free_MIOBuffer(m_output_buf); + } +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +NullTransform::handle_event(int event, void *edata) +{ + handle_event_count(event); + + Debug("transform", "[NullTransform::handle_event] event count %d", m_event_count); + + if (m_closed) { + if (m_deletable) { + Debug("transform", "NullTransform destroy: %d [0x%lx]", m_output_vio ? m_output_vio->ndone : 0, (long) this); + delete this; + } + } else { + switch (event) { + case VC_EVENT_ERROR: + m_write_vio._cont->handleEvent(VC_EVENT_ERROR, &m_write_vio); + break; + case VC_EVENT_WRITE_COMPLETE: + ink_assert(m_output_vio == (VIO *) edata); + + // The write to the output vconnection completed. This + // could only be the case if the data being fed into us + // has also completed. + ink_assert(m_write_vio.ntodo() == 0); + + m_output_vc->do_io_shutdown(IO_SHUTDOWN_WRITE); + break; + case VC_EVENT_WRITE_READY: + default: + { + int64_t towrite; + int64_t avail; + + ink_assert(m_output_vc != NULL); + + if (!m_output_vio) { + m_output_buf = new_empty_MIOBuffer(); + m_output_reader = m_output_buf->alloc_reader(); + m_output_vio = m_output_vc->do_io_write(this, m_write_vio.nbytes, m_output_reader); + } + + MUTEX_TRY_LOCK(trylock, m_write_vio.mutex, this_ethread()); + if (!trylock) { + retry(10); + return 0; + } + + if (m_closed) { + return 0; + } + + if (m_write_vio.op == VIO::NONE) { + m_output_vio->nbytes = m_write_vio.ndone; + m_output_vio->reenable(); + return 0; + } + + towrite = m_write_vio.ntodo(); + if (towrite > 0) { + avail = m_write_vio.get_reader()->read_avail(); + if (towrite > avail) { + towrite = avail; + } + + if (towrite > 0) { + Debug("transform", "[NullTransform::handle_event] " "writing %d bytes to output", towrite); + m_output_buf->write(m_write_vio.get_reader(), towrite); + + m_write_vio.get_reader()->consume(towrite); + m_write_vio.ndone += towrite; + } + } + + if (m_write_vio.ntodo() > 0) { + if (towrite > 0) { + m_output_vio->reenable(); + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_READY, &m_write_vio); + } + } else { + m_output_vio->nbytes = m_write_vio.ndone; + m_output_vio->reenable(); + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_COMPLETE, &m_write_vio); + } + + break; + } + } + } + + return 0; +} + + +/*------------------------------------------------------------------------- + Reasons the JG transform cannot currently be a plugin: + a) Uses the config system + - Easily avoided by using the plugin.config file to pass the config + values as parameters to the plugin initialization routine. + b) Uses the stat system + - FIXME: should probably solve this. + -------------------------------------------------------------------------*/ + +/* the JG transform is now a plugin. All the JG code, + config variables and stats are removed from Transform.cc */ + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +#ifdef TS_HAS_TESTS +void +TransformTest::run() +{ + if (is_action_tag_set("transform_test")) { + eventProcessor.schedule_imm(NEW(new TransformControl()), ET_NET); + } +} +#endif + + + +/////////////////////////////////////////////////////////////////// +/// RangeTransform implementation +/// handling Range requests from clients +/////////////////////////////////////////////////////////////////// + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +inline static int +num_chars_for_int(int64_t i) +{ + int k = 1; + + if (i < 0) + return 0; + + while ((i /= 10) != 0) + ++k; + + return k; +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +RangeTransform::RangeTransform(ProxyMutex *mut, MIMEField *range_field, HTTPInfo *cache_obj, HTTPHdr *transform_resp) + : INKVConnInternal(NULL, reinterpret_cast(mut)), + m_output_buf(NULL), + m_output_reader(NULL), + m_range_field(range_field), + m_transform_resp(transform_resp), + m_output_vio(NULL), + m_unsatisfiable_range(true), + m_not_handle_range(false), + m_num_range_fields(0), + m_current_range(0), m_content_type(NULL), m_content_type_len(0), m_ranges(NULL), m_output_cl(0), m_done(0) +{ + SET_HANDLER(&RangeTransform::handle_event); + + m_content_type = cache_obj-> + response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &m_content_type_len); + + m_content_length = cache_obj->object_size_get(); + m_num_chars_for_cl = num_chars_for_int(m_content_length); + + parse_range_and_compare(); + calculate_output_cl(); + + Debug("transform_range", "RangeTransform creation finishes"); +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +RangeTransform::~RangeTransform() +{ + if (m_ranges) + delete[]m_ranges; + if (m_output_buf) + free_MIOBuffer(m_output_buf); +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +RangeTransform::parse_range_and_compare() +{ + // note: unsatisfiable_range is initialized to true in constructor + int prev_good_range, i; + const char *value; + int value_len; + HdrCsvIter csv; + const char *s, *e; + + if (m_content_length <= 0) + return; + + ink_assert(m_range_field != NULL); + + m_num_range_fields = 0; + value = csv.get_first(m_range_field, &value_len); + + while (value) { + m_num_range_fields++; + value = csv.get_next(&value_len); + } + + if (m_num_range_fields <= 0) + return; + + m_ranges = NEW(new RangeRecord[m_num_range_fields]); + + value = csv.get_first(m_range_field, &value_len); + + i = 0; + prev_good_range = -1; + // Currently HTTP/1.1 only defines bytes Range + if (ptr_len_ncmp(value, value_len, "bytes=", 6) == 0) { + while (value) { + // If delimiter '-' is missing + if (!(e = (const char *) memchr(value, '-', value_len))) { + m_unsatisfiable_range = true; + return; + } + + if ( memcmp(value,"bytes=",6) == 0 ) { + s = value + 6; + } + else { + s = value; + } + + m_ranges[i]._start = ((s==e)?-1:mime_parse_int64(s, e)); + + e++; + s = e; + e = value + value_len; + if ( e && *(e-1) == '-') { //open-ended Range: bytes=10-\r\n\r\n should be supported + m_ranges[i]._end = -1; + } + else { + m_ranges[i]._end = mime_parse_int64(s, e); + } + + // check and change if necessary whether this is a right entry + // the last _end bytes are required + if (m_ranges[i]._start == -1 && m_ranges[i]._end > 0) { + if (m_ranges[i]._end > m_content_length) + m_ranges[i]._end = m_content_length; + + m_ranges[i]._start = m_content_length - m_ranges[i]._end; + m_ranges[i]._end = m_content_length - 1; + } + // open start + else if (m_ranges[i]._start >= 0 && m_ranges[i]._end == -1) { + if (m_ranges[i]._start >= m_content_length) + m_ranges[i]._start = -1; + else + m_ranges[i]._end = m_content_length - 1; + } + // "normal" Range - could be wrong if _end<_start + else if (m_ranges[i]._start >= 0 && m_ranges[i]._end >= 0) { + if (m_ranges[i]._start > m_ranges[i]._end || m_ranges[i]._start >= m_content_length) + m_ranges[i]._start = m_ranges[i]._end = -1; + else if (m_ranges[i]._end >= m_content_length) + m_ranges[i]._end = m_content_length - 1; + } + + else + m_ranges[i]._start = m_ranges[i]._end = -1; + + // this is a good Range entry + if (m_ranges[i]._start != -1) { + if (m_unsatisfiable_range) { + m_unsatisfiable_range = false; + // initialize m_current_range to the first good Range + m_current_range = i; + } + // currently we don't handle out-of-order Range entry + else if (prev_good_range >= 0 && m_ranges[i]._start <= m_ranges[prev_good_range]._end) { + m_not_handle_range = true; + break; + } + + prev_good_range = i; + } + + value = csv.get_next(&value_len); + i++; + } + } +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +int +RangeTransform::handle_event(int event, void *edata) +{ + handle_event_count(event); + + if (m_closed) { + if (m_deletable) { + Debug("transform_range", "RangeTransform destroy: %p", this); + delete this; + } + } else { + switch (event) { + case VC_EVENT_ERROR: + m_write_vio._cont->handleEvent(VC_EVENT_ERROR, &m_write_vio); + break; + case VC_EVENT_WRITE_COMPLETE: + ink_assert(m_output_vio == (VIO *) edata); + m_output_vc->do_io_shutdown(IO_SHUTDOWN_WRITE); + break; + case VC_EVENT_WRITE_READY: + default: + ink_assert(m_output_vc != NULL); + + if (!m_output_vio) { + m_output_buf = new_empty_MIOBuffer(); + m_output_reader = m_output_buf->alloc_reader(); + m_output_vio = m_output_vc->do_io_write(this, m_output_cl, m_output_reader); + + change_response_header(); + + if (m_num_range_fields > 1) { + add_boundary(false); + add_sub_header(m_current_range); + } + } + + MUTEX_TRY_LOCK(trylock, m_write_vio.mutex, this_ethread()); + if (!trylock) { + retry(10); + return 0; + } + + if (m_closed) { + return 0; + } + + if (m_write_vio.op == VIO::NONE) { + m_output_vio->nbytes = m_done; + m_output_vio->reenable(); + return 0; + } + + transform_to_range(); + break; + } + } + + return 0; +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +RangeTransform::transform_to_range() +{ + IOBufferReader *reader = m_write_vio.get_reader(); + int64_t toskip, tosend, avail; + const int64_t *end, *start; + int64_t prev_end = 0; + int64_t *done_byte; + + end = &m_ranges[m_current_range]._end; + done_byte = &m_ranges[m_current_range]._done_byte; + start = &m_ranges[m_current_range]._start; + avail = reader->read_avail(); + + while (true) { + if (*done_byte < (*start - 1)) { + toskip = *start - *done_byte - 1; + + if (toskip > avail) + toskip = avail; + + if (toskip > 0) { + reader->consume(toskip); + *done_byte += toskip; + avail = reader->read_avail(); + } + } + + if (avail > 0) { + tosend = *end - *done_byte; + + if (tosend > avail) + tosend = avail; + + m_output_buf->write(reader, tosend); + reader->consume(tosend); + + m_done += tosend; + *done_byte += tosend; + } + + if (*done_byte == *end) + prev_end = *end; + + // move to next Range if done one + // ignore bad Range: _done_byte -1, _end -1 + while (*done_byte == *end) { + m_current_range++; + + if (m_current_range == m_num_range_fields) { + if (m_num_range_fields > 1) { + m_done += m_output_buf->write("\r\n", 2); + add_boundary(true); + } + + Debug("transform_range", "total bytes of Range response body is %d", m_done); + m_output_vio->nbytes = m_done; + m_output_vio->reenable(); + + // if we are detaching before processing all the + // input data, send VC_EVENT_EOS to let the upstream know + // that it can rely on us consuming any more data + int cb_event = (m_write_vio.ntodo() > 0) ? VC_EVENT_EOS : VC_EVENT_WRITE_COMPLETE; + m_write_vio._cont->handleEvent(cb_event, &m_write_vio); + return; + } + + end = &m_ranges[m_current_range]._end; + done_byte = &m_ranges[m_current_range]._done_byte; + start = &m_ranges[m_current_range]._start; + + // if this is a good Range + if (*end != -1) { + m_done += m_output_buf->write("\r\n", 2); + add_boundary(false); + add_sub_header(m_current_range); + + // keep this part for future support of out-of-order Range + // if this is NOT a sequential Range compared to the previous one - + // start of current Range is larger than the end of last Range, do + // not need to go back to the start of the IOBuffereReader. + // Otherwise, reset the IOBufferReader. + //if ( *start > prev_end ) + *done_byte = prev_end; + //else + // reader->reset(); + + break; + } + } + + // When we need to read and there is nothing available + avail = reader->read_avail(); + if (avail == 0) + break; + } + + m_output_vio->reenable(); + m_write_vio._cont->handleEvent(VC_EVENT_WRITE_READY, &m_write_vio); +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +/* + * these two need be changed at the same time + */ + +static char bound[] = "RANGE_SEPARATOR"; +static char range_type[] = "multipart/byteranges; boundary=RANGE_SEPARATOR"; +static char cont_type[] = "Content-type: "; +static char cont_range[] = "Content-range: bytes "; +static int sub_header_size = sizeof(cont_type) - 1 + 2 + sizeof(cont_range) - 1 + 4; +static int boundary_size = 2 + sizeof(bound) - 1 + 2; + +void +RangeTransform::add_boundary(bool end) +{ + m_done += m_output_buf->write("--", 2); + m_done += m_output_buf->write(bound, sizeof(bound) - 1); + + if (end) + m_done += m_output_buf->write("--", 2); + + m_done += m_output_buf->write("\r\n", 2); +} + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +#define RANGE_NUMBERS_LENGTH 60 + +void +RangeTransform::add_sub_header(int index) +{ + // this should be large enough to hold three integers! + char numbers[RANGE_NUMBERS_LENGTH]; + int len; + + m_done += m_output_buf->write(cont_type, sizeof(cont_type) - 1); + if (m_content_type) + m_done += m_output_buf->write(m_content_type, m_content_type_len); + m_done += m_output_buf->write("\r\n", 2); + m_done += m_output_buf->write(cont_range, sizeof(cont_range) - 1); + + snprintf(numbers, sizeof(numbers), "%" PRId64 "d-%" PRId64 "d/%" PRId64 "d", m_ranges[index]._start, m_ranges[index]._end, m_content_length); + len = strlen(numbers); + if (len < RANGE_NUMBERS_LENGTH) + m_done += m_output_buf->write(numbers, len); + m_done += m_output_buf->write("\r\n\r\n", 4); +} + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +/* + * this function changes the response header to reflect this is + * a Range response. + */ + +void +RangeTransform::change_response_header() +{ + MIMEField *field; + char *reason_phrase; + HTTPStatus status_code; + + ink_assert(m_transform_resp->field_find(MIME_FIELD_CONTENT_RANGE, MIME_LEN_CONTENT_RANGE) == NULL); + + status_code = HTTP_STATUS_PARTIAL_CONTENT; + m_transform_resp->status_set(status_code); + reason_phrase = (char *) (HttpMessageBody::StatusCodeName(status_code)); + m_transform_resp->reason_set(reason_phrase, strlen(reason_phrase)); + + // set the right Content-Type for multiple entry Range + if (m_num_range_fields > 1) { + field = m_transform_resp->field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + + if (field != NULL) + m_transform_resp->field_delete(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + + + field = m_transform_resp->field_create(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + field->value_append(m_transform_resp->m_heap, m_transform_resp->m_mime, range_type, sizeof(range_type) - 1); + + m_transform_resp->field_attach(field); + } + + else { + char numbers[RANGE_NUMBERS_LENGTH]; + + field = m_transform_resp->field_create(MIME_FIELD_CONTENT_RANGE, MIME_LEN_CONTENT_RANGE); + snprintf(numbers, sizeof(numbers), "bytes %" PRId64 "-%" PRId64 "/%" PRId64 "", m_ranges[0]._start, m_ranges[0]._end, m_content_length); + field->value_append(m_transform_resp->m_heap, m_transform_resp->m_mime, numbers, strlen(numbers)); + m_transform_resp->field_attach(field); + } +} + +#undef RANGE_NUMBERS_LENGTH + + +/*------------------------------------------------------------------------- + -------------------------------------------------------------------------*/ + +void +RangeTransform::calculate_output_cl() +{ + int i; + + if (m_unsatisfiable_range) + return; + + if (m_num_range_fields == 1) + m_output_cl = m_ranges[0]._end - m_ranges[0]._start + 1; + + else { + for (i = 0; i < m_num_range_fields; i++) { + if (m_ranges[i]._start >= 0) { + m_output_cl += boundary_size; + m_output_cl += sub_header_size + m_content_type_len; + m_output_cl += num_chars_for_int(m_ranges[i]._start) + + num_chars_for_int(m_ranges[i]._end) + m_num_chars_for_cl + 2; + m_output_cl += m_ranges[i]._end - m_ranges[i]._start + 1; + m_output_cl += 2; + } + } + + m_output_cl += boundary_size + 2; + } + + Debug("transform_range", "Pre-calculated Content-Length for Range response is %d", m_output_cl); +} + +#endif // TS_NO_TRANSFORM diff --git a/proxy/Transform.h b/proxy/Transform.h new file mode 100644 index 00000000..a9e95c74 --- /dev/null +++ b/proxy/Transform.h @@ -0,0 +1,62 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __TRANSFORM_H__ +#define __TRANSFORM_H__ + +#include "P_EventSystem.h" + +#include "HTTP.h" +#include "InkAPIInternal.h" + + +#define TRANSFORM_READ_READY (TRANSFORM_EVENTS_START + 0) + + +class TransformProcessor +{ +public: + void start(); + +public: + VConnection * open(Continuation * cont, APIHook * hooks); + INKVConnInternal *null_transform(ProxyMutex * mutex); + INKVConnInternal *range_transform(ProxyMutex * mutex, MIMEField * range_field, HTTPInfo * cache_obj, + HTTPHdr * transform_resp, bool & b); +}; + + +#ifdef TS_HAS_TESTS +class TransformTest +{ +public: + static void run(); +}; +#endif + + +extern TransformProcessor transformProcessor; + + +#endif /* __TRANSFORM_H__ */ + diff --git a/proxy/TransformInternal.h b/proxy/TransformInternal.h new file mode 100644 index 00000000..641868dc --- /dev/null +++ b/proxy/TransformInternal.h @@ -0,0 +1,179 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __TRANSFORM_INTERNAL_H__ +#define __TRANSFORM_INTERNAL_H__ + + +#include "HttpSM.h" +#include "MIME.h" +#include "Transform.h" +#include "P_EventSystem.h" + + +class TransformVConnection; + + +class TransformTerminus:public VConnection +{ +public: + TransformTerminus(TransformVConnection * tvc); + + int handle_event(int event, void *edata); + + VIO *do_io_read(Continuation * c, int64_t nbytes, MIOBuffer * buf); + VIO *do_io_write(Continuation * c, int64_t nbytes, IOBufferReader * buf, bool owner = false); + void do_io_close(int lerrno = -1); + void do_io_shutdown(ShutdownHowTo_t howto); + + void reenable(VIO * vio); + +public: + TransformVConnection * m_tvc; + VIO m_read_vio; + VIO m_write_vio; + volatile int m_event_count; + volatile int m_deletable; + volatile int m_closed; + int m_called_user; +}; + + +class TransformVConnection:public VConnection +{ +public: + TransformVConnection(Continuation * cont, APIHook * hooks); + ~TransformVConnection(); + + int handle_event(int event, void *edata); + + VIO *do_io_read(Continuation * c, int64_t nbytes, MIOBuffer * buf); + VIO *do_io_write(Continuation * c, int64_t nbytes, IOBufferReader * buf, bool owner = false); + void do_io_close(int lerrno = -1); + void do_io_shutdown(ShutdownHowTo_t howto); + + void reenable(VIO * vio); + +public: + VConnection * m_transform; + Continuation *m_cont; + TransformTerminus m_terminus; + volatile int m_closed; +}; + + +class TransformControl:public Continuation +{ +public: + TransformControl(); + + int handle_event(int event, void *edata); + +public: + APIHooks m_hooks; + VConnection *m_tvc; + IOBufferReader *m_read_buf; + MIOBuffer *m_write_buf; +}; + + +class NullTransform:public INKVConnInternal +{ +public: + NullTransform(ProxyMutex * mutex); + ~NullTransform(); + + int handle_event(int event, void *edata); + +public: + MIOBuffer * m_output_buf; + IOBufferReader *m_output_reader; + VIO *m_output_vio; +}; + + +class RangeTransform:public INKVConnInternal +{ +public: + RangeTransform(ProxyMutex * mutex, MIMEField * range_field, HTTPInfo * cache_obj, HTTPHdr * transform_resp); + ~RangeTransform(); + + void parse_range_and_compare(); + int handle_event(int event, void *edata); + + void transform_to_range(); + void add_boundary(bool end); + void add_sub_header(int index); + void change_response_header(); + void calculate_output_cl(); + bool is_this_range_not_handled() + { + return m_not_handle_range; + } + bool is_range_unsatisfiable() + { + return m_unsatisfiable_range; + } + + typedef struct _RangeRecord + { + _RangeRecord() : + _start(-1), _end(-1), _done_byte(-1) + { } + + int64_t _start; + int64_t _end; + int64_t _done_byte; + } RangeRecord; + +public: + MIOBuffer * m_output_buf; + IOBufferReader *m_output_reader; + MIMEField *m_range_field; + HTTPHdr *m_transform_resp; + VIO *m_output_vio; + bool m_unsatisfiable_range; + bool m_not_handle_range; + int64_t m_content_length; + int m_num_chars_for_cl; + int m_num_range_fields; + int m_current_range; + const char *m_content_type; + int m_content_type_len; + RangeRecord *m_ranges; + int64_t m_output_cl; + int64_t m_done; +}; + +#define PREFETCH +#ifdef PREFETCH +class PrefetchProcessor +{ +public: + void start(); +}; + +extern PrefetchProcessor prefetchProcessor; +#endif //PREFETCH + +#endif /* __TRANSFORM_INTERNAL_H__ */ diff --git a/proxy/UDPAPIClientTest.cc b/proxy/UDPAPIClientTest.cc new file mode 100644 index 00000000..2e22649d --- /dev/null +++ b/proxy/UDPAPIClientTest.cc @@ -0,0 +1,116 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "UDPAPIClientTest.h" + +#include +#include +#include +#include + + +char sendBuff[] = "I'm Alive."; + +FILE *fp; + +void +UDPClientTestInit() +{ + TSCont cont; + unsigned long ip; + TSMutex readMutexp; + + ip = inet_addr("209.131.48.79"); + readMutexp = TSMutexCreate(); + cont = TSContCreate(&UDPClient_handle_callbacks, readMutexp); + fp = fopen("UDPAPI.dbg", "a+"); + fprintf(fp, "UDPClient Init called\n"); + fclose(fp); + INKUDPBind(cont, ip, 9999); + +} + +int +UDPClient_handle_callbacks(TSCont cont, TSEvent event, void *e) +{ + INKUDPacketQueue packetQueue; + INKUDPPacket packet; + TSIOBufferBlock recvBuffBlock; + unsigned int destIp = inet_addr("209.131.48.79"); + int destPort = 1813; + INKUDPConn UDPConn; + TSIOBufferReader reader; + TSIOBuffer iobuffer; + const char *buf; + int avail, total_len = 0; + char recvBuff[1024]; + fp = fopen("UDPAPI.dbg", "a+"); + + switch (event) { + + case TS_NET_EVENT_DATAGRAM_OPEN: + UDPConn = (INKUDPConn) e; + INKUDPRecvFrom(cont, UDPConn); + INKUDPSendTo(cont, UDPConn, destIp, destPort, sendBuff, strlen(sendBuff)); + fprintf(fp, "sent %s\n.", (const char *) sendBuff); + + break; + + case TS_NET_EVENT_DATAGRAM_READ_READY: + fprintf(fp, "read ready called\n."); + packetQueue = (INKUDPacketQueue) e; + + while ((packet = INKUDPPacketGet(packetQueue)) != NULL) { + recvBuffBlock = INKUDPPacketBufferBlockGet(packet); + + iobuffer = TSIOBufferCreate(); + reader = TSIOBufferReaderAlloc(iobuffer); + TSIOBufferAppend(iobuffer, recvBuffBlock); + buf = TSIOBufferBlockReadStart(recvBuffBlock, reader, &avail); + + if (avail > 0) { + + for (int i = 0; i < avail; i++) + fprintf(fp, "%c", *(buf + i)); + + + memcpy((char *) &recvBuff + total_len, buf, avail); + TSIOBufferReaderConsume(reader, avail); + total_len += avail; + } + + /* INKqa10255: we'd free the memory - jinsheng */ + INKUDPPacketDestroy(packet); + TSIOBufferReaderFree(reader); + TSIOBufferDestroy(iobuffer); + } + + break; + + case TS_NET_EVENT_DATAGRAM_WRITE_COMPLETE: + break; + + } + fclose(fp); + return TS_EVENT_CONTINUE; +} diff --git a/proxy/UDPAPIClientTest.h b/proxy/UDPAPIClientTest.h new file mode 100644 index 00000000..78266d5f --- /dev/null +++ b/proxy/UDPAPIClientTest.h @@ -0,0 +1,28 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "api/include/experimental.h" + +void UDPClientTestInit(); +int UDPClient_handle_callbacks(INKCont cont, INKEvent event, void *e); +//int send_callbacks (INKCont cont, INKEvent event, void *e); diff --git a/proxy/UDPAPITest.cc b/proxy/UDPAPITest.cc new file mode 100644 index 00000000..4547b212 --- /dev/null +++ b/proxy/UDPAPITest.cc @@ -0,0 +1,131 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "UDPAPITest.h" +#include +#include +#include +#include + + +char ACK[] = "I got it."; + +FILE *fp; + +void +UDPTestInit() +{ + TSCont cont; + TSMutex readMutexp; + unsigned long ip; + + ip = inet_addr("209.131.48.79"); + readMutexp = TSMutexCreate(); + cont = TSContCreate(&handle_callbacks, readMutexp); +// INKUDPBind(cont, INADDR_ANY,1813); + INKUDPBind(cont, ip, 1813); +} + + +void +printN(const char *start, int length) +{ + int i; + for (i = 0; i < length; i++) + fprintf(fp, "%c", *(start + i)); + fprintf(fp, "\n"); +} + +int +handle_callbacks(TSCont cont, TSEvent event, void *e) +{ + INKUDPacketQueue packetQueue; + INKUDPPacket packet; + TSIOBufferBlock recvBuffBlock; + TSIOBufferReader reader; + TSIOBuffer iobuffer; + INKUDPConn UDPConn; + unsigned int ip; + int port; + int *sizep; + int size; + char sendBuff[32]; + const char *buf; + int avail, total_len; + char recv_buffer[4096]; + + + fp = fopen("UDPServer.log", "a+"); + + switch (event) { + + case TS_NET_EVENT_DATAGRAM_OPEN: + fprintf(fp, "open event called\n"); + UDPConn = (INKUDPConn) e; + INKUDPRecvFrom(cont, UDPConn); + break; + + + case TS_NET_EVENT_DATAGRAM_READ_READY: + fprintf(fp, "read ready event called\n"); + packetQueue = (INKUDPacketQueue) e; + total_len = 0; + while ((packet = INKUDPPacketGet(packetQueue)) != NULL) { + recvBuffBlock = INKUDPPacketBufferBlockGet(packet); + iobuffer = TSIOBufferCreate(); + reader = TSIOBufferReaderAlloc(iobuffer); + TSIOBufferAppend(iobuffer, recvBuffBlock); + buf = TSIOBufferBlockReadStart(recvBuffBlock, reader, &avail); + + if (avail > 0) { + fprintf(fp, "Received message is\n"); + printN(buf, avail); + fprintf(fp, "message length = %i\n", avail); + memcpy((char *) &recv_buffer + total_len, buf, avail); + TSIOBufferReaderConsume(reader, avail); + total_len += avail; + } + + + ip = INKUDPPacketFromAddressGet(packet); + port = INKUDPPacketFromPortGet(packet); + fprintf(fp, "port = %d\n", port); + + UDPConn = (INKUDPConn) INKUDPPacketConnGet(packet); + INKUDPSendTo(cont, UDPConn, ip, port, ACK, strlen(ACK)); + + /* INKqa10255: we'd free the memory - jinsheng */ + INKUDPPacketDestroy(packet); + TSIOBufferReaderFree(reader); + TSIOBufferDestroy(iobuffer); + } + + break; + + case TS_NET_EVENT_DATAGRAM_WRITE_COMPLETE: + break; + + } + fclose(fp); + return TS_EVENT_CONTINUE; +} diff --git a/proxy/UDPAPITest.h b/proxy/UDPAPITest.h new file mode 100644 index 00000000..cae6ae6d --- /dev/null +++ b/proxy/UDPAPITest.h @@ -0,0 +1,28 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "api/include/experimental.h" + +void UDPTestInit(); +int handle_callbacks(INKCont cont, INKEvent event, void *e); +//int send_callbacks (INKCont cont, INKEvent event, void *e); diff --git a/proxy/UglyLogStubs.cc b/proxy/UglyLogStubs.cc new file mode 100644 index 00000000..6fdd30ec --- /dev/null +++ b/proxy/UglyLogStubs.cc @@ -0,0 +1,176 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + + +// This is total BS, because our libraries are riddled with cross dependencies. +// TODO: Clean up the dependency mess, and get rid of this. + +#include "libts.h" +#include "LogObject.h" + +#if defined(solaris) +#include +#include +#endif + + +#include "P_Net.h" + +int cache_config_mutex_retry_delay = 2; + +int fds_limit = 8000; +UDPNetProcessor& udpNet; // = udpNetInternal; + +ClassAllocator udpPacketAllocator("udpPacketAllocator"); + +void +UDPConnection::Release() +{ + ink_release_assert(false); +} + +void +UDPNetProcessor::FreeBandwidth(Continuation * udpConn) +{ + NOWARN_UNUSED(udpConn); + ink_release_assert(false); +} + +NetProcessor& netProcessor; // = unix_netProcessor; + +Action * +UnixNetProcessor::connect_re_internal(Continuation * cont, unsigned int ip, int port, NetVCOptions * opt) +{ + NOWARN_UNUSED(cont); + NOWARN_UNUSED(ip); + NOWARN_UNUSED(port); + NOWARN_UNUSED(opt); + ink_release_assert(false); + return NULL; +} + + +#include "InkAPIInternal.h" +ConfigUpdateCbTable *global_config_cbs = NULL; + +void +ConfigUpdateCbTable::invoke(const char *name) +{ + NOWARN_UNUSED(name); + ink_release_assert(false); +} + +const char * +event_int_to_string(int event, int blen, char *buffer) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(blen); + NOWARN_UNUSED(buffer); + ink_release_assert(false); + return NULL; +} + + +struct Machine; +Machine * +this_machine() +{ + ink_release_assert(false); + return NULL; +} + + +#include "LogConfig.h" +void +LogConfig::setup_collation(LogConfig * prev_config) +{ + NOWARN_UNUSED(prev_config); + ink_release_assert(false); +} + +void +LogConfig::create_pre_defined_objects_with_filter(const PreDefinedFormatInfoList & pre_def_info_list, size_t num_filters, + LogFilter ** filter, const char *filt_name, bool force_extension) +{ + NOWARN_UNUSED(pre_def_info_list); + NOWARN_UNUSED(num_filters); + NOWARN_UNUSED(filter); + NOWARN_UNUSED(filt_name); + NOWARN_UNUSED(force_extension); + ink_release_assert(false); +} + +int +LogHost::write(LogBuffer * lb, size_t * to_disk, size_t * to_net, size_t * to_pipe) +{ + NOWARN_UNUSED(lb); + NOWARN_UNUSED(to_disk); + NOWARN_UNUSED(to_net); + NOWARN_UNUSED(to_pipe); + ink_release_assert(false); + return 0; +} + +// TODO: The following was necessary only for Solaris, should examine more. +NetVCOptions const Connection::DEFAULT_OPTIONS; +NetProcessor::AcceptOptions const NetProcessor::DEFAULT_ACCEPT_OPTIONS; + +// TODO: This is even uglier, this actually gets called here when "defined". +NetProcessor::AcceptOptions& +NetProcessor::AcceptOptions::reset() +{ + port = 0; + accept_threads = 0; + domain = AF_INET; + etype = ET_NET; + f_callback_on_open = false; + recv_bufsize = 0; + send_bufsize = 0; + sockopt_flags = 0; + f_outbound_transparent = false; + f_inbound_transparent = false; + return *this; +} + +int +net_accept(NetAccept * na, void *ep, bool blockable) +{ + NOWARN_UNUSED(na); + NOWARN_UNUSED(ep); + NOWARN_UNUSED(blockable); + ink_release_assert(false); + return 0; +} + + +// These are for clang / llvm + +int +CacheVC::handleWrite(int event, Event *e) +{ + NOWARN_UNUSED(event); + NOWARN_UNUSED(e); + return 0; + ink_release_assert(false); +} diff --git a/proxy/UnixCompletionUtil.h b/proxy/UnixCompletionUtil.h new file mode 100644 index 00000000..2a791984 --- /dev/null +++ b/proxy/UnixCompletionUtil.h @@ -0,0 +1,104 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef _UNIX_COMPLETION_UTIL_H_ +#define _UNIX_COMPLETION_UTIL_H_ + +// platform specific wrappers for dealing with I/O completion events +// passed into and back from the I/O core. +#include "UDPIOEvent.h" + +inline Event * +completionUtil::create() +{ + UDPIOEvent *u = UDPIOEventAllocator.alloc(); + return u; +}; +inline void +completionUtil::destroy(Event * e) +{ + ink_assert(e != NULL); + UDPIOEvent *u = (UDPIOEvent *) e; + UDPIOEvent::free(u); +}; +inline void +completionUtil::setThread(Event * e, EThread * t) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->ethread = t; +} +inline void +completionUtil::setContinuation(Event * e, Continuation * c) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + *(Action *) u = c; +} +inline void * +completionUtil::getHandle(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getHandle(); +} +inline void +completionUtil::setHandle(Event * e, void *handle) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->setHandle(handle); +} +inline void +completionUtil::setInfo(Event * e, int fd, IOBufferBlock * buf, int actual, int errno_) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->setInfo(fd, buf, actual, errno_); +} +inline void +completionUtil::setInfo(Event * e, int fd, struct msghdr *msg, int actual, int errno_) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + u->setInfo(fd, msg, actual, errno_); +} +inline int +completionUtil::getBytesTransferred(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getBytesTransferred(); +} +inline IOBufferBlock * +completionUtil::getIOBufferBlock(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getIOBufferBlock(); +} +inline Continuation * +completionUtil::getContinuation(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getContinuation(); +} +inline int +completionUtil::getError(Event * e) +{ + UDPIOEvent *u = (UDPIOEvent *) e; + return u->getError(); +} +#endif diff --git a/proxy/Update.cc b/proxy/Update.cc new file mode 100644 index 00000000..ef63d62f --- /dev/null +++ b/proxy/Update.cc @@ -0,0 +1,2676 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "libts.h" + +#include "Main.h" +#include "Update.h" +#include "ProxyConfig.h" +#include "StatSystem.h" +#include "HttpUpdateSM.h" +#include "HttpDebugNames.h" +#include "URL.h" +#include "HdrUtils.h" +//#include "MixtAPIInternal.h" + +RecRawStatBlock *update_rsb; + +#define UpdateEstablishStaticConfigInteger(_ix,_n) \ + REC_EstablishStaticConfigInteger(_ix,_n); \ + +#define UPDATE_INCREMENT_DYN_STAT(x) \ + RecIncrRawStat(update_rsb, mutex->thread_holding, (int) x, 1); +#define UPDATE_DECREMENT_DYN_STAT(x) \ + RecIncrRawStat(update_rsb, mutex->thread_holding, (int) x, -1); +#define UPDATE_READ_DYN_STAT(x, C, S) \ + RecGetRawStatCount(update_rsb, (int) x, &C); \ + RecGetRawStatSum(update_rsb, (int) x, &S); + +#define UPDATE_CLEAR_DYN_STAT(x) \ +do { \ + RecSetRawStatSum(update_rsb, x, 0); \ + RecSetRawStatCount(update_rsb, x, 0); \ +} while (0); + +#define UPDATE_ConfigReadInteger REC_ConfigReadInteger +#define UPDATE_ConfigReadString REC_ConfigReadString +#define UPDATE_RegisterConfigUpdateFunc REC_RegisterConfigUpdateFunc + + + +// Fundamental constants + +static const char *const GET_METHOD = "GET "; +static const char *const HTTP_VERSION = " HTTP/1.0"; +static const char *const REQUEST_TERMINATOR = "\r\n\r\n"; +static const char *const TERMINATOR = "\r\n"; +static const char *const HTML_COMMENT_TAG = "!--"; +static const char *const HTML_COMMENT_END = "-->"; +static const int MAX_LINE_LENGTH = (32 * 1024); + +// Fundamental constants initialized by UpdateManager::start() + +static int len_GET_METHOD = 0; +static int len_HTTP_VERSION = 0; +static int len_REQUEST_TERMINATOR = 0; +static int len_TERMINATOR = 0; + +struct html_tag update_allowable_html_tags[] = { + {"a", "href"}, + {"img", "src"}, + {"img", "href"}, + {"body", "background"}, + {"frame", "src"}, + {"iframe", "src"}, + {"fig", "src"}, + {"overlay", "src"}, + {"applet", "code"}, + {"script", "src"}, + {"embed", "src"}, + {"bgsound", "src"}, + {"area", "href"}, + {"base", "href"}, // special handling + {"meta", "content"}, // special handling + {NULL, NULL} +}; + +struct schemes_descriptor +{ + const char *tag; + int tag_len; +}; + +struct schemes_descriptor proto_schemes[] = { + {"cid:", 0}, + {"clsid:", 0}, + {"file:", 0}, + {"finger:", 0}, + {"ftp:", 0}, + {"gopher:", 0}, + {"hdl:", 0}, + {"http:", 0}, + {"https:", 0}, + {"ilu:", 0}, + {"ior:", 0}, + {"irc:", 0}, + {"java:", 0}, + {"javascript:", 0}, + {"lifn:", 0}, + {"mailto:", 0}, + {"mid:", 0}, + {"news:", 0}, + {"path:", 0}, + {"prospero:", 0}, + {"rlogin:", 0}, + {"service:", 0}, + {"shttp:", 0}, + {"snews:", 0}, + {"stanf:", 0}, + {"telnet:", 0}, + {"tn3270:", 0}, + {"wais:", 0}, + {"whois++:", 0}, + {NULL, 0} +}; + +struct schemes_descriptor supported_proto_schemes[] = { + {"http:",}, + {NULL, 0} +}; + +static int global_id = 1; + +void +init_proto_schemes() +{ + int n; + for (n = 0; proto_schemes[n].tag; ++n) { + proto_schemes[n].tag_len = strlen(proto_schemes[n].tag); + } +} + +void +init_supported_proto_schemes() +{ + int n; + for (n = 0; supported_proto_schemes[n].tag; ++n) { + supported_proto_schemes[n].tag_len = strlen(supported_proto_schemes[n].tag); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Class UpdateConfigParams +// Global subsystem configuration parameters +/////////////////////////////////////////////////////////////////////////////// + +UpdateConfigParams::UpdateConfigParams(): +_enabled(0), _immediate_update(0), _retry_count(0), +_retry_interval(0), _concurrent_updates(0), _max_update_state_machines(0), _memory_use_in_mb(0) +{ +} + +UpdateConfigParams::UpdateConfigParams(UpdateConfigParams & p) +{ + _enabled = p._enabled; + _immediate_update = p._immediate_update; + _retry_count = p._retry_count; + _retry_interval = p._retry_interval; + _concurrent_updates = p._concurrent_updates; + _max_update_state_machines = p._max_update_state_machines; + _memory_use_in_mb = p._memory_use_in_mb; +} + +UpdateConfigParams::~UpdateConfigParams() +{ +} + +UpdateConfigParams & UpdateConfigParams::operator=(UpdateConfigParams & p) +{ + _enabled = p._enabled; + _immediate_update = p._immediate_update; + _retry_count = p._retry_count; + _retry_interval = p._retry_interval; + _concurrent_updates = p._concurrent_updates; + _max_update_state_machines = p._max_update_state_machines; + _memory_use_in_mb = p._memory_use_in_mb; + return *this; +} + +int +UpdateConfigParams::operator==(UpdateConfigParams & p) +{ + if (_enabled != p._enabled) + return 0; + if (_immediate_update != p._immediate_update) + return 0; + if (_retry_count != p._retry_count) + return 0; + if (_retry_interval != p._retry_interval) + return 0; + if (_concurrent_updates != p._concurrent_updates) + return 0; + if (_max_update_state_machines != p._max_update_state_machines) + return 0; + if (_memory_use_in_mb != p._memory_use_in_mb) + return 0; + return 1; +} + +///////////////////////////////////////////////////////////////////////////// +// Class UpdateEntry +// Per update object descriptor +///////////////////////////////////////////////////////////////////////////// + +UpdateEntry::UpdateEntry():_group_link(0), _hash_link(0), _id(0), _url(0), +_URLhandle(), _terminal_url(0), +_request_headers(0), _num_request_headers(0), +_http_hdr(0), +_offset_hour(0), _interval(0), _max_depth(0), _start_time(0), _expired(0), _scheme_index(-1), _update_event_status(0) +{ + http_parser_init(&_http_parser); +} + +UpdateEntry::~UpdateEntry() +{ + if (_url) { + xfree(_url); + _url = NULL; + } + if (_URLhandle.valid()) { + _URLhandle.destroy(); + } + if (_request_headers) { + xfree(_request_headers); + _request_headers = NULL; + } + // INKqa12891: _http_hdr can be NULL + if (_http_hdr && _http_hdr->valid()) { + _http_hdr->destroy(); + delete _http_hdr; + _http_hdr = NULL; + } + _indirect_list = NULL; +} + +void +UpdateEntry::Init(int derived_url) +{ + _id = ink_atomic_increment(&global_id, 1); + if (derived_url) { + return; + } + ComputeScheduleTime(); + + int scheme_len; + const char *scheme = _URLhandle.scheme_get(&scheme_len); + if (scheme != URL_SCHEME_HTTP) { + // Depth is only valid for scheme "http" + _max_depth = 0; + } + +} + +int +UpdateEntry::ValidURL(char *s, char *e) +{ + // Note: string 's' is null terminated. + + const char *url_start = s; + char *url_end = e; + int err; + + _URLhandle.create(NULL); + err = _URLhandle.parse(&url_start, url_end); + if (err >= 0) { + _url = xstrdup(s); + return 0; // Valid URL + } else { + _URLhandle.destroy(); + return 1; // Invalid URL + } + return 0; +} + +int +UpdateEntry::ValidHeaders(char *s, char *e) +{ + NOWARN_UNUSED(e); + // Note: string 's' is null terminated. + + enum + { + FIND_START_OF_HEADER_NAME = 1, + SCAN_FOR_HEADER_NAME, + SCAN_FOR_END_OF_HEADER_VALUE + }; + + char *p = s; + char *t; + int bad_header = 0; + int end_of_headers = 0; + int scan_state = FIND_START_OF_HEADER_NAME; + + while (*p) { + switch (scan_state) { + case FIND_START_OF_HEADER_NAME: + { + if (!ValidHeaderNameChar(*p)) { + bad_header = 1; + break; + } else { + scan_state = SCAN_FOR_HEADER_NAME; + break; + } + } + case SCAN_FOR_HEADER_NAME: + { + if (!ValidHeaderNameChar(*p)) { + if (*p == ':') { + scan_state = SCAN_FOR_END_OF_HEADER_VALUE; + break; + } else { + bad_header = 1; + break; + } + } else { + // Get next char + break; + } + } + case SCAN_FOR_END_OF_HEADER_VALUE: + { + t = strchr(p, '\r'); + if (t) { + if (*(t + 1) == '\n') { + p = t + 1; + ++_num_request_headers; + scan_state = FIND_START_OF_HEADER_NAME; + break; + } else { + bad_header = 1; + break; + } + } else { + t = strchr(p, 0); + if (t) { + ++_num_request_headers; + end_of_headers = 1; + } else { + bad_header = 1; + } + break; + } + } + } // End of switch + + if (bad_header) { + if (_num_request_headers) { + return 1; // Fail; Bad header with > 1 valid headers + } else { + if (p == s) { + return 0; // OK; user specified no headers + } else { + return 1; // Fail; first header is invalid + } + } + } else { + if (end_of_headers) { + break; + } else { + ++p; + } + } + } + + // At least 1 valid header exists + + _request_headers = xstrdup(s); + return 0; // OK; > 1 valid headers +} + +int +UpdateEntry::BuildHttpRequest() +{ + // Given the HTTP request and associated headers, + // transform the data into a HTTPHdr object. + + char request[MAX_LINE_LENGTH]; + int request_size; + + request_size = len_GET_METHOD + strlen(_url) + + len_HTTP_VERSION + (_request_headers ? len_TERMINATOR + strlen(_request_headers) : 0) + len_REQUEST_TERMINATOR + 1; + if (request_size > MAX_LINE_LENGTH) { + return 1; + } + if (_request_headers) { + snprintf(request, sizeof(request), "%s%s%s%s%s%s", GET_METHOD, _url, + HTTP_VERSION, TERMINATOR, _request_headers, REQUEST_TERMINATOR); + } else { + snprintf(request, sizeof(request), "%s%s%s%s", GET_METHOD, _url, HTTP_VERSION, REQUEST_TERMINATOR); + } + _http_hdr = NEW(new HTTPHdr); + http_parser_init(&_http_parser); + _http_hdr->create(HTTP_TYPE_REQUEST); + int err; + const char *start = request; + const char *end = start + request_size - 1; + + while (start < end) { + err = _http_hdr->parse_req(&_http_parser, &start, end, false); + if (err != PARSE_CONT) { + break; + } + end = start + strlen(start); + } + http_parser_clear(&_http_parser); + return 0; +} + +int +UpdateEntry::ValidHeaderNameChar(char c) +{ + if ((c > 31) && (c < 127)) { + if (ValidSeparatorChar(c)) { + return 0; // Invalid + } else { + return 1; // Valid + } + } else { + return 0; // Invalid + } +} + +int +UpdateEntry::ValidSeparatorChar(char c) +{ + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + case ' ': + case '\t': + return 1; // Valid separator char + default: + return 0; + } +} + +int +UpdateEntry::ValidHour(char *s, char *e) +{ + NOWARN_UNUSED(e); + // Note: string 's' is null terminated. + + _offset_hour = atoi(s); + if ((_offset_hour >= MIN_OFFSET_HOUR) && (_offset_hour <= MAX_OFFSET_HOUR)) { + return 0; // Valid data + } else { + return 1; // Invalid data + } +} + +int +UpdateEntry::ValidInterval(char *s, char *e) +{ + NOWARN_UNUSED(e); + // Note: string 's' is null terminated. + + _interval = atoi(s); + if ((_interval >= MIN_INTERVAL) && (_interval <= MAX_INTERVAL)) { + return 0; // Valid data + } else { + return 1; // Invalid data + } + return 0; +} + +int +UpdateEntry::ValidDepth(char *s, char *e) +{ + NOWARN_UNUSED(e); + // Note: string 's' is null terminated. + + _max_depth = atoi(s); + if ((_max_depth >= MIN_DEPTH) && (_max_depth <= MAX_DEPTH)) { + return 0; // Valid data + } else { + return 1; // Invalid data + } + return 0; +} + +void +UpdateEntry::SetTerminalStatus(int term_url) +{ + _terminal_url = term_url; +} + +int +UpdateEntry::TerminalURL() +{ + return _terminal_url; +} + + +void +UpdateEntry::ComputeScheduleTime() +{ + ink_hrtime ht; + time_t cur_time; + time_t start_time_delta; + struct tm cur_tm; + + if (_expired) { + _expired = 0; + } else { + if (_start_time) { + return; + } + } + ht = ink_get_based_hrtime(); + cur_time = ht / HRTIME_SECOND; + ink_localtime_r(&cur_time, &cur_tm); + + if (!_start_time) { + // Initial case + if (cur_tm.tm_hour == _offset_hour) { + start_time_delta = 24 * SECONDS_PER_HOUR; + + } else if (cur_tm.tm_hour < _offset_hour) { + start_time_delta = (_offset_hour - cur_tm.tm_hour) * SECONDS_PER_HOUR; + + } else { + start_time_delta = ((24 - cur_tm.tm_hour) + _offset_hour) * SECONDS_PER_HOUR; + } + start_time_delta -= ((cur_tm.tm_min * SECONDS_PER_MIN) + cur_tm.tm_sec); + _start_time = cur_time + start_time_delta; + + } else { + // Compute next start time + _start_time += _interval; + } +} + +int +UpdateEntry::ScheduleNow(time_t cur_time) +{ + if (cur_time >= _start_time) { + _expired = 1; + return 1; + } else { + return 0; + } +} + +///////////////////////////////////////////////////////////////////////////// +// Class UpdateConfigList +// Container for UpdateEntry objects +///////////////////////////////////////////////////////////////////////////// +UpdateConfigList::UpdateConfigList():_entry_q_elements(0), _pending_q_elements(0), _hash_table(0) +{ +} + +UpdateConfigList::~UpdateConfigList() +{ + if (_hash_table) { + delete[]_hash_table; + _hash_table = NULL; + } +} + +void +UpdateConfigList::Add(UpdateEntry * e) +{ + _entry_q_elements++; + _entry_q.enqueue(e); +} + +int +UpdateConfigList::HashAdd(UpdateEntry * e) +{ + uint64_t folded64 = e->_url_md5.fold(); + ink_assert(folded64); + int32_t index = folded64 % HASH_TABLE_SIZE; + + if (!_hash_table) { + // One time initialization + + _hash_table = NEW(new UpdateEntry *[HASH_TABLE_SIZE]); + memset((char *) _hash_table, 0, (sizeof(UpdateEntry *) * HASH_TABLE_SIZE)); + } + // Add to hash table only if unique + + UpdateEntry *he = _hash_table[index]; + UpdateEntry **last_link = &_hash_table[index]; + + while (he) { + if (e->_url_md5 == he->_url_md5) { + return 1; // duplicate detected + } else { + last_link = &he->_hash_link; + he = he->_hash_link; + } + } + + // Entry is unique, add to hash list + + e->_hash_link = *last_link; + *last_link = e; + + // Add to entry queue + + Add(e); + + return 0; // Entry added +} + +UpdateEntry * +UpdateConfigList::Remove() +{ + UpdateEntry *e = _entry_q.dequeue(); + if (e) { + _entry_q_elements--; + } + return e; +} + +void +UpdateConfigList::AddPending(UpdateEntry * e) +{ + _pending_q_elements++; + _pending_q.enqueue(e); +} + +UpdateEntry * +UpdateConfigList::RemovePending() +{ + UpdateEntry *e = _pending_q.dequeue(); + if (e) { + _pending_q_elements--; + } + return e; +} + +///////////////////////////////////////////////////////////////////////////// +// Class UpdateManager +// External interface to Update subsystem +///////////////////////////////////////////////////////////////////////////// + +UpdateManager::UpdateManager():_CM(0), _SCH(0) +{ +} + +UpdateManager::~UpdateManager() +{ +} + +int +UpdateManager::start() +{ + // Initialize fundamental constants + + len_GET_METHOD = strlen(GET_METHOD); + len_HTTP_VERSION = strlen(HTTP_VERSION); + len_REQUEST_TERMINATOR = strlen(REQUEST_TERMINATOR); + len_TERMINATOR = strlen(TERMINATOR); + init_proto_schemes(); + init_supported_proto_schemes(); + + _CM = NEW(new UpdateConfigManager); + _CM->init(); + + _SCH = NEW(new UpdateScheduler(_CM)); + _SCH->Init(); + + return 0; +} + +UpdateManager updateManager; + +typedef int (UpdateConfigManager::*UpdateConfigManagerContHandler) (int, void *); +///////////////////////////////////////////////////////////////////////////// +// Class UpdateConfigManager +// Handle Update subsystem global configuration and URL list updates +///////////////////////////////////////////////////////////////////////////// +UpdateConfigManager::UpdateConfigManager() +:Continuation(new_ProxyMutex()), _periodic_event(0), _filename(0) +{ + SET_HANDLER((UpdateConfigManagerContHandler) + & UpdateConfigManager::ProcessUpdate); +} + +UpdateConfigManager::~UpdateConfigManager() +{ +} + +static RecInt local_http_server_port = 0; + +int +UpdateConfigManager::init() +{ + update_rsb = RecAllocateRawStatBlock((int) update_stat_count); + + UpdateEstablishStaticConfigInteger(local_http_server_port, "proxy.config.http.server_port"); + + _CP_actual = NEW(new UpdateConfigParams); + + // Setup update handlers for each global configuration parameter + + UpdateEstablishStaticConfigInteger(_CP_actual->_enabled, "proxy.config.update.enabled"); + + UpdateEstablishStaticConfigInteger(_CP_actual->_immediate_update, "proxy.config.update.force"); + + UpdateEstablishStaticConfigInteger(_CP_actual->_retry_count, "proxy.config.update.retry_count"); + + UpdateEstablishStaticConfigInteger(_CP_actual->_retry_interval, "proxy.config.update.retry_interval"); + + UpdateEstablishStaticConfigInteger(_CP_actual->_concurrent_updates, "proxy.config.update.concurrent_updates"); + + UpdateEstablishStaticConfigInteger(_CP_actual->_max_update_state_machines, + "proxy.config.update.max_update_state_machines"); + + UpdateEstablishStaticConfigInteger(_CP_actual->_memory_use_in_mb, "proxy.config.update.memory_use_mb"); + + // Register Scheduled Update stats + + RecRegisterRawStat(update_rsb, RECT_PROCESS, + "proxy.process.update.successes", + RECD_INT, RECP_NON_PERSISTENT, (int) update_successes_stat, RecRawStatSyncCount); + UPDATE_CLEAR_DYN_STAT(update_successes_stat); + + RecRegisterRawStat(update_rsb, RECT_PROCESS, + "proxy.process.update.no_actions", + RECD_INT, RECP_NON_PERSISTENT, (int) update_no_actions_stat, RecRawStatSyncCount); + UPDATE_CLEAR_DYN_STAT(update_no_actions_stat); + + RecRegisterRawStat(update_rsb, RECT_PROCESS, + "proxy.process.update.fails", + RECD_INT, RECP_NON_PERSISTENT, (int) update_fails_stat, RecRawStatSyncCount); + UPDATE_CLEAR_DYN_STAT(update_fails_stat); + + RecRegisterRawStat(update_rsb, RECT_PROCESS, + "proxy.process.update.unknown_status", + RECD_INT, RECP_NON_PERSISTENT, (int) update_unknown_status_stat, RecRawStatSyncCount); + UPDATE_CLEAR_DYN_STAT(update_unknown_status_stat); + + RecRegisterRawStat(update_rsb, RECT_PROCESS, + "proxy.process.update.state_machines", + RECD_INT, RECP_NON_PERSISTENT, (int) update_state_machines_stat, RecRawStatSyncCount); + UPDATE_CLEAR_DYN_STAT(update_state_machines_stat); + + Debug("update", + "Update params: enable %d force %d rcnt %d rint %d updates %d " + "max_sm %d mem %d", + _CP_actual->_enabled, _CP_actual->_immediate_update, + _CP_actual->_retry_count, _CP_actual->_retry_interval, + _CP_actual->_concurrent_updates, _CP_actual->_max_update_state_machines, _CP_actual->_memory_use_in_mb); + + // Make working and actual global config copies equal + + _CP = NEW(new UpdateConfigParams(*_CP_actual)); + + // Setup "update.config" update handler + + SetFileName((char *) "update.config"); + REC_RegisterConfigUpdateFunc("proxy.config.update.update_configuration", URL_list_update_callout, (void *) this); + + // Simulate configuration update to sync working and current databases + + handleEvent(EVENT_IMMEDIATE, (Event *) NULL); + + // Setup periodic to detect global config updates + + _periodic_event = eventProcessor.schedule_every(this, HRTIME_SECONDS(10)); + + return 0; +} + +int +UpdateConfigManager::GetConfigParams(Ptr *P) +{ + MUTEX_TRY_LOCK(lock, mutex, this_ethread()); + if (!lock) { + return 0; // Try again later + } else { + *P = _CP; + return 1; // Success + } +} + +int +UpdateConfigManager::GetConfigList(Ptr *L) +{ + MUTEX_TRY_LOCK(lock, mutex, this_ethread()); + if (!lock) { + return 0; // Try again later + } else { + *L = _CL; + return 1; // Success + } +} + +int +UpdateConfigManager::URL_list_update_callout(const char *name, RecDataT data_type, RecData data, void *cookie) +{ + NOWARN_UNUSED(name); + NOWARN_UNUSED(data_type); + UpdateConfigManager *cm = (UpdateConfigManager *) cookie; + cm->SetFileName((char *) data.rec_string); + + + // URL update may block in file i/o. + // Reschedule on ET_CACHE thread. + + eventProcessor.schedule_imm(cm, ET_CACHE); + + return 0; +} + +int +UpdateConfigManager::ProcessUpdate(int event, Event * e) +{ + if (event == EVENT_IMMEDIATE) { + //////////////////////////////////////////////////////////////////// + // EVENT_IMMEDIATE -- URL list update + //////////////////////////////////////////////////////////////////// + + UpdateConfigList *l = NULL; + + l = BuildUpdateList(); + if (l) { + _CL = l; + } + return EVENT_DONE; + } + + if (event == EVENT_INTERVAL) { + //////////////////////////////////////////////////////////////////// + // EVENT_INTERVAL -- Global configuration update check + //////////////////////////////////////////////////////////////////// + + UpdateConfigParams *p = NEW(new UpdateConfigParams(*_CP_actual)); + + if (!(*_CP == *p)) { + _CP = p; + Debug("update", "enable %d force %d rcnt %d rint %d updates %d mem %d", + p->_enabled, p->_immediate_update, p->_retry_count, + p->_retry_interval, p->_concurrent_updates, p->_max_update_state_machines, p->_memory_use_in_mb); + } else { + delete p; + } + return EVENT_DONE; + } + // Unknown event, ignore it. + + Debug("update", "ProcessUpdate: Unknown event %d 0x%x", event, e); + return EVENT_DONE; +} + +UpdateConfigList * +UpdateConfigManager::BuildUpdateList() +{ + // Build pathname to "update.config" and open file + + char ConfigFilePath[PATH_NAME_MAX]; + if (_filename) { + ink_strncpy(ConfigFilePath, system_config_directory, sizeof(ConfigFilePath)); + strncat(ConfigFilePath, "/", sizeof(ConfigFilePath) - strlen(ConfigFilePath) - 1); + strncat(ConfigFilePath, _filename, sizeof(ConfigFilePath) - strlen(ConfigFilePath) - 1); + } else { + return (UpdateConfigList *) NULL; + } + +#ifdef _WIN32 + // O_BINARY to avoid translation of CR-LF + int fd = open(ConfigFilePath, O_RDONLY | O_BINARY); +#else + int fd = open(ConfigFilePath, O_RDONLY); +#endif + if (fd < 0) { + Warning("read update.config, open failed"); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, open failed"); + return (UpdateConfigList *) NULL; + } + return ParseConfigFile(fd); +} + +int +UpdateConfigManager::GetDataLine(int fd, int bufsize, char *buf, int field_delimiters, int delimiter) +{ + char *line = buf; + int linesize = bufsize; + int bytes_read = 0; + int rlen; + + while ((rlen = ink_file_fd_readline(fd, linesize, line)) > 0) { + //////////////////////////////////////////////////////////////////// + // Notes: + // 1) ink_file_fd_readline() null terminates returned buffer + // 2) Input processing guarantees that the item delimiter '\' + // does not exist in any data field. + //////////////////////////////////////////////////////////////////// + + // Just return data if we have a comment line + + if (!bytes_read && *line == '#') { + return rlen; + } + bytes_read += rlen; + + // Determine if we have a complete line. + + char *p = buf; + int delimiters_found = 0; + + while (*p) { + if (*p == delimiter) { + delimiters_found++; + } + p++; + } + if (delimiters_found == field_delimiters) { + // We have a complete line. + return bytes_read; + + } else if ((delimiters_found == (field_delimiters - 1)) + && (*(p - 1) == '\n')) { + // End of line not delimited. + // Fix it and consider it a complete line. + + *(p - 1) = '\\'; + return bytes_read; + } + // Resume read + line += rlen; + linesize -= rlen; + } + return 0; +} + +UpdateConfigList * +UpdateConfigManager::ParseConfigFile(int f) +{ + /* + "update.config" line syntax: + \\\\\ + */ + + enum + { F_URL, F_HEADERS, F_HOUR, F_INTERVAL, F_DEPTH, F_ITEMS }; + char *p_start[F_ITEMS]; + char *p_end[F_ITEMS]; + + char line[MAX_LINE_LENGTH]; + char *p; + + int ln = 0; + int i; + + UpdateEntry *e = NULL; + UpdateConfigList *ul = NEW(new UpdateConfigList); + + while (GetDataLine(f, sizeof(line) - 1, line, F_ITEMS, '\\') > 0) { + ++ln; + if (*line == '#') { + continue; + } else { + p = line; + } + + // Extract fields + + for (i = 0; i < F_ITEMS; ++i) { + p_start[i] = p; + p_end[i] = strchr(p, '\\'); + *p_end[i] = 0; // Null terminate string + + if (p_end[i]) { + p = p_end[i] + 1; + } else { + Warning("read update.config, invalid syntax, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, invalid syntax"); + break; + } + } + if (i < F_ITEMS) { + // Syntax error + goto abort_processing; + } + // Validate data fields + + e = NEW(new UpdateEntry); + + //////////////////////////////////// + // Validate URL + //////////////////////////////////// + if (e->ValidURL(p_start[F_URL], p_end[F_URL])) { + Warning("read update.config, invalid URL field, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, invalid URL field"); + goto abort_processing; + } + //////////////////////////////////// + // Validate headers + //////////////////////////////////// + if (e->ValidHeaders(p_start[F_HEADERS], p_end[F_HEADERS])) { + Warning("read update.config, invalid headers field, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, invalid headers field"); + goto abort_processing; + } + ///////////////////////////////////////////////////////////// + // Convert request (URL+Headers) into HTTPHdr format. + ///////////////////////////////////////////////////////////// + if (e->BuildHttpRequest()) { + Warning("read update.config, header processing error, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, header processing error"); + goto abort_processing; + } + //////////////////////////////////// + // Validate hour + //////////////////////////////////// + if (e->ValidHour(p_start[F_HOUR], p_end[F_HOUR])) { + Warning("read update.config, invalid hour field, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, invalid hour field"); + goto abort_processing; + } + //////////////////////////////////// + // Validate interval + //////////////////////////////////// + if (e->ValidInterval(p_start[F_INTERVAL], p_end[F_INTERVAL])) { + Warning("read update.config, invalid interval field, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, invalid interval field"); + goto abort_processing; + } + //////////////////////////////////// + // Validate recursion depth + //////////////////////////////////// + if (e->ValidDepth(p_start[F_DEPTH], p_end[F_DEPTH])) { + Warning("read update.config, invalid depth field, line %d", ln); + SignalWarning(MGMT_SIGNAL_CONFIG_ERROR, "read update.config, invalid depth field"); + goto abort_processing; + } + // Valid entry, add to list + + e->Init(); + Debug("update", + "[%d] [%s] [%s] nhdrs %d hour %d interval %d depth %d", + e->_id, e->_url, e->_request_headers, e->_num_request_headers, e->_offset_hour, e->_interval, e->_max_depth); + ul->Add(e); + e = NULL; + } + + // All file entries are valid. + + close(f); + return ul; + +abort_processing: + close(f); + if (e) { + delete e; + } + if (ul) { + delete ul; + } + return (UpdateConfigList *) NULL; +} + +///////////////////////////////////////////////////////////////////////////// +// Class UpdateScheduler +// Handle scheduling of UpdateEntry objects +///////////////////////////////////////////////////////////////////////////// +UpdateScheduler::UpdateScheduler(UpdateConfigManager * c) +:Continuation(new_ProxyMutex()), _periodic_event(0), +_recursive_update(0), _CM(c), _schedule_event_callbacks(0), _update_state_machines(0), _base_EN(0), _parent_US(0) +{ + SET_HANDLER((UpdateSchedulerContHandler) + & UpdateScheduler::ScheduleEvent); +} + +UpdateScheduler::~UpdateScheduler() +{ +} + +int +UpdateScheduler::Init() +{ + _recursive_update = 0; + _periodic_event = eventProcessor.schedule_every(this, HRTIME_SECONDS(10)); + return 0; +} + +int +UpdateScheduler::Init(UpdateScheduler * us, UpdateEntry * ue, Ptr p) +{ + ink_assert(ue->_indirect_list->Entries()); + + _recursive_update = 1; + _CP = p; + _CL = ue->_indirect_list; + _base_EN = ue; + _parent_US = us; + + // Schedule entries for update by moving entries to pending queue. + + UpdateEntry *e; + while ((e = _CL->Remove())) { + _CL->AddPending(e); + } + _periodic_event = eventProcessor.schedule_every(this, HRTIME_SECONDS(10)); + return 0; +} + +int +UpdateScheduler::ScheduleEvent(int event, void *e) +{ + UpdateEntry *ue = NULL; + int update_complete = 1; + + if (event == EVENT_IMMEDIATE) { + ////////////////////////////////////////////////////////////////////// + // Callback on update completion from Update State Machine + ////////////////////////////////////////////////////////////////////// + ue = (UpdateEntry *) e; + + switch (ue->_update_event_status) { + case UPDATE_EVENT_SUCCESS: + { + Debug("update", "%s update complete, UPDATE_EVENT_SUCCESS id: %d", (_recursive_update ? "(R)" : ""), ue->_id); + UPDATE_INCREMENT_DYN_STAT(update_successes_stat); + + if ((ue->_max_depth > 0) && ue->_indirect_list) { + if (ue->_indirect_list->Entries()) { + ////////////////////////////////////////////////////////// + // Recursive update case. + // At this point, we have a list of URLs which was + // recursively derived from the base URL. + // Instantiate UpdateScheduler to process this URL list. + ////////////////////////////////////////////////////////// + Debug("update", "Starting UpdateScheduler for id: %d [%s]", ue->_id, ue->_url); + UpdateScheduler *us = NEW(new UpdateScheduler()); + us->Init(this, ue, _CP); + update_complete = 0; + + } else { + ue->_indirect_list = NULL; + } + } + break; + } + case UPDATE_EVENT_SUCCESS_NOACTION: + { + Debug("update", + "%s update complete, UPDATE_EVENT_SUCCESS_NOACTION id: %d", (_recursive_update ? "(R)" : ""), ue->_id); + UPDATE_INCREMENT_DYN_STAT(update_no_actions_stat); + break; + } + case UPDATE_EVENT_FAILED: + { + Debug("update", "%s update complete, UPDATE_EVENT_FAILED id: %d", (_recursive_update ? "(R)" : ""), ue->_id); + UPDATE_INCREMENT_DYN_STAT(update_fails_stat); + break; + } + default: + { + Debug("update", + "%s update complete, unknown status %d, id: %d", + (_recursive_update ? "(R)" : ""), ue->_update_event_status, ue->_id); + UPDATE_INCREMENT_DYN_STAT(update_unknown_status_stat); + break; + } + } // End of switch + + if (update_complete) { + if (!_recursive_update) { + ///////////////////////////////////////////////////////// + // Recompute expire time and place entry back on list + ///////////////////////////////////////////////////////// + + ue->ComputeScheduleTime(); + _CL->Add(ue); // Place back on list + + } else { + delete ue; + } + --_update_state_machines; + UPDATE_DECREMENT_DYN_STAT(update_state_machines_stat); + } + //////////////////////////////////////////////////////////////// + // Start another update SM if scheduling is allowed + // and an entry exists on the pending list. + //////////////////////////////////////////////////////////////// + + if (Schedule() < 0) { + // Scheduling allowed, but nothing to schedule + if (_update_state_machines == 0) { + ////////////////////////////////////////////////////////////// + // No more active updates, deallocate config/entry structures + ////////////////////////////////////////////////////////////// + + _CP = NULL; + _CL = NULL; + + if (_recursive_update) { + // + // Recursive list update is now complete. + // Callback parent UpdateScheduler. + // + _periodic_event->cancel(); + _base_EN->_indirect_list = NULL; + _base_EN->_update_event_status = UPDATE_EVENT_SUCCESS; + + SET_HANDLER((UpdateSchedulerContHandler) + & UpdateScheduler::ChildExitEventHandler); + handleEvent(EVENT_IMMEDIATE, 0); + } + } + } + return EVENT_DONE; + } + ////////////////////////////////////// + // Periodic event callback + ////////////////////////////////////// + if (event == EVENT_INTERVAL) { + ++_schedule_event_callbacks; + } else { + // Unknown event, ignore it. + Debug("update", "UpdateScheduler::ScheduleEvent unknown event %d", event); + return EVENT_DONE; + } + + if (!_CP && !_CL) { + // No updates pending, attempt to schedule any expired updates + + if (!_CM->GetConfigParams(&_CP)) { + return EVENT_CONT; // Missed lock, try at next event + } + if (!_CM->GetConfigList(&_CL)) { + _CP = NULL; + return EVENT_CONT; // Missed lock, try at next event + } + // Cannot do anything unless we have valid params and list + + if (!_CP || !_CL) { + _CP = NULL; + _CL = NULL; + return EVENT_CONT; // try at next event + } + // Determine if the subsystem is enabled + + if (!_CP->IsEnabled()) { + _CP = NULL; + _CL = NULL; + return EVENT_CONT; // try at next event + } + + } else { + /////////////////////////////////////////////////////////////////// + // Updates pending from last schedule event, attempt to restart + // additional update SM(s). + /////////////////////////////////////////////////////////////////// + + Schedule(); + return EVENT_CONT; + } + ink_release_assert(!_update_state_machines); + + /////////////////////////////////////////////////////// + // Scan entry list and schedule expired updates + /////////////////////////////////////////////////////// + + ink_hrtime ht = ink_get_based_hrtime(); + time_t cur_time = ht / HRTIME_SECOND; + Queue no_action_q; + int time_expired; + + while ((ue = _CL->Remove())) { + time_expired = ue->ScheduleNow(cur_time); + if (time_expired || _CP->ImmediateUpdate()) { + if (Schedule(ue) > 0) { + Debug("update", "%s and started id: %d", time_expired ? "expired" : "force expire", ue->_id); + } else { + Debug("update", "%s with deferred start id: %d", time_expired ? "expired" : "force expire", ue->_id); + } + + } else { + no_action_q.enqueue(ue); + } + } + + // Place no_action_q elements back on list + + while ((ue = no_action_q.dequeue())) { + _CL->Add(ue); + } + + if (!_update_state_machines && !_CL->_pending_q.head) { + // Nothing active or pending. + // Drop references to config/param structures. + + _CP = NULL; + _CL = NULL; + } + return EVENT_DONE; +} + +int +UpdateScheduler::ChildExitEventHandler(int event, Event * e) +{ + NOWARN_UNUSED(e); + switch (event) { + case EVENT_IMMEDIATE: + case EVENT_INTERVAL: + { + MUTEX_TRY_LOCK(lock, _parent_US->mutex, this_ethread()); + if (lock) { + Debug("update", "Child UpdateScheduler exit id: %d", _base_EN->_id); + _parent_US->handleEvent(EVENT_IMMEDIATE, _base_EN); + delete this; + + } else { + // Lock miss, try again later. + eventProcessor.schedule_in(this, HRTIME_MSECONDS(10)); + } + break; + } + default: + { + ink_release_assert(!"UpdateScheduler::ChildExitEventHandler invalid event"); + } // End of case + } // End of switch + + return EVENT_DONE; +} + +int +UpdateScheduler::Schedule(UpdateEntry * e) +{ + // Return > 0, UpdateEntry scheduled + // Return == 0, Scheduling not allowed + // Return < 0, Scheduling allowed, but nothing to schedule + + UpdateSM *usm; + UpdateEntry *ue = e; + int allow_schedule; + RecInt count, sum; + int max_concurrent_updates; + + UPDATE_READ_DYN_STAT(update_state_machines_stat, count, sum); + if (_CP->ConcurrentUpdates() < _CP->MaxUpdateSM()) { + max_concurrent_updates = _CP->ConcurrentUpdates(); + } else { + max_concurrent_updates = _CP->MaxUpdateSM(); + } + allow_schedule = (sum < max_concurrent_updates); + + if (allow_schedule) { + ue = ue ? ue : _CL->RemovePending(); + if (ue) { + ++_update_state_machines; + UPDATE_INCREMENT_DYN_STAT(update_state_machines_stat); + usm = NEW(new UpdateSM(this, _CP, ue)); + usm->Start(); + + Debug("update", "%s %s start update id: %d [%s]", + (_recursive_update ? "(R)" : ""), (e ? "directed" : "speculative"), ue->_id, ue->_url); + + return 1; // UpdateEntry scheduled + } else { + return -1; // Scheduling allowed but nothing to schedule + } + + } else { + if (ue) { + _CL->AddPending(ue); + } + return 0; // Scheduling not allowed + } +} + +///////////////////////////////////////////////////////////////////////////// +// Class UpdateSM +// State machine which handles object update action +///////////////////////////////////////////////////////////////////////////// +UpdateSM::UpdateSM(UpdateScheduler * us, Ptr p, UpdateEntry * e) +:Continuation(new_ProxyMutex()), _state(USM_INIT), _return_status(0), _retries(0) +{ + SET_HANDLER((UpdateSMContHandler) & UpdateSM::HandleSMEvent); + _US = us; + _CP = p; + _EN = e; +} + +UpdateSM::~UpdateSM() +{ + _CP = NULL; // drop reference +} + +void +UpdateSM::Start() +{ + eventProcessor.schedule_imm(this, ET_CACHE); +} + +int +UpdateSM::HandleSMEvent(int event, Event * e) +{ + NOWARN_UNUSED(e); + while (1) { + switch (_state) { + case USM_INIT: + { + //////////////////////////////////////////////////////////////////// + // Cluster considerations. + // For non-recursive URL(s), only process it if the cluster + // hash returns this node. Recursive URL(s) are processed by + // all nodes in the cluster. + //////////////////////////////////////////////////////////////////// + if (_EN->_max_depth > 0) { + // Recursive URL(s) are processed by all nodes. + _state = USM_PROCESS_URL; + break; + } + + INK_MD5 url_md5; + Cache::generate_key(&url_md5, &_EN->_URLhandle, (_EN->_num_request_headers ? _EN->_http_hdr : NULL)); + Cache::generate_key(&url_md5, &_EN->_URLhandle, _EN->_http_hdr); + ClusterMachine *m = cluster_machine_at_depth(cache_hash(url_md5)); + if (m) { + // URL hashed to remote node, do nothing. + _state = USM_EXIT; + _EN->_update_event_status = UPDATE_EVENT_SUCCESS_NOACTION; + break; + } else { + // URL hashed to local node, start processing. + _state = USM_PROCESS_URL; + break; + } + } + case USM_PROCESS_URL: + { + /////////////////////////////////// + // Dispatch to target handler + /////////////////////////////////// + int n; + int scheme_len; + const char *scheme; + _state = USM_PROCESS_URL_COMPLETION; + scheme = _EN->_URLhandle.scheme_get(&scheme_len); + for (n = 0; n < N_SCHEMES; ++n) { + if (scheme == *scheme_dispatch_table[n].scheme) { + _EN->_scheme_index = n; + if ((*scheme_dispatch_table[n].func) (this)) { + break; // Error in initiation + } + return EVENT_CONT; + } + } + // Error in initiation or bad scheme. + + _state = USM_EXIT; + _EN->_update_event_status = UPDATE_EVENT_FAILED; + break; + } + case USM_PROCESS_URL_COMPLETION: + { + /////////////////////////////////// + // Await URL update completion + /////////////////////////////////// + _state = USM_EXIT; + _EN->_update_event_status = event; + (*scheme_post_dispatch_table[_EN->_scheme_index].func) (this); + break; + } + case USM_EXIT: + { + ///////////////////////////////////////////// + // Operation complete + ///////////////////////////////////////////// + if ((_return_status == UPDATE_EVENT_FAILED) + && (_retries < _CP->RetryCount())) { + + // Retry operation + + ++_retries; + _state = USM_PROCESS_URL; + eventProcessor.schedule_in(this, HRTIME_SECONDS(_CP->RetryInterval()), ET_CACHE); + return EVENT_DONE; + + } else { + MUTEX_TRY_LOCK(lock, _US->mutex, this_ethread()); + if (lock) { + _US->handleEvent(EVENT_IMMEDIATE, (void *) _EN); + delete this; + return EVENT_DONE; + + } else { + // Missed lock, try again later + eventProcessor.schedule_in(this, HRTIME_MSECONDS(10), ET_CACHE); + return EVENT_CONT; + } + } + } + } // End of switch + } // End of while + + return EVENT_CONT; +} + +struct dispatch_entry scheme_dispatch_table[UpdateSM::N_SCHEMES] = { + {&URL_SCHEME_HTTP, UpdateSM::http_scheme}, +}; + +struct dispatch_entry scheme_post_dispatch_table[UpdateSM::N_SCHEMES] = { + {&URL_SCHEME_HTTP, UpdateSM::http_scheme_postproc}, +}; + +int +UpdateSM::http_scheme(UpdateSM * sm) +{ + if (sm->_EN->_max_depth > 0) { + //////////////////////////////////// + // Recursive Update + //////////////////////////////////// + Debug("update", "Start recursive HTTP GET id: %d [%s]", sm->_EN->_id, sm->_EN->_url); + sm->_EN->_indirect_list = NEW(new UpdateConfigList); + RecursiveHttpGet *RHttpGet = NEW(new RecursiveHttpGet); + + RHttpGet->Init(sm, sm->_EN->_url, sm->_EN->_request_headers, + &sm->_EN->_URLhandle, sm->_EN->_http_hdr, + sm->_EN->_max_depth, sm->_EN->_indirect_list, &update_allowable_html_tags[0]); + } else { + //////////////////////////////////// + // One URL update + //////////////////////////////////// + Debug("update", "Start HTTP GET id: %d [%s]", sm->_EN->_id, sm->_EN->_url); + HttpUpdateSM *current_reader; + + current_reader = HttpUpdateSM::allocate(); + current_reader->init(); + // TODO: Do anything with the returned Action* ? + current_reader->start_scheduled_update(sm, sm->_EN->_http_hdr); + } + return 0; +} + +int +UpdateSM::http_scheme_postproc(UpdateSM * sm) +{ + // Map HttpUpdateSM return event code to internal status code + + switch (sm->_EN->_update_event_status) { + case UPDATE_EVENT_SUCCESS: + case UPDATE_EVENT_FAILED: + // Returned only by RecursiveHttpGet + sm->_return_status = sm->_EN->_update_event_status; + break; + + case HTTP_SCH_UPDATE_EVENT_WRITTEN: + case HTTP_SCH_UPDATE_EVENT_UPDATED: + case HTTP_SCH_UPDATE_EVENT_DELETED: + case HTTP_SCH_UPDATE_EVENT_NOT_CACHED: + case HTTP_SCH_UPDATE_EVENT_NO_ACTION: + sm->_EN->_update_event_status = UPDATE_EVENT_SUCCESS; + sm->_return_status = UPDATE_EVENT_SUCCESS; + break; + + case HTTP_SCH_UPDATE_EVENT_ERROR: + default: + sm->_EN->_update_event_status = UPDATE_EVENT_FAILED; + sm->_return_status = UPDATE_EVENT_FAILED; + break; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////// +// Class RecursiveHttpGet +// Generate URL list by recursively traversing non-terminal URL(s) +// up to the specified depth. +///////////////////////////////////////////////////////////////////////////// +char + HtmlParser::default_zero_char = '\0'; + +RecursiveHttpGet::RecursiveHttpGet() +:Continuation(new_ProxyMutex()), _id(0), _caller_cont(0), +_request_headers(0), _http_hdr(0), _recursion_depth(0), _OL(0), _group_link_head(0), _active_child_state_machines(0) +{ + SET_HANDLER((RecursiveHttpGetContHandler) + & RecursiveHttpGet::RecursiveHttpGetEvent); +} + +RecursiveHttpGet::~RecursiveHttpGet() +{ + _CL = NULL; +} + +void +RecursiveHttpGet::Init(Continuation * cont, char *url, char *request_headers, + URL * url_data, HTTPHdr * http_hdr, int recursion_depth, + Ptr L, struct html_tag *allowed_html_tags) +{ + ///////////////////////////////////////////////////////////////////////// + // Note: URL and request header data pointers are assumed to be + // valid during the life of this class. + ///////////////////////////////////////////////////////////////////////// + _id = ink_atomic_increment(&global_id, 1); + _caller_cont = cont; + _request_headers = request_headers; + _url_data = url_data; + _http_hdr = http_hdr; + _recursion_depth = recursion_depth; + _CL = L; + _OL = ObjectReloadContAllocator.alloc(); + _OL->Init(this, url, strlen(url), _request_headers, (_request_headers ? strlen(_request_headers) : 0), 1, 1); + + html_parser.Init(url, allowed_html_tags); + + Debug("update", "Start recursive read rid: %d [%s]", _id, html_parser._url); +} + +int +RecursiveHttpGet::RecursiveHttpGetEvent(int event, Event * d) +{ + char *url, *url_end; + int status; + UpdateEntry *ue; + IOBufferReader *r = (IOBufferReader *) d; + + switch (event) { + case NET_EVENT_OPEN_FAILED: + { + Debug("update", "RecursiveHttpGetEvent connect failed id: %d [%s]", _id, html_parser._url); + break; + } + case VC_EVENT_ERROR: + { + Debug("update", "RecursiveHttpGetEvent connect event error id: %d [%s]", _id, html_parser._url); + break; + } + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + { + while ((status = html_parser.ParseHtml(r, &url, &url_end))) { + // Validate given URL. + + ue = NEW(new UpdateEntry); + if (ue->ValidURL(url, url_end + 1 /* Point to null */ )) { + delete ue; + ue = NULL; + + } else { + // Complete remaining UpdateEntry initializations + + ue->_request_headers = xstrdup(_request_headers); + ue->BuildHttpRequest(); + ue->Init(1); // Derived URL + + // Discard remote URL(s) + int ue_host_len; + const char *ue_host = ue->_URLhandle.host_get(&ue_host_len); + int url_host_len; + const char *url_host = _url_data->host_get(&url_host_len); + + if (ue_host == NULL || url_host == NULL || ptr_len_casecmp(ue_host, ue_host_len, url_host, url_host_len)) { + delete ue; + ue = NULL; + continue; + } + // I think we're generating the cache key just to get + // a hash of the URL. Used to use Cache::generate_key + // that no longer works with vary_on_user_agent + // isn't turned on +// Cache::generate_key(&ue->_url_md5, &ue->_URLhandle, _http_hdr); + ue->_URLhandle.MD5_get(&ue->_url_md5); + + if (_CL->HashAdd(ue)) { + // Entry already exists + + delete ue; + ue = NULL; + + } else { + // Entry is unique and has been added to hash table. + // Set terminal URL status and add to current + // recursion level list. + + ue->SetTerminalStatus(((status < 0) ? 1 : 0)); + Debug("update", "Recursive find rid: %d id: %d %s\n [%s]", + _id, ue->_id, (ue->TerminalURL()? "T " : ""), ue->_url); + + if (_group_link_head) { + ue->_group_link = _group_link_head; + _group_link_head = ue; + } else { + _group_link_head = ue; + ue->_group_link = NULL; + } + } + } + } + ink_release_assert(r->read_avail() == 0); + + if ((event == VC_EVENT_READ_COMPLETE) + || (event == VC_EVENT_EOS)) { + break; + + } else { + return EVENT_CONT; + } + } + case UPDATE_EVENT_SUCCESS: + case UPDATE_EVENT_FAILED: + { + // Child state machine completed. + + ink_release_assert(_active_child_state_machines > 0); + _active_child_state_machines--; + break; + } + default: + { + ink_release_assert(!"RecursiveHttpGetEvent invalid event"); + return EVENT_DONE; + + } // End of case + } // End of switch + + if (_group_link_head) { + // At this point, we have a list of valid terminal + // and non-terminal URL(s). + // Sequentially initiate the read on the non-terminal URL(s). + + while (_group_link_head) { + ue = _group_link_head; + _group_link_head = ue->_group_link; + + if (!ue->TerminalURL()) { + if (_recursion_depth <= 1) { + continue; + } + + Debug("update", "(R) start non-terminal HTTP GET rid: %d id: %d [%s]", _id, ue->_id, ue->_url); + + _active_child_state_machines++; + RecursiveHttpGet *RHttpGet = NEW(new RecursiveHttpGet()); + RHttpGet->Init(this, ue->_url, _request_headers, + _url_data, _http_hdr, (_recursion_depth - 1), _CL, &update_allowable_html_tags[0]); + return EVENT_CONT; + + } + } + } + // All child state machines have completed, tell our parent + // and delete ourself. + + SET_HANDLER((RecursiveHttpGetContHandler) + & RecursiveHttpGet::ExitEventHandler); + handleEvent(EVENT_IMMEDIATE, 0); + return EVENT_DONE; +} + +int +RecursiveHttpGet::ExitEventHandler(int event, Event * e) +{ + NOWARN_UNUSED(e); + switch (event) { + case EVENT_IMMEDIATE: + case EVENT_INTERVAL: + { + MUTEX_TRY_LOCK(lock, _caller_cont->mutex, this_ethread()); + if (lock) { + Debug("update", "Exiting recursive read rid: %d [%s]", _id, html_parser._url); + _caller_cont->handleEvent(UPDATE_EVENT_SUCCESS, 0); + delete this; + + } else { + // Lock miss, try again later. + eventProcessor.schedule_in(this, HRTIME_MSECONDS(10)); + } + break; + } + default: + { + ink_release_assert(!"RecursiveHttpGet::ExitEventHandler invalid event"); + } // End of case + } // End of switch + + return EVENT_DONE; +} + +int +HtmlParser::ParseHtml(IOBufferReader * r, char **url, char **url_end) +{ + int status; + while (1) { + if ((status = ScanHtmlForURL(r, url, url_end))) { + status = ConstructURL(url, url_end); + if (status) + return status; + } else { + return 0; // No more bytes + } + } +} + +int +HtmlParser::ScanHtmlForURL(IOBufferReader * r, char **url, char **url_end) +{ + unsigned char c; + int n = 0; + + while (1) { + switch (_scan_state) { + case SCAN_INIT: + { + _tag.clear(); + + _attr.clear(); + _attr_value.clear(); + _attr_value_hash_char_index = -1; + _attr_value_quoted = 0; + _attr_matched = false; + + _scan_state = SCAN_START; + n = -1; + break; + } + case SCAN_START: + { + while ((n = r->read((char *) &c, 1))) { + if (c == '<') { + _scan_state = FIND_TAG_START; + break; + } + } + break; + } + case FIND_TAG_START: + { + while ((n = r->read((char *) &c, 1))) { + if (!isspace(c)) { + if (c == '>') { + //////////////////////////////////////////////////// + // '< >' with >= 0 embedded spaces, ignore it. + //////////////////////////////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else { + _tag(_tag.length()) = c; + _scan_state = COPY_TAG; + break; + } + } + } + break; + } + case COPY_TAG: + { + while ((n = r->read((char *) &c, 1))) { + if (!isspace(c)) { + if (c == '>') { + ///////////////////////////// + // , ignore it + ///////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else if (c == '=') { + /////////////////////////////// + // , ignore it + /////////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else { + if (_tag.length() < MAX_TAG_NAME_LENGTH) { + _tag(_tag.length()) = c; + + } else { + /////////////////////////////////// + // Tag name to long, ignore it + /////////////////////////////////// + _scan_state = SCAN_INIT; + break; + } + } + + } else { + _tag(_tag.length()) = 0; + if (strcmp(_tag, HTML_COMMENT_TAG) == 0) { + _scan_state = IGNORE_COMMENT_START; + } else { + _scan_state = FIND_ATTR_START; + } + break; + } + } + break; + } + case IGNORE_COMMENT_START: + { + _comment_end_ptr = (char *) HTML_COMMENT_END; + _scan_state = IGNORE_COMMENT; + break; + } + case IGNORE_COMMENT: + { + while ((n = r->read((char *) &c, 1))) { + if (!isspace(c)) { + if (c == *_comment_end_ptr) { + _comment_end_ptr++; + if (!*_comment_end_ptr) { + _scan_state = SCAN_INIT; + break; + } + } else { + _comment_end_ptr = (char *) HTML_COMMENT_END; + } + } + } + break; + } + case FIND_ATTR_START: + { + while ((n = r->read((char *) &c, 1))) { + if (!isspace(c)) { + if (c == '>') { + //////////////////////////////////////////////// + // with >=1 embedded spaces, ignore it + //////////////////////////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else if (c == '=') { + ////////////////////////////////////////////////////////// + // with >=1 embedded spaces, ignore it + ////////////////////////////////////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else { + _attr(_attr.length()) = c; + _scan_state = COPY_ATTR; + break; + } + } + } + break; + } + case COPY_ATTR: + { + while ((n = r->read((char *) &c, 1))) { + if (!isspace(c)) { + if (c == '>') { + ///////////////////////////// + // , ignore it + ///////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else if (c == '=') { + /////////////////////////////// + // + /////////////////////////////// + _attr(_attr.length()) = 0; + _scan_state = FIND_ATTR_VALUE_START; + break; + + } else { + if (_attr.length() < MAX_ATTR_NAME_LENGTH) { + _attr(_attr.length()) = c; + + } else { + /////////////////////////////////// + // Attr name to long, ignore it + /////////////////////////////////// + _scan_state = SCAN_INIT; + break; + } + } + + } else { + _attr(_attr.length()) = 0; + _scan_state = FIND_ATTR_VALUE_DELIMITER; + break; + } + } + break; + } + case FIND_ATTR_VALUE_DELIMITER: + { + while ((n = r->read((char *) &c, 1))) { + if (isspace(c) || (c == '=')) { + if (c == '=') { + _scan_state = FIND_ATTR_VALUE_START; + break; + } + } else { + _scan_state = SCAN_INIT; + break; + } + } + break; + } + case FIND_ATTR_VALUE_START: + { + while ((n = r->read((char *) &c, 1))) { + if (!isspace(c)) { + if (c == '>') { + ///////////////////////////// + // , ignore + ///////////////////////////// + _scan_state = SCAN_INIT; + break; + + } else if ((c == '\'') || (c == '\"')) { + _attr_value_quoted = c; + _scan_state = COPY_ATTR_VALUE; + break; + + } else { + _attr_value_quoted = 0; + _attr_value(_attr_value.length()) = c; + _scan_state = COPY_ATTR_VALUE; + break; + } + } + } + break; + } + case COPY_ATTR_VALUE: + { + while ((n = r->read((char *) &c, 1))) { + if (_attr_value_quoted) { + if (c == _attr_value_quoted) { + /////////////////////////////////////////// + // We have a complete ') { + ///////////////////////////////////////// + // We have a complete + ///////////////////////////////////////// + _attr_value(_attr_value.length()) = 0; + _scan_state = VALIDATE_ENTRY_RESTART; + break; + + } else { + _attr_value(_attr_value.length()) = c; + if (c == '#') { + _attr_value_hash_char_index = _attr_value.length() - 1; + } + } + } + } + break; + } + case VALIDATE_ENTRY: + case VALIDATE_ENTRY_RESTART: + { + if (_scan_state == VALIDATE_ENTRY) { + _scan_state = RESUME_ATTR_VALUE_SCAN; + } else { + _scan_state = SCAN_INIT; + } + if (AllowTagAttrValue()) { + if (ExtractURL(url, url_end)) { + return 1; // valid URL + } + } + break; // resume scan + } + case RESUME_ATTR_VALUE_SCAN: + { + _attr.clear(); + _attr_value.clear(); + _attr_value_hash_char_index = -1; + _attr_value_quoted = 0; + + _scan_state = FIND_ATTR_START; + n = -2; + break; + } + case TERMINATE_COPY_ATTR_VALUE: + { + while ((n = r->read((char *) &c, 1))) { + if (c == _attr_value_quoted) { + _scan_state = RESUME_ATTR_VALUE_SCAN; + break; + } + } + break; + } + default: + { + ink_release_assert(!"HtmlParser::ScanHtmlForURL bad state"); + } + } // end of switch + + if (n == 0) { + return 0; // No more data + } + + } // end of while +} + +int +HtmlParser::AllowTagAttrValue() +{ + struct html_tag *p_tag = allowable_html_tags; + struct html_tag *p_attr = allowable_html_attrs; + + if (!_tag || !_attr) + return 0; + + while (p_tag->tag && p_tag->attr) { + if (!strcasecmp(_tag, p_tag->tag) + && !strcasecmp(_attr, p_tag->attr)) { + if (p_attr == NULL || p_attr->tag == NULL) + return 1; + else if (_attr_matched) { + return 1; + } else { + // attributes don't match + return 0; + } + } else { + if (p_attr && p_attr->tag && p_attr->attr && _attr_value.length() > 0) { + if (!strcasecmp(_attr, p_attr->tag) + && !strcasecmp(_attr_value, p_attr->attr)) { + _attr_matched = true; + } + } + p_tag++; + if (p_attr) + p_attr++; + } + } + return 0; +} + +int +HtmlParser::ValidProtoScheme(char *p) +{ + int n; + for (n = 0; proto_schemes[n].tag; ++n) { + if (!strncasecmp(p, proto_schemes[n].tag, proto_schemes[n].tag_len)) { + return 1; + } + } + return 0; +} + +int +HtmlParser::ValidSupportedProtoScheme(char *p) +{ + int n; + for (n = 0; supported_proto_schemes[n].tag; ++n) { + if (!strncasecmp(p, supported_proto_schemes[n].tag, supported_proto_schemes[n].tag_len)) { + return 1; + } + } + return 0; +} + +int +HtmlParser::ExtractURL(char **url, char **url_end) +{ + intptr_t n; + + // '#' considerations + if (_attr_value_hash_char_index >= 0) { + if (!_attr_value_hash_char_index) { + return 0; // No URL + + } else { + // '#' terminates _attr_value + _attr_value.set_length(_attr_value_hash_char_index + 1); + _attr_value[_attr_value_hash_char_index] = 0; + } + } + + if (!strcasecmp(_tag, "base") && !strcasecmp(_attr, "href")) { + if (_html_doc_base) { + _html_doc_base.clear(); + } + for (n = 0; n < _attr_value.length(); ++n) { + _html_doc_base(_html_doc_base.length()) = _attr_value[n]; + } + _html_doc_base(_html_doc_base.length()) = 0; + return 0; // No URL + + } else if (!strcasecmp(_tag, "meta") && !strcasecmp(_attr, "content")) { + ///////////////////////////////////////////////////////////////// + // General form: + // + ///////////////////////////////////////////////////////////////// + if (_attr_value.length()) { + // Locate start of URL + for (n = 0; n < _attr_value.length(); ++n) { + if (!ParseRules::is_digit((unsigned char) _attr_value[n])) { + break; + } + } + if ((n < _attr_value.length()) && (((unsigned char) _attr_value[n]) == ';')) { + + for (; n < _attr_value.length(); ++n) { + if (!isspace((unsigned char) _attr_value[n])) { + break; + } + } + if ((n < _attr_value.length()) && (!strncasecmp(&_attr_value[n], "URL=", 4))) { + n += 4; + if ((n < _attr_value.length()) + && ((_attr_value.length() - n) > 1)) { + *url = &_attr_value[n]; + *url_end = &_attr_value[_attr_value.length() - 2]; + return 1; + } + } + } + return 0; // No URL + + } else { + return 0; // No URL + } + } + + if (_attr_value.length() > 1) { + *url = &_attr_value[(intptr_t)0]; + *url_end = &_attr_value[_attr_value.length() - 2]; + return 1; + + } else { + return 0; // No URL + } +} + +int +HtmlParser::ConstructURL(char **url, char **url_end) +{ + unsigned char *p_url = (unsigned char *) *url; + unsigned char *p_url_end = (unsigned char *) *url_end; + + ///////////////////////////////////////////////////////////////////// + // Handle the case by skipping over spaces + ///////////////////////////////////////////////////////////////////// + while (p_url < p_url_end) { + if (isspace(*p_url)) { + ++p_url; + } else { + break; + } + } + + //////////////////////////////////////////////////// + // Determine if we have a relative or absolute URI + //////////////////////////////////////////////////// + int relative_URL = 0; + int http_needed = 0; + if (ValidProtoScheme((char *) p_url)) { + if (!strncasecmp((char *) p_url, "http:", 5) + && (strncasecmp((char *) p_url, "http://", 7) != 0)) { + + ////////////////////////////////////////////////////////// + // Bad relative URI references of the form http:URL. + // Skip over the "http:" part. + ////////////////////////////////////////////////////////// + p_url += strlen("http:"); + if (p_url > p_url_end) { + return 0; // Invalid URL + } + relative_URL = 1; + } + } else { + relative_URL = 1; + // problem found with www.slashdot.com + if (strncasecmp((char *) p_url, "//", 2) == 0) + http_needed = 1; + } + + ////////////////////////////////////////////// + // Only handle supported protocol schemes + ////////////////////////////////////////////// + if (!relative_URL && !ValidSupportedProtoScheme((char *) p_url)) { + return 0; // Invalid URL + } + + if (relative_URL) { + //////////////////////////////////// + // Compute document base path + //////////////////////////////////// + DynArray*base = 0; + DynArray*absolute_url = 0; + + if (http_needed) { + absolute_url = PrependString("http:", 5, (char *) p_url, (p_url_end - p_url + 2)); + } else if (_html_doc_base.length()) { + /////////////////////////////////////////////////////////////// + // Document base specified via + /////////////////////////////////////////////////////////////// + base = MakeURL(_url, _html_doc_base, _html_doc_base.length(), !ValidProtoScheme(_html_doc_base)); + absolute_url = MakeURL(*base, (char *) p_url, (p_url_end - p_url + 2), 1); + } else { + absolute_url = MakeURL(_url, (char *) p_url, (p_url_end - p_url + 2), 1); + } + _result.clear(); + _result = *absolute_url; + absolute_url->detach(); + + // fix INKqa07208; need to reclaim memory + delete absolute_url; + if (base) + delete base; + + *url = &_result[(intptr_t)0]; + *url_end = &_result[_result.length() - 3]; // -1 (real len) + // -1 (skip null) + // -1 (zero base) + } else { + *url = (char *) p_url; + *url_end = (char *) p_url_end; + } + + ////////////////////////////////////////////////////////////////// + // Determine if we have a terminal or non-terminal URL. + // URL ending with '/', .htm or .html is considered non-terminal. + // Return < 0 ==> Terminal URL + // Return > 0 ==> Non terminal URL + ////////////////////////////////////////////////////////////////// + if (!strncasecmp((char *) (p_url_end - 4), ".html", 5) + || !strncasecmp((char *) (p_url_end - 3), ".htm", 4) + || !strncasecmp((char *) (p_url_end), "/", 1)) { + return 1; // Non-terminal URL + } else { + return -1; // Terminal URL + } +} + +DynArray* +HtmlParser::MakeURL(char *url, char *sub, int subsize, int relative_url) +{ + int i, n; + int skip_slashslash; + + DynArray*result = NEW(new DynArray(&default_zero_char, 128)); + + if (relative_url) { + if (*sub != '/') { + + int url_len = strlen(url); + + // Locate last '/' in url + for (i = url_len; i && url[i] != '/'; i--); + + if (i && (url[i] == url[i - 1])) { + // http://hostname case with no terminating '/' + + for (n = 0; n < url_len; ++n) { + (*result) (result->length()) = url[n]; + } + (*result) (result->length()) = '/'; + + } else { + for (n = 0; n < (i + 1); ++n) { + (*result) (result->length()) = url[n]; + } + } + + for (n = 0; n < subsize; ++n) { + (*result) (result->length()) = sub[n]; + } + (*result) (result->length()) = '\0'; + + } else { + i = 0; + do { + // Locate leading '/' + for (; url[i] && url[i] != '/'; i++); + + if (!url[i]) { + break; + } + // Skip over '://' + skip_slashslash = ((url[i] == url[i + 1]) && (url[i + 1] == '/')); + + if (skip_slashslash) { + i += 2; + } + } while (skip_slashslash); + + for (n = 0; n < (i - 1); ++n) { + (*result) (result->length()) = url[n]; + } + + if (url[n] != '/') { + (*result) (result->length()) = url[n]; + } + + for (n = 0; n < subsize; ++n) { + (*result) (result->length()) = sub[n]; + } + (*result) (result->length()) = '\0'; + } + + } else { + for (n = 0; n < subsize; ++n) { + (*result) (result->length()) = sub[n]; + } + (*result) (result->length()) = '\0'; + } + return result; +} + +DynArray* +HtmlParser::PrependString(const char *pre, int presize, char *sub, int subsize) +{ + int n; + + DynArray*result = NEW(new DynArray(&default_zero_char, 128)); + + for (n = 0; n < presize; ++n) { + (*result) (result->length()) = pre[n]; + } + for (n = 0; n < subsize; ++n) { + (*result) (result->length()) = sub[n]; + } + (*result) (result->length()) = '\0'; + + return result; +} + +/////////////////////////////////////////////////////////////////// +// Class ObjectReloadCont +// Background load URL into local cache +/////////////////////////////////////////////////////////////////// +ClassAllocator ObjectReloadContAllocator("ObjectReloadCont"); + +ObjectReloadCont::ObjectReloadCont():Continuation(0), +_caller_cont(0), _request_id(0), _send_data(0), +_receive_data(0), _start_event(0), +_state(START), _cur_action(0), _netvc(0), _write_vio(0), _read_vio(0), _read_event_callback(0) +{ + SET_HANDLER((ObjectReloadContHandler) & ObjectReloadCont::ObjectReloadEvent); +} + +ObjectReloadCont::~ObjectReloadCont() +{ +} + +void +ObjectReloadCont::Init(Continuation * cont, char *url, int url_len, + char *headers, int headers_len, int http_case, int read_event_callback) +{ + int total_len; + + mutex = new_ProxyMutex(); + _caller_cont = cont; + _request_id = ink_atomic_increment(&global_id, 1); + _read_event_callback = read_event_callback; + + // Setup send data buffer by prepending the HTTP GET method to the + // given NULL terminated URL and terminating with HTTP version + + if (http_case) { + if (headers_len) { + total_len = len_GET_METHOD + url_len + len_HTTP_VERSION + len_TERMINATOR + headers_len + len_REQUEST_TERMINATOR; + } else { + total_len = len_GET_METHOD + url_len + len_HTTP_VERSION + len_REQUEST_TERMINATOR; + } + _send_data = new_MIOBuffer(buffer_size_to_index(total_len + 1)); // allow for NULL + + memcpy(_send_data->end(), GET_METHOD, len_GET_METHOD); + memcpy(&(_send_data->end())[len_GET_METHOD], url, url_len); + memcpy(&(_send_data->end())[len_GET_METHOD + url_len], HTTP_VERSION, len_HTTP_VERSION); + + if (headers_len) { + memcpy(&(_send_data->end())[len_GET_METHOD + url_len + len_HTTP_VERSION], TERMINATOR, len_TERMINATOR); + memcpy(&(_send_data->end())[len_GET_METHOD + url_len + len_HTTP_VERSION + len_TERMINATOR], headers, headers_len); + memcpy(&(_send_data->end())[len_GET_METHOD + url_len + + len_HTTP_VERSION + len_TERMINATOR + + headers_len], REQUEST_TERMINATOR, len_REQUEST_TERMINATOR); + + // Add NULL for Debug URL output + (_send_data->end())[len_GET_METHOD + url_len + + len_HTTP_VERSION + len_TERMINATOR + headers_len + len_REQUEST_TERMINATOR] = 0; + } else { + memcpy(&(_send_data->end())[len_GET_METHOD + url_len + + len_HTTP_VERSION], REQUEST_TERMINATOR, len_REQUEST_TERMINATOR); + + // Add NULL for Debug URL output + (_send_data->end())[len_GET_METHOD + url_len + len_HTTP_VERSION + len_REQUEST_TERMINATOR] = 0; + } + _send_data->fill(total_len); + + } else { + // Unhandled case... TODO: Do we need to actually handle this? + ink_debug_assert(false); + } + handleEvent(EVENT_IMMEDIATE, (void *) NULL); +} + +void +ObjectReloadCont::free() +{ + mutex = 0; + if (_send_data) { + free_MIOBuffer(_send_data); + _send_data = 0; + } + if (_receive_data) { + free_MIOBuffer(_receive_data); + _receive_data = 0; + } +} + +int +ObjectReloadCont::ObjectReloadEvent(int event, void *d) +{ + switch (_state) { + case START: + { + // Schedule connect to localhost: + Debug("update-reload", "Connect start id=%d", _request_id); + _state = ObjectReloadCont::ATTEMPT_CONNECT; + MUTEX_TRY_LOCK(lock, this->mutex, this_ethread()); + ink_release_assert(lock); + _cur_action = netProcessor.connect_re(this, inet_addr("127.0.0.1"), local_http_server_port); + return EVENT_DONE; + } + case ATTEMPT_CONNECT: + { + if (event != NET_EVENT_OPEN) { + // Connect error, terminate processing + Debug("update-reload", "Connect fail id=%d", _request_id); + CallBackUser(event, 0); + free(); + ObjectReloadContAllocator.free(this); + return EVENT_DONE; + } + _netvc = (class NetVConnection *) d; + + // Start URL write + Debug("update-reload", "Write start id=%d [%s]", _request_id, _send_data->start()); + _state = ObjectReloadCont::WRITING_URL; + IOBufferReader *r = _send_data->alloc_reader(); + _write_vio = _netvc->do_io_write(this, r->read_avail(), r); + return EVENT_DONE; + } + case WRITING_URL: + { + ink_release_assert(_write_vio == (VIO *) d); + if (event == VC_EVENT_WRITE_READY) { + _write_vio->reenable(); + return EVENT_DONE; + } else if (event == VC_EVENT_WRITE_COMPLETE) { + // Write successful, start read + Debug("update-reload", "Read start id=%d", _request_id); + _state = ObjectReloadCont::READING_DATA; + _receive_data = new_MIOBuffer(max_iobuffer_size); + _receive_data_reader = _receive_data->alloc_reader(); + _read_vio = _netvc->do_io_read(this, INT64_MAX, _receive_data); + return EVENT_DONE; + } else { + // Write error, terminate processing + Debug("update-reload", "Write fail id=%d", _request_id); + _netvc->do_io(VIO::CLOSE); + CallBackUser(event, 0); + free(); + ObjectReloadContAllocator.free(this); + return EVENT_DONE; + } + } + case READING_DATA: + { + ink_release_assert(_read_vio == (VIO *) d); + switch (event) { + case VC_EVENT_READ_READY: + { + if (_read_event_callback) { + _caller_cont->handleEvent(event, _receive_data_reader); + + } else { + int64_t read_bytes = _receive_data_reader->read_avail(); + _receive_data_reader->consume(read_bytes); + _read_vio->reenable(); + } + return EVENT_CONT; + } + case VC_EVENT_READ_COMPLETE: + case VC_EVENT_EOS: + { + if (_read_event_callback) { + _caller_cont->handleEvent(event, _receive_data_reader); + } + // Object injected into local cache + Debug("update-reload", "Fill success id=%d", _request_id); + break; + } + default: + { + Debug("update-reload", "Fill read fail id=%d", _request_id); + CallBackUser(event, 0); + break; + } + } // End of switch + + _netvc->do_io(VIO::CLOSE); + free(); + ObjectReloadContAllocator.free(this); + return EVENT_DONE; + } + default: + { + ink_release_assert(!"ObjectReloadEvent invalid state"); + } + + } // End of switch + return 0; +} + +int +ObjectReloadCont::CallBackUser(int event, void *d) +{ + _caller_cont->handleEvent(event, d); + return 0; +} + +// End of Update.cc diff --git a/proxy/Update.h b/proxy/Update.h new file mode 100644 index 00000000..95a78d6a --- /dev/null +++ b/proxy/Update.h @@ -0,0 +1,527 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/**************************************************************************** + + Update.h + + +****************************************************************************/ + +#include "P_EventSystem.h" +#include "URL.h" +#include "HTTP.h" + +#ifndef _Update_h_ +#define _Update_h_ + +///////////////////////////////////////////////////////// +// Update subsystem specific events +///////////////////////////////////////////////////////// +#define UPDATE_EVENT_SUCCESS (UPDATE_EVENT_EVENTS_START+0) +#define UPDATE_EVENT_SUCCESS_NOACTION (UPDATE_EVENT_EVENTS_START+1) +#define UPDATE_EVENT_FAILED (UPDATE_EVENT_EVENTS_START+2) + +#define MAX_UPDATE_EVENT UPDATE_EVENT_FAILED + +#define IS_UPDATE_EVENT(_e) \ + ( ( ((_e) >= UPDATE_EVENT_EVENTS_START) && \ + ((_e) <= MAX_UPDATE_EVENT) ) ? 1 : 0 ) + +extern RecRawStatBlock *update_rsb; + +enum +{ + update_successes_stat, + update_no_actions_stat, + update_fails_stat, + update_unknown_status_stat, + update_state_machines_stat, + + update_stat_count +}; + +////////////////////////////////////////////////////////////////////// +// UpdateConfigParams -- Global subsystem configuration parameters +////////////////////////////////////////////////////////////////////// +class UpdateConfigParams:public RefCountObj +{ +public: + UpdateConfigParams(); + UpdateConfigParams(UpdateConfigParams &); + ~UpdateConfigParams(); + UpdateConfigParams & operator=(UpdateConfigParams &); + int operator==(UpdateConfigParams &); + + int IsEnabled() + { + return _enabled; + } + int ImmediateUpdate() + { + return _immediate_update; + } + int RetryCount() + { + return _retry_count; + } + int RetryInterval() + { + return _retry_interval; + } + int ConcurrentUpdates() + { + return _concurrent_updates; + } + int MaxUpdateSM() + { + return _max_update_state_machines; + } + int MaxMemoryUsageMB() + { + return _memory_use_in_mb; + } + +public: + RecInt _enabled; + RecInt _immediate_update; + RecInt _retry_count; + RecInt _retry_interval; + RecInt _concurrent_updates; + RecInt _max_update_state_machines; + RecInt _memory_use_in_mb; +}; + +/////////////////////////////////////////////////// +// UpdateEntry -- Per update object descriptor +/////////////////////////////////////////////////// +class UpdateConfigList; + +class UpdateEntry +{ +public: + UpdateEntry(); + ~UpdateEntry(); + + enum + { + MIN_OFFSET_HOUR = 0, MAX_OFFSET_HOUR = 23, + MIN_INTERVAL = 0, MAX_INTERVAL = 86400, + MIN_DEPTH = 0, MAX_DEPTH = 128, + SECONDS_PER_HOUR = 3600, + SECONDS_PER_MIN = 60 + }; + + void Init(int derived_url = 0); + int ValidURL(char *, char *); + int ValidHeaders(char *, char *); + int BuildHttpRequest(); + int ValidHeaderNameChar(char); + int ValidSeparatorChar(char); + int ValidHour(char *, char *); + int ValidInterval(char *, char *); + int ValidDepth(char *, char *); + int TerminalURL(); + void SetTerminalStatus(int); + + void ComputeScheduleTime(); + int ScheduleNow(time_t); + +public: + LINK(UpdateEntry, link); + UpdateEntry *_group_link; + UpdateEntry *_hash_link; + +public: + ////////////////////// + // URL data + ////////////////////// + int _id; + char *_url; + URL _URLhandle; + INK_MD5 _url_md5; + int _terminal_url; + + //////////////////////////// + // Request header data + //////////////////////////// + char *_request_headers; + int _num_request_headers; + HTTPHdr *_http_hdr; + HTTPParser _http_parser; + + /////////////////////////////// + // Configuration data + /////////////////////////////// + int _offset_hour; + int _interval; + int _max_depth; + + ////////////////////////////////// + // State data + ////////////////////////////////// + time_t _start_time; + int _expired; + + int _scheme_index; + int _update_event_status; + + Ptr _indirect_list; +}; + +///////////////////////////////////////////////////////////// +// UpdateConfigList -- Container for UpdateEntry objects +///////////////////////////////////////////////////////////// +class UpdateConfigList:public RefCountObj +{ +public: + UpdateConfigList(); + ~UpdateConfigList(); + void Add(UpdateEntry *); + int HashAdd(UpdateEntry *); + UpdateEntry *Remove(); + void AddPending(UpdateEntry *); + UpdateEntry *RemovePending(); + int Entries() + { + return _entry_q_elements; + } + int PendingEntries() + { + return _pending_q_elements; + } + +public: + enum + { + HASH_TABLE_SIZE = 4096 + }; + int _entry_q_elements; + Queue _entry_q; + int _pending_q_elements; + Queue _pending_q; + UpdateEntry **_hash_table; +}; + +//////////////////////////////////////////////////////////////// +// UpdateManager -- External interface to Update subsystem +//////////////////////////////////////////////////////////////// +class UpdateConfigManager; +class UpdateScheduler; + +class UpdateManager +{ +public: + UpdateManager(); + ~UpdateManager(); + int start(); + +private: + UpdateConfigManager * _CM; + UpdateScheduler *_SCH; +}; + +extern UpdateManager updateManager; + +////////////////////////////////////////////////////////////////////////// +// UpdateConfigManager -- Handle Update subsystem global configuration +// and URL list updates +////////////////////////////////////////////////////////////////////////// +typedef int (UpdateConfigManager::*UpdateConfigManagerContHandler) (int, void *); + +class UpdateConfigManager:public Continuation +{ +public: + UpdateConfigManager(); + ~UpdateConfigManager(); + int init(); + int GetConfigParams(Ptr *); + int GetConfigList(Ptr *); + + static int URL_list_update_callout(const char *name, RecDataT data_type, RecData data, void *cookie); + + void SetFileName(char *f) + { + _filename = f; + } + char *GetFileName() + { + return _filename; + } + + int ProcessUpdate(int event, Event * e); + UpdateConfigList *BuildUpdateList(); + UpdateConfigList *ParseConfigFile(int); + int GetDataLine(int, int, char *, int, int); + +private: + Event * _periodic_event; + char *_filename; + Ptr _CP; + Ptr _CP_actual; + Ptr _CL; +}; + +//////////////////////////////////////////////////////////////////////// +// UpdateScheduler -- Handle scheduling of UpdateEntry objects +//////////////////////////////////////////////////////////////////////// +typedef int (UpdateScheduler::*UpdateSchedulerContHandler) (int, void *); + +class UpdateScheduler:public Continuation +{ +public: + UpdateScheduler(UpdateConfigManager * cm = NULL); + ~UpdateScheduler(); + int Init(); + int Init(UpdateScheduler *, UpdateEntry *, Ptr); + + int ScheduleEvent(int, void *); + int Schedule(UpdateEntry * e = NULL); + int ChildExitEventHandler(int, Event *); + +private: + Event * _periodic_event; + int _recursive_update; + UpdateConfigManager *_CM; + Ptr _CP; + Ptr _CL; + int _schedule_event_callbacks; + int _update_state_machines; + + UpdateEntry *_base_EN; // Entry from which recursive + // list was derived + UpdateScheduler *_parent_US; // Parent which created us +}; + +///////////////////////////////////////////////////////////////// +// UpdateSM -- State machine which handles object update action +///////////////////////////////////////////////////////////////// +class UpdateSM; +typedef int (UpdateSM::*UpdateSMContHandler) (int, void *); + +class UpdateSM:public Continuation +{ +public: + enum state_t + { + USM_INIT = 1, + USM_PROCESS_URL, + USM_PROCESS_URL_COMPLETION, + USM_EXIT + }; + + enum + { + N_SCHEMES = 1 + }; + + static int http_scheme(UpdateSM *); + static int http_scheme_postproc(UpdateSM *); + + UpdateSM(UpdateScheduler *, Ptr, UpdateEntry *); + ~UpdateSM(); + void Start(); + int HandleSMEvent(int, Event *); + +public: + UpdateEntry * _EN; + +private: + UpdateScheduler * _US; + Ptr _CP; + state_t _state; + int _return_status; + int _retries; +}; + +struct dispatch_entry +{ + const char **scheme; + int (*func) (UpdateSM *); +}; + +extern struct dispatch_entry scheme_dispatch_table[UpdateSM::N_SCHEMES]; +extern struct dispatch_entry scheme_post_dispatch_table[UpdateSM::N_SCHEMES]; + +struct html_tag +{ + const char *tag; + const char *attr; +}; + +///////////////////////////////////////////////////////////////////////////// +// RecursiveHttpGet -- Generate URL list by recursively traversing +// non-terminal URL(s) up to the specified depth. +///////////////////////////////////////////////////////////////////////////// +class ObjectReloadCont; +class RecursiveHttpGet; + +typedef int (RecursiveHttpGet::*RecursiveHttpGetContHandler) (int, Event *); + +class HtmlParser +{ + // Parse Html routines +public: + static char default_zero_char; + + enum scan_state_t + { + SCAN_INIT = 1, + SCAN_START, + FIND_TAG_START, + COPY_TAG, + IGNORE_COMMENT_START, + IGNORE_COMMENT, + FIND_ATTR_START, + COPY_ATTR, + FIND_ATTR_VALUE_DELIMITER, + FIND_ATTR_VALUE_START, + COPY_ATTR_VALUE, + VALIDATE_ENTRY, + VALIDATE_ENTRY_RESTART, + RESUME_ATTR_VALUE_SCAN, + TERMINATE_COPY_ATTR_VALUE + }; + + enum + { + MAX_TAG_NAME_LENGTH = 1024, + MAX_ATTR_NAME_LENGTH = 1024 + }; + + HtmlParser() + : _attr_matched(false), _url(0), _comment_end_ptr(0), _scan_state(SCAN_INIT), + _tag(&default_zero_char, 32), _attr(&default_zero_char, 32), + _attr_value(&default_zero_char, 32), + _attr_value_hash_char_index(-1), _attr_value_quoted(0), + _html_doc_base(&default_zero_char, 128), + _result(&default_zero_char, 128), allowable_html_tags(0), allowable_html_attrs(0) + { } + + ~HtmlParser() + { } + + void Init(char *url, struct html_tag *allowed_html_tags, struct html_tag *allowed_html_attrs = NULL) { + _url = url; + allowable_html_tags = allowed_html_tags; + allowable_html_attrs = allowed_html_attrs; + _attr_matched = false; + } + + int ParseHtml(IOBufferReader *, char **, char **); + int ScanHtmlForURL(IOBufferReader *, char **, char **); + int AllowTagAttrValue(); + int ValidProtoScheme(char *); + int ValidSupportedProtoScheme(char *); + int ExtractURL(char **, char **); + int ConstructURL(char **, char **); + DynArray*MakeURL(char *, char *, int, int); + DynArray*PrependString(const char *, int, char *, int); + bool _attr_matched; + + char *_url; + char *_comment_end_ptr; + scan_state_t _scan_state; + DynArray_tag; + DynArray_attr; + DynArray_attr_value; + intptr_t _attr_value_hash_char_index; // '#' char loc + unsigned char _attr_value_quoted; + DynArray_html_doc_base; + DynArray_result; + + struct html_tag *allowable_html_tags; + struct html_tag *allowable_html_attrs; +}; + +class RecursiveHttpGet:public Continuation +{ +public: + RecursiveHttpGet(); + ~RecursiveHttpGet(); + void Init(Continuation *, char *, char *, URL *, HTTPHdr *, int, + Ptr, struct html_tag *allowed_html_tags); + int RecursiveHttpGetEvent(int, Event *); + + int ExitEventHandler(int, Event *); + +public: + int _id; + Continuation *_caller_cont; + char *_request_headers; + URL *_url_data; + HTTPHdr *_http_hdr; + int _recursion_depth; + Ptr _CL; + ObjectReloadCont *_OL; + UpdateEntry *_group_link_head; + int _active_child_state_machines; + + HtmlParser html_parser; +}; + +///////////////////////////////////////////////////////////////////////// +// ObjectReloadCont -- Read given URL object via the local proxy port +///////////////////////////////////////////////////////////////////////// +class ObjectReloadCont; +typedef int (ObjectReloadCont::*ObjectReloadContHandler) (int, void *); + +class ObjectReloadCont:public Continuation +{ +public: + ObjectReloadCont(); + ~ObjectReloadCont(); + void Init(Continuation *, char *, int, char *, int, int, int); + void free(); + int ObjectReloadEvent(int, void *); + int CallBackUser(int, void *); + + enum state_t + { + START = 1, + ATTEMPT_CONNECT, + WRITING_URL, + READING_DATA + }; + + Continuation *_caller_cont; + int _request_id; + MIOBuffer *_send_data; + MIOBuffer *_receive_data; + IOBufferReader *_receive_data_reader; + Event *_start_event; + state_t _state; + Action *_cur_action; + class NetVConnection *_netvc; + VIO *_write_vio; + VIO *_read_vio; + int _read_event_callback; + +}; + +extern ClassAllocator ObjectReloadContAllocator; + +#endif // _Update_h_ + +// End of Update.h diff --git a/proxy/UserNameCacheTest.h b/proxy/UserNameCacheTest.h new file mode 100644 index 00000000..dabf8e19 --- /dev/null +++ b/proxy/UserNameCacheTest.h @@ -0,0 +1,25 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +int UserNameHandleCallbacks(INKCont cont, INKEvent event, void *e); +void userNameCacheTestInit(); diff --git a/proxy/api/ts/InkAPIHughes.h b/proxy/api/ts/InkAPIHughes.h new file mode 100644 index 00000000..7a36aaca --- /dev/null +++ b/proxy/api/ts/InkAPIHughes.h @@ -0,0 +1,126 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/* + This file is created for Prefetch API and is used only by Hughes +*/ + +typedef struct +{ + + /*request header */ + TSMBuffer request_buf; + TSMLoc request_loc; + + /*response header */ + TSMBuffer response_buf; + TSMLoc response_loc; + + /*child ip addr in network order */ + unsigned int client_ip; + + /*the embedded url parsed by the parser */ + const char *embedded_url; + + /* flag which says if a perticular embedded url is present in the cache */ + int present_in_cache; + + /* Reader for the buffer which contains the prefetched object */ + TSIOBuffer object_buf; + TSIOBufferReader object_buf_reader; + + /* This specifies if we need to invoke the OBJECT_HOOK and whether we + need to send the buffer to child as well + This should set inside EMBEDDED_URL_HOOK by the user + */ + int object_buf_status; + + /*method of sending data to child */ + unsigned int url_proto; + unsigned int url_response_proto; + +} TSPrefetchInfo; + +typedef int (*TSPrefetchHook) (int hook, TSPrefetchInfo * prefetch_info); + +enum +{ /* return type for TSPrefetchHook */ + TS_PREFETCH_CONTINUE, + TS_PREFETCH_DISCONTINUE +}; + +enum +{ + TS_PREFETCH_PROTO_TCP = 1, + TS_PREFETCH_PROTO_UDP +}; + +enum +{ + TS_PREFETCH_OBJ_BUF_NOT_NEEDED = 0, + TS_PREFETCH_OBJ_BUF_NEEDED, /* The user wants the buffer but does not + want it to be transmitted to the child */ + TS_PREFETCH_OBJ_BUF_NEEDED_N_TRANSMITTED /* The object should + be transmitted as well */ +}; + +enum +{ /* prefetch hooks */ + TS_PREFETCH_PRE_PARSE_HOOK, + /* This hook is invoked just before we begin to parse a document + request and response headers are available. + Return value: TS_PREFETCH_CONTINUE :continue parsing + TS_PREFETCH_DISCONTIUE: don't bother parser + */ + + TS_PREFETCH_EMBEDDED_URL_HOOK, + /* This hook is invoked when a URL is extracted. + url_proto and url_response_proto contain the default protocols used + for sending the url and actual url object respectively to the child. + The hook can change thes to one of the 3 methods mentioned above. + Return value: TS_PREFETCH_CONTINUE : prefetch this url. + TS_PREFETCH_DISCONTIUE: don't bother prefetching this + url + */ + + TS_PREFETCH_EMBEDDED_OBJECT_HOOK + /* This hook is invoked when the user wants to have access to the buffer + of the embedded object we prefetched. We pass in the buffer reader. + The reader contains the data in the format specified in the Prefetch + document (with 12 byte header etc). + It is the users responsibility to free the reader. + The only valid field in the PrefetchInfo structure object_buf_reader. + embedded_url, object_buf, object_buf_reader, and object_buf_status are + set in TSPrefetchInfo passed as arguments + */ + /* more hooks */ +}; + +tsapi int TSPrefetchStart(); +/* This starts the Prefetch engine in Traffic Server + Return value 0 indicates success.*/ + +tsapi int TSPrefetchHookSet(int hook_no, TSPrefetchHook hook_fn); +/* Registers a hook for the given hook_no. + A hook is already present, it is replace by hook_fn + return value 0 indicates success */ diff --git a/proxy/api/ts/InkAPIPrivateIOCore.h b/proxy/api/ts/InkAPIPrivateIOCore.h new file mode 100644 index 00000000..d99bde85 --- /dev/null +++ b/proxy/api/ts/InkAPIPrivateIOCore.h @@ -0,0 +1,248 @@ +/** @file + + Internal SDK stuff + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef __INK_API_PRIVATE_IOCORE_H__ +#define __INK_API_PRIVATE_IOCORE_H__ +#include "ts.h" +#if !defined(__GNUC__) +#include "I_EventSystem.h" +#include "I_Cache.h" +#include "I_Net.h" +#else +#include "P_EventSystem.h" +#include "P_Cache.h" +#include "P_Net.h" +#endif + +enum INKContInternalMagic_t +{ + INKCONT_INTERN_MAGIC_ALIVE = 0x00009631, + INKCONT_INTERN_MAGIC_DEAD = 0xDEAD9631 +}; + +class INKContInternal:public DummyVConnection +{ +public: + INKContInternal(); + INKContInternal(TSEventFunc funcp, TSMutex mutexp); + + void init(TSEventFunc funcp, TSMutex mutexp); + virtual void destroy(); + + void handle_event_count(int event); + int handle_event(int event, void *edata); + +public: + void *mdata; + TSEventFunc m_event_func; + volatile int m_event_count; + volatile int m_closed; + int m_deletable; + int m_deleted; + //INKqa07670: Nokia memory leak bug fix + INKContInternalMagic_t m_free_magic; +}; + + +enum TSApiDataType +{ + TS_API_DATA_READ_VIO = VCONNECTION_API_DATA_BASE, + TS_API_DATA_WRITE_VIO, + TS_API_DATA_OUTPUT_VC, + TS_API_DATA_CLOSED +}; + + +class INKVConnInternal:public INKContInternal +{ +public: + INKVConnInternal(); + INKVConnInternal(TSEventFunc funcp, TSMutex mutexp); + + void init(TSEventFunc funcp, TSMutex mutexp); + virtual void destroy(); + + int handle_event(int event, void *edata); + + VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf); + + VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false); + + void do_io_transform(VConnection *vc); + + void do_io_close(int lerrno = -1); + + void do_io_shutdown(ShutdownHowTo_t howto); + + void reenable(VIO *vio); + + void retry(unsigned int delay); + + bool get_data(int id, void *data); + bool set_data(int id, void *data); + +public: + VIO m_read_vio; + VIO m_write_vio; + VConnection *m_output_vc; +}; + +/**************************************************************** + * IMPORTANT - READ ME + * Any plugin using the IO Core must enter + * with a held mutex. SDK 1.0, 1.1 & 2.0 did not + * have this restriction so we need to add a mutex + * to Plugin's Continuation if it trys to use the IOCore + * Not only does the plugin have to have a mutex + * before entering the IO Core. The mutex needs to be held. + * We now take out the mutex on each call to ensure it is + * held for the entire duration of the IOCore call + ***************************************************************/ + +// +// FORCE_PLUGIN_MUTEX -- define 'UNSAFE_FORCE_MUTEX' if you +// do *not* want the locking macro to be thread safe. +// Otherwise, access during 'null-mutex' case will be serialized +// in a locking manner (too bad for the net threads). +// + + +#define UNSAFE_FORCE_MUTEX + +#ifdef UNSAFE_FORCE_MUTEX +#define LOCK_MONGO_MUTEX +#define UNLOCK_MONGO_MUTEX +#define MUX_WARNING(p) \ +TSDebug ("sdk","(SDK) null mutex detected in critical region (mutex created)"); \ +TSDebug ("sdk","(SDK) please create continuation [%p] with mutex", (p)); +#else +static ink_mutex big_mux; + +#define MUX_WARNING(p) 1 +#define LOCK_MONGO_MUTEX ink_mutex_acquire (&big_mux) +#define UNLOCK_MONGO_MUTEX ink_mutex_release (&big_mux) +#endif + +#define FORCE_PLUGIN_MUTEX(_c) \ + MutexLock ml; \ + LOCK_MONGO_MUTEX; \ + if (( (INKContInternal*)_c)->mutex == NULL) { \ + ( (INKContInternal*)_c)->mutex = new_ProxyMutex(); \ + UNLOCK_MONGO_MUTEX; \ + MUX_WARNING(_c); \ + MUTEX_SET_AND_TAKE_LOCK(ml, ((INKContInternal*)_c)->mutex, this_ethread()); \ + } else { \ + UNLOCK_MONGO_MUTEX; \ + MUTEX_SET_AND_TAKE_LOCK(ml, ((INKContInternal*)_c)->mutex, this_ethread()); \ + } + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + TSReturnCode sdk_sanity_check_mutex(TSMutex); + TSReturnCode sdk_sanity_check_hostlookup_structure(TSHostLookupResult); + TSReturnCode sdk_sanity_check_iocore_structure(void *); + +/* ---------------------------------------------------------------------- + * + * Interfaces for Raft project + * + * ---------------------------------------------------------------------- */ + + tsapi TSMutex TSMutexCreateInternal(void); + tsapi int TSMutexCheck(TSMutex mutex); + + +/* IOBuffer */ + tsapi void TSIOBufferReaderCopy(TSIOBufferReader readerp, const void *buf, int64_t length); + tsapi int64_t TSIOBufferBlockDataSizeGet(TSIOBufferBlock blockp); + tsapi void TSIOBufferBlockDestroy(TSIOBufferBlock blockp); + typedef void *INKUDPPacket; + typedef void *INKUDPacketQueue; + typedef void *INKUDPConn; +/* ===== UDP Connections ===== */ +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi TSAction INKUDPBind(TSCont contp, unsigned int ip, int port); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi TSAction INKUDPSendTo(TSCont contp, INKUDPConn udp, unsigned int ip, int port, char *buf, int len); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi TSAction INKUDPRecvFrom(TSCont contp, INKUDPConn udp); + +/**************************************************************************** + * Return file descriptor. + * contact: OXYGEN + ****************************************************************************/ + tsapi int INKUDPConnFdGet(INKUDPConn udp); + +/* ===== UDP Packet ===== */ +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi INKUDPPacket INKUDPPacketCreate(); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi TSIOBufferBlock INKUDPPacketBufferBlockGet(INKUDPPacket packet); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi unsigned int INKUDPPacketFromAddressGet(INKUDPPacket packet); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi int INKUDPPacketFromPortGet(INKUDPPacket packet); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi INKUDPConn INKUDPPacketConnGet(INKUDPPacket packet); + +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi void INKUDPPacketDestroy(INKUDPPacket packet); + +/* ===== Packet Queue ===== */ +/**************************************************************************** + * contact: OXYGEN + ****************************************************************************/ + tsapi INKUDPPacket INKUDPPacketGet(INKUDPacketQueue queuep); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __INK_API_PRIVATE_IOCORE_H__ */ diff --git a/proxy/api/ts/Makefile.am b/proxy/api/ts/Makefile.am new file mode 100644 index 00000000..e22dd42d --- /dev/null +++ b/proxy/api/ts/Makefile.am @@ -0,0 +1,28 @@ +# api/ts Makefile.am +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +includedir=$(prefix)/include/ts + +include_HEADERS = \ + ts.h \ + remap.h \ + experimental.h + +noinst_HEADERS = \ + InkAPIHughes.h \ + InkAPIPrivateIOCore.h diff --git a/proxy/api/ts/Makefile.in b/proxy/api/ts/Makefile.in new file mode 100644 index 00000000..ebe737e9 --- /dev/null +++ b/proxy/api/ts/Makefile.in @@ -0,0 +1,677 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# api/ts Makefile.am +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = proxy/api/ts +DIST_COMMON = $(include_HEADERS) $(noinst_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in $(srcdir)/ts.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = ts.h +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(includedir)" +HEADERS = $(include_HEADERS) $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = $(prefix)/include/ts +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +include_HEADERS = \ + ts.h \ + remap.h \ + experimental.h + +noinst_HEADERS = \ + InkAPIHughes.h \ + InkAPIPrivateIOCore.h + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign proxy/api/ts/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign proxy/api/ts/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +ts.h: $(top_builddir)/config.status $(srcdir)/ts.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags uninstall uninstall-am uninstall-includeHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/proxy/api/ts/TsException.h b/proxy/api/ts/TsException.h new file mode 100644 index 00000000..eff09e74 --- /dev/null +++ b/proxy/api/ts/TsException.h @@ -0,0 +1,61 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +# if ! defined(TS_EXCEPTION_HEADER) +# define TS_EXCEPTION_HEADER + +/** @file + Apache Traffic Server Exceptions. + */ + +# include +# include + +namespace ts { + /** Base class for ATS exception. + Clients should subclass as appropriate. This is intended to carry + pre-allocated text along so that it can be thrown without any + addditional memory allocation. + */ + class Exception { + public: + /// Default constructor. + Exception(); + /// Construct with alternate @a text. + Exception( + const char* text ///< Alternate text for exception. + ); + + static char const* const DEFAULT_TEXT; + protected: + char const* m_text; + }; + + // ---------------------------------------------------------- + // Inline implementations. + + inline Exception::Exception() : m_text(DEFAULT_TEXT) { } + inline Exception::Exception(char const* text) : m_text(text) { } +} + +# endif // TS_EXCEPTION_HEADER diff --git a/proxy/api/ts/experimental.h b/proxy/api/ts/experimental.h new file mode 100644 index 00000000..332b5360 --- /dev/null +++ b/proxy/api/ts/experimental.h @@ -0,0 +1,465 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * Interfaces in this header file are experimental, undocumented and + * are subject to change even across minor releases of Traffic Server. + * None of the interfaces in this file are committed to be stable + * unless they are migrated to ts/ts.h If you require stable APIs to + * Traffic Server, DO NOT USE anything in this file. + */ + +#ifndef __TS_API_EXPERIMENTAL_H__ +#define __TS_API_EXPERIMENTAL_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /* Cache APIs that are not yet fully supported and/or frozen nor complete. */ + tsapi TSReturnCode TSCacheBufferInfoGet(TSCacheTxn txnp, uint64_t *length, uint64_t *offset); + + tsapi TSCacheHttpInfo TSCacheHttpInfoCreate(); + tsapi void TSCacheHttpInfoReqGet(TSCacheHttpInfo infop, TSMBuffer *bufp, TSMLoc *obj); + tsapi void TSCacheHttpInfoRespGet(TSCacheHttpInfo infop, TSMBuffer *bufp, TSMLoc *obj); + tsapi void TSCacheHttpInfoReqSet(TSCacheHttpInfo infop, TSMBuffer bufp, TSMLoc obj); + tsapi void TSCacheHttpInfoRespSet(TSCacheHttpInfo infop, TSMBuffer bufp, TSMLoc obj); + tsapi void TSCacheHttpInfoKeySet(TSCacheHttpInfo infop, TSCacheKey key); + tsapi void TSCacheHttpInfoSizeSet(TSCacheHttpInfo infop, int64_t size); + tsapi int TSCacheHttpInfoVector(TSCacheHttpInfo infop, void *data, int length); + + /* Do not edit these apis, used internally */ + tsapi int TSMimeHdrFieldEqual(TSMBuffer bufp, TSMLoc hdr_obj, TSMLoc field1, TSMLoc field2); + tsapi TSReturnCode TSHttpTxnHookRegisteredFor(TSHttpTxn txnp, TSHttpHookID id, TSEventFunc funcp); + + /* IP Lookup */ + typedef struct tsapi_iplookup* TSIPLookup; + typedef struct tsapi_iplookupstate* TSIPLookupState; + typedef void (*TSIPLookupPrintFunc) (void *data); + + tsapi void TSIPLookupPrint(TSIPLookup iplu, TSIPLookupPrintFunc pf); + tsapi void TSIPLookupNewEntry(TSIPLookup iplu, uint32_t addr1, uint32_t addr2, void *data); + tsapi int TSIPLookupMatch(TSIPLookup iplu, uint32_t addr, void **data); + tsapi TSReturnCode TSIPLookupMatchFirst(TSIPLookup iplu, uint32_t addr, TSIPLookupState iplus, void **data); + tsapi TSReturnCode TSIPLookupMatchNext(TSIPLookup iplu, TSIPLookupState iplus, void **data); + + /* for Media-IXT mms over http */ + typedef enum + { + TS_HTTP_CNTL_GET_LOGGING_MODE, + TS_HTTP_CNTL_SET_LOGGING_MODE, + TS_HTTP_CNTL_GET_INTERCEPT_RETRY_MODE, + TS_HTTP_CNTL_SET_INTERCEPT_RETRY_MODE + } TSHttpCntlType; + +#define TS_HTTP_CNTL_OFF (void*) 0 +#define TS_HTTP_CNTL_ON (void*) 1 + /* usage: + void *onoff = 0; + TSHttpTxnCntl(.., TS_HTTP_CNTL_GET_LOGGING_MODE, &onoff); + if (onoff == TS_HTTP_CNTL_ON) .... + */ + tsapi TSReturnCode TSHttpTxnCntl(TSHttpTxn txnp, TSHttpCntlType cntl, void *data); + + + /* Protocols APIs */ + tsapi void TSVConnCacheHttpInfoSet(TSVConn connp, TSCacheHttpInfo infop); + + /* ICP freshness functions */ + typedef int (*TSPluginFreshnessCalcFunc) (TSCont contp); + tsapi void TSICPFreshnessFuncSet(TSPluginFreshnessCalcFunc funcp); + + tsapi TSReturnCode TSICPCachedReqGet(TSCont contp, TSMBuffer *bufp, TSMLoc *obj); + tsapi TSReturnCode TSICPCachedRespGet(TSCont contp, TSMBuffer *bufp, TSMLoc *obj); + + + /* The rest is from the old "froze" private API include, we should consider + moving some of these over to ts/ts.h as well. TODO */ + + /**************************************************************************** + * Test if cache ready to accept request for a specific type of data + ****************************************************************************/ + tsapi TSReturnCode TSCacheDataTypeReady(TSCacheDataType type, int *is_ready); + + /**************************************************************************** + * When reenabling a txn in error, keep the connection open in case + * of keepalive. + ****************************************************************************/ + tsapi void TSHttpTxnClientKeepaliveSet(TSHttpTxn txnp, int set); + + /**************************************************************************** + * Allow to set the body of a POST request. + ****************************************************************************/ + tsapi void TSHttpTxnServerRequestBodySet(TSHttpTxn txnp, char *buf, int64_t buflength); + + /* ===== High Resolution Time ===== */ +#define TS_HRTIME_FOREVER HRTIME_FOREVER +#define TS_HRTIME_DECADE HRTIME_DECADE +#define TS_HRTIME_YEAR HRTIME_YEAR +#define TS_HRTIME_WEEK HRTIME_WEEK +#define TS_HRTIME_DAY HRTIME_DAY +#define TS_HRTIME_HOUR HRTIME_HOUR +#define TS_HRTIME_MINUTE HRTIME_MINUTE +#define TS_HRTIME_SECOND HRTIME_SECOND +#define TS_HRTIME_MSECOND HRTIME_MSECOND +#define TS_HRTIME_USECOND HRTIME_USECOND +#define TS_HRTIME_NSECOND HRTIME_NSECOND + +#define TS_HRTIME_APPROX_SECONDS(_x) HRTIME_APPROX_SECONDS(_x) +#define TS_HRTIME_APPROX_FACTOR HRTIME_APPROX_FACTOR + + /* +//////////////////////////////////////////////////////////////////// +// +// Map from units to ts_hrtime values +// +//////////////////////////////////////////////////////////////////// +*/ +#define TS_HRTIME_YEARS(_x) HRTIME_YEARS(_x) +#define TS_HRTIME_WEEKS(_x) HRTIME_WEEKS(_x) +#define TS_HRTIME_DAYS(_x) HRTIME_DAYS(_x) +#define TS_HRTIME_HOURS(_x) HRTIME_HOURS(_x) +#define TS_HRTIME_MINUTES(_x) HRTIME_MINUTES(_x) +#define TS_HRTIME_SECONDS(_x) HRTIME_SECONDS(_x) +#define TS_HRTIME_MSECONDS(_x) HRTIME_MSECONDS(_x) +#define TS_HRTIME_USECONDS(_x) HRTIME_USECONDS(_x) +#define TS_HRTIME_NSECONDS(_x) HRTIME_NSECONDS(_x) + + /* ===== Time ===== */ + tsapi TSHRTime TSBasedTimeGet(); + + /**************************************************************************** + * Get time when Http TXN started / ended + ****************************************************************************/ + tsapi TSReturnCode TSHttpTxnStartTimeGet(TSHttpTxn txnp, TSHRTime *start_time); + tsapi TSReturnCode TSHttpTxnEndTimeGet(TSHttpTxn txnp, TSHRTime *end_time); + + tsapi TSReturnCode TSHttpTxnCachedRespTimeGet(TSHttpTxn txnp, time_t *resp_time); + + /* ===== Cache ===== */ + tsapi TSReturnCode TSCacheKeyDataTypeSet(TSCacheKey key, TSCacheDataType type); + + + /* ===== Utility ===== */ + /**************************************************************************** + * Create a random number + * Return random integer between and + ****************************************************************************/ + tsapi unsigned int TSrandom(void); + + /**************************************************************************** + * Create a random double + * Return random double between and + ****************************************************************************/ + tsapi double TSdrandom(void); + + /**************************************************************************** + * Return Hi-resolution current time. (int64_t) + ****************************************************************************/ + tsapi TSHRTime TShrtime(void); + + /* ===== CacheHttpInfo ===== */ + + tsapi TSCacheHttpInfo TSCacheHttpInfoCopy(TSCacheHttpInfo infop); + tsapi void TSCacheHttpInfoReqGet(TSCacheHttpInfo infop, TSMBuffer *bufp, TSMLoc *offset); + tsapi void TSCacheHttpInfoRespGet(TSCacheHttpInfo infop, TSMBuffer *bufp, TSMLoc *offset); + tsapi void TSCacheHttpInfoDestroy(TSCacheHttpInfo infop); + + + /* ===== ICP ===== */ + tsapi void TSHttpIcpDynamicSet(int value); + + /**************************************************************************** + * TSHttpTxnCacheLookupCountGet + * Return: TS_SUCESS/TS_ERROR + ****************************************************************************/ + tsapi TSReturnCode TSHttpTxnCacheLookupCountGet(TSHttpTxn txnp, int *lookup_count); + tsapi TSReturnCode TSHttpTxnNewCacheLookupDo(TSHttpTxn txnp, TSMBuffer bufp, TSMLoc url_loc); + tsapi TSReturnCode TSHttpTxnSecondUrlTryLock(TSHttpTxn txnp); + tsapi TSReturnCode TSHttpTxnRedirectRequest(TSHttpTxn txnp, TSMBuffer bufp, TSMLoc url_loc); + tsapi TSReturnCode TSHttpTxnCacheLookupSkip(TSHttpTxn txnp); + tsapi TSReturnCode TSHttpTxnServerRespNoStore(TSHttpTxn txnp); + tsapi TSReturnCode TSHttpTxnServerRespIgnore(TSHttpTxn txnp); + tsapi TSReturnCode TSHttpTxnShutDown(TSHttpTxn txnp, TSEvent event); + + /**************************************************************************** + * ?? + * Return ?? + ****************************************************************************/ + tsapi int TSHttpTxnClientReqIsServerStyle(TSHttpTxn txnp); + + /**************************************************************************** + * ?? + * Return ?? + ****************************************************************************/ + tsapi void TSHttpTxnOverwriteExpireTime(TSHttpTxn txnp, time_t expire_time); + + /**************************************************************************** + * ?? + * Return ?? + ****************************************************************************/ + tsapi TSReturnCode TSHttpTxnUpdateCachedObject(TSHttpTxn txnp); + + /**************************************************************************** + * ?? + * TODO: This returns a LookingUp_t value, we need to SDK'ify it. + ****************************************************************************/ + tsapi int TSHttpTxnLookingUpTypeGet(TSHttpTxn txnp); + + + /* ===== Matcher Utils ===== */ +#define TS_MATCHER_LINE_INVALID 0 + typedef struct tsapi_matcheline* TSMatcherLine; + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi char *TSMatcherReadIntoBuffer(char *file_name, int *file_len); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi char *TSMatcherTokLine(char *buffer, char **last); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi char *TSMatcherExtractIPRange(char *match_str, uint32_t *addr1, uint32_t *addr2); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi TSMatcherLine TSMatcherLineCreate(); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi void TSMatcherLineDestroy(TSMatcherLine ml); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi const char *TSMatcherParseSrcIPConfigLine(char *line, TSMatcherLine ml); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi char *TSMatcherLineName(TSMatcherLine ml, int element); + + /**************************************************************************** + * ?? + * Return + ****************************************************************************/ + tsapi char *TSMatcherLineValue(TSMatcherLine ml, int element); + + /**************************************************************************** + * Set a records.config integer variable + ****************************************************************************/ + tsapi TSReturnCode TSMgmtConfigIntSet(const char *var_name, TSMgmtInt value); + + /* ---------------------------------------------------------------------- + * Interfaces used by Wireless group + * ---------------------------------------------------------------------- */ + +#define TS_NET_EVENT_DATAGRAM_READ_COMPLETE TS_EVENT_INTERNAL_206 +#define TS_NET_EVENT_DATAGRAM_READ_ERROR TS_EVENT_INTERNAL_207 +#define TS_NET_EVENT_DATAGRAM_WRITE_COMPLETE TS_EVENT_INTERNAL_208 +#define TS_NET_EVENT_DATAGRAM_WRITE_ERROR TS_EVENT_INTERNAL_209 +#define TS_NET_EVENT_DATAGRAM_READ_READY TS_EVENT_INTERNAL_210 +#define TS_NET_EVENT_DATAGRAM_OPEN TS_EVENT_INTERNAL_211 +#define TS_NET_EVENT_DATAGRAM_ERROR TS_EVENT_INTERNAL_212 + + typedef enum + { + TS_SIGNAL_WDA_BILLING_CONNECTION_DIED = 100, + TS_SIGNAL_WDA_BILLING_CORRUPTED_DATA = 101, + TS_SIGNAL_WDA_XF_ENGINE_DOWN = 102, + TS_SIGNAL_WDA_RADIUS_CORRUPTED_PACKETS = 103 + } TSAlarmType; + + /* ===== Alarm ===== */ + /**************************************************************************** + * ?? + * contact: OXYGEN + ****************************************************************************/ + tsapi void TSSignalWarning(TSAlarmType code, char *msg); + + /***************************************************************************** + * Cluster RPC API support * + *****************************************************************************/ + /* + * Usage notes: + * 1) User is responsible for marshalling and unmarshaling data. + * 2) RPC message incompatiblities due to different plugin versions + * must be dealt with by the user. + * 3) Upon receipt of a machine offline, no guarantees are made about + * messages sent prior to the machine offline. + * 4) A node transitioning to the online state in an active cluster, + * is assumed to have no prior knowledge of messages processed in + * the past. + * 5) Key point to reiterate, actions taken in the functions specified in + * TSAddClusterStatusFunction() and TSAddClusterRPCFunction() must + * be non-blocking (i.e. usage of TSMutexLock() and file i/o is + * not allowed). + * 6) TSSendClusterRPC() can only process TSClusterRPCMsg_t generated + * by TSAllocClusterRPCMsg(). Failure to adhere to this rule will + * result in heap corruption. + * 7) Messages sent via TSSendClusterRPC() must be at least 4 bytes in + * length. + * 8) The user is not provided with any alignment guarantees on the + * 'm_data' field in the TSClusterRPCMsg_t returned via + * TSAllocClusterRPCMsg(). Assume byte alignment. + * 9) TSSendClusterRPC() interface owns the memory and is responsible + * for freeing the memory. + * 10) RPC functions defined via TSAddClusterRPCFunction() own the + * memory when invoked and are responsible for freeing it via + * TSFreeRPCMsg(). + */ +#define MAX_CLUSTER_NODES 256 + + typedef struct TSClusterRPCHandle + { + int opaque[2]; + } TSClusterRPCHandle_t; + + typedef int TSClusterStatusHandle_t; + typedef int TSNodeHandle_t; + + typedef struct TSClusterRPCMsg + { + TSClusterRPCHandle_t m_handle; + char m_data[4]; + } TSClusterRPCMsg_t; + + typedef enum + { + NODE_ONLINE = 1, + NODE_OFFLINE + } TSNodeStatus_t; + + typedef enum + { + RPC_API_WIRELESS_F01 = 51, + RPC_API_WIRELESS_F02, + RPC_API_WIRELESS_F03, + RPC_API_WIRELESS_F04, + RPC_API_WIRELESS_F05, + RPC_API_WIRELESS_F06, + RPC_API_WIRELESS_F07, + RPC_API_WIRELESS_F08, + RPC_API_WIRELESS_F09, + RPC_API_WIRELESS_F10 + } TSClusterRPCKey_t; + + typedef void (*TSClusterRPCFunction) (TSNodeHandle_t *node, TSClusterRPCMsg_t *msg, int msg_data_len); + typedef void (*TSClusterStatusFunction) (TSNodeHandle_t *node, TSNodeStatus_t s); + + /**************************************************************************** + * Subscribe to node up/down status notification. * + * Return == 0 Success * + * Return != 0 Failure * + * contact: OXY, DY + ****************************************************************************/ + tsapi int TSAddClusterStatusFunction(TSClusterStatusFunction Status_Function, TSMutex m, TSClusterStatusHandle_t *h); + /**************************************************************************** + * Cancel subscription to node up/down status notification. * + * Return == 0 Success * + * Return != 0 Failure * + * contact: OXY, DY + ****************************************************************************/ + tsapi int TSDeleteClusterStatusFunction(TSClusterStatusHandle_t *h); + + /**************************************************************************** + * Get the struct in_addr associated with the TSNodeHandle_t. * + * Return == 0 Success * + * Return != 0 Failure * + * contact: OXY, DY + ****************************************************************************/ + tsapi int TSNodeHandleToIPAddr(TSNodeHandle_t *h, struct in_addr *in); + + /**************************************************************************** + * Get the TSNodeHandle_t for the local node. * + * contact: OXY, DY + ****************************************************************************/ + tsapi void TSGetMyNodeHandle(TSNodeHandle_t *h); + + /**************************************************************************** + * Enable node up/down notification for subscription added via * + * TSAddClusterStatusFunction(). * + * contact: OXY, DY + ****************************************************************************/ + tsapi void TSEnableClusterStatusCallout(TSClusterStatusHandle_t *h); + + /**************************************************************************** + * Associate the given key with the given RPC function. * + * Return == 0 Success * + * Return != 0 Failure * + * contact: OXY, DY + ****************************************************************************/ + tsapi int TSAddClusterRPCFunction(TSClusterRPCKey_t k, TSClusterRPCFunction RPC_Function, TSClusterRPCHandle_t *h); + + /**************************************************************************** + * Delete the key to function association created via * + * TSAddClusterRPCFunction(). * + * Return == 0 Success * + * Return != 0 Failure * + * contact: OXY, DY + ****************************************************************************/ + tsapi int TSDeleteClusterRPCFunction(TSClusterRPCHandle_t *h); + + /**************************************************************************** + * Free TSClusterRPCMsg_t received via RPC function * + * contact: OXY, DY + ****************************************************************************/ + tsapi void TSFreeRPCMsg(TSClusterRPCMsg_t *msg, int msg_data_len); + + /**************************************************************************** + * Allocate TSClusterRPCMsg_t for use in TSSendClusterRPC() * + * Return != 0 Success * + * Return == 0 Allocation failed * + * contact: OXY, DY + ****************************************************************************/ + tsapi TSClusterRPCMsg_t *TSAllocClusterRPCMsg(TSClusterRPCHandle_t *h, int data_size); + + /**************************************************************************** + * Send the RPC message to the specified node. * + * Cluster frees the given memory on send. * + * RPC function frees memory on receive. * + * Return == 0 Success * + * Return != 0 Failure * + * contact: OXY, DY + ****************************************************************************/ + tsapi int TSSendClusterRPC(TSNodeHandle_t *nh, TSClusterRPCMsg_t *msg); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __TS_API_EXPERIMENTAL_H__ */ diff --git a/proxy/api/ts/remap.h b/proxy/api/ts/remap.h new file mode 100644 index 00000000..c3913883 --- /dev/null +++ b/proxy/api/ts/remap.h @@ -0,0 +1,133 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#ifndef H_REMAPAPI_H +#define H_REMAPAPI_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#define TSREMAP_VMAJOR 3 /* major version number */ +#define TSREMAP_VMINOR 0 /* minor version number */ +#define TSREMAP_VERSION ((TSREMAP_VMAJOR << 16)|TSREMAP_VMINOR) + + typedef struct _tsremap_api_info + { + unsigned long size; /* in: sizeof(struct _tsremap_api_info) */ + unsigned long tsremap_version; /* in: TS supported version ((major << 16) | minor) */ + } TSRemapInterface; + + + typedef struct _tm_remap_request_info + { + /* Important: You should *not* release these buf pointers or TSMLocs from your plugin! */ + + /* these URL mloc's are read only, use normal ts/ts.h APIs for accesing */ + TSMLoc mapFromUrl; + TSMLoc mapToUrl; + + /* the request URL mloc and buffer pointers are read-write. You can read and modify the + requestUrl using normal ts/ts.h APIs, which is how you change the destination URL. */ + TSMLoc requestUrl; + + /* requestBufp and requestHdrp are the equivalent of calling TSHttpTxnClientReqGet(). */ + TSMBuffer requestBufp; + TSMLoc requestHdrp; + + /* 0 - don't redirect, 1 - use the (new)request URL as a redirect */ + int redirect; + } TSRemapRequestInfo; + + + /* This is the type returned by the TSRemapDoRemap() callback */ + typedef enum + { + TSREMAP_NO_REMAP = 0, /* No remaping was done, continue with next in chain */ + TSREMAP_DID_REMAP = 1, /* Remapping was done, continue with next in chain */ + TSREMAP_NO_REMAP_STOP = 2, /* No remapping was done, and stop plugin chain evaluation */ + TSREMAP_DID_REMAP_STOP = 3, /* Remapping was done, but stop plugin chain evaluation */ + + /* In the future, the following error codes can also be used: + -400 to -499 + -500 to -599 + .... + This would allow a plugin to generate an error page. Right now, + setting the return code to any negative number is equivalent to TSREMAP_NO_REMAP */ + TSREMAP_ERROR = -1 /* Some error, that should generate an error page */ + } TSRemapStatus; + + + + /* ---------------------------------------------------------------------------------- + These are the entry points a plugin can implement. Note that TSRemapInit() and + TSRemapDoRemap() are both required. + ---------------------------------------------------------------------------------- + */ + + /* Plugin initialization - called first. + Mandatory interface function. + Return: TS_SUCCESS + TS_ERROR - error, errbuf can include error message from plugin + */ + TSReturnCode TSRemapInit(TSRemapInterface* api_info, char* errbuf, int errbuf_size); + + + /* Remap new request + Mandatory interface function. + Remap API plugin can/should use SDK API function calls inside this function! + return: TSREMAP_NO_REMAP - No remaping was done, continue with next in chain + TSREMAP_DID_REMAP - Remapping was done, continue with next in chain + TSREMAP_NO_REMAP_STOP - No remapping was done, and stop plugin chain evaluation + TSREMAP_DID_REMAP_STOP - Remapping was done, but stop plugin chain evaluation + */ + TSRemapStatus TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo* rri); + + + /* Plugin shutdown, called when plugin is unloaded. + Optional function. */ + void TSRemapDone(void); + + + /* Plugin new instance. Create new plugin processing entry for unique remap record. + First two arguments in argv vector are - fromURL and toURL from remap record. + Please keep in mind that fromURL and toURL will be converted to canonical view. + Return: TS_SUCESS + TS_ERROR - instance creation error + */ + TSReturnCode TSRemapNewInstance(int argc, char* argv[], void** ih, char* errbuf, int errbuf_size); + void TSRemapDeleteInstance(void*); + + + /* Check response code from Origin Server + os_response_type -> TSServerState + Remap API plugin can use InkAPI function calls inside TSRemapDoRemap() + Return: none + */ + void TSRemapOSResponse(void* ih, TSHttpTxn rh, int os_response_type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* #ifndef H_REMAPAPI_H */ diff --git a/proxy/api/ts/ts.h.in b/proxy/api/ts/ts.h.in new file mode 100644 index 00000000..49d384bd --- /dev/null +++ b/proxy/api/ts/ts.h.in @@ -0,0 +1,2972 @@ +/** @file + + Traffic Server SDK API header file + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + @section developers Developers + + Developers, when adding a new element to an enum, append it. DO NOT + insert it. Otherwise, binary compatibility of plugins will be broken! + + */ + +#ifndef __TS_API_H__ +#define __TS_API_H__ + +/* GENERATED FILE WARNING! DO NOT EDIT ts.h + * + * You must modify ts.h.in instead. + * + */ + +#include + +#include +#include + +#define tsapi + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /* Version info + */ +#define TS_VERSION_STRING "@TS_VERSION_STRING@" +#define TS_VERSION_NUMBER @TS_VERSION_NUMBER@ +#define TS_VERSION_MAJOR @TS_VERSION_MAJOR@ +#define TS_VERSION_MINOR @TS_VERSION_MINOR@ +#define TS_VERSION_MICRO @TS_VERSION_MICRO@ + +#define TS_HTTP_VERSION(a,b) ((((a) & 0xFFFF) << 16) | ((b) & 0xFFFF)) +#define TS_HTTP_MINOR(v) ((v) & 0xFFFF) +#define TS_HTTP_MAJOR(v) (((v) >> 16) & 0xFFFF) +#define __TS_RES_PATH(x) #x +#define _TS_RES_PATH(x) __TS_RES_PATH (x) +#define TS_RES_PATH(x) x __FILE__ ":" _TS_RES_PATH (__LINE__) +#define TS_RES_MEM_PATH TS_RES_PATH ("memory/") +#define TS_MAX_USER_NAME_LEN 256 + +#if __GNUC__ >= 3 +#ifndef TS_DEPRECATED +#define TS_DEPRECATED __attribute__ ((deprecated)) +#endif +#else +#define TS_DEPRECATED +#endif + + /** + The following struct is used by TSPluginRegister(). It stores + registration information about the plugin. + + */ + typedef struct + { + char* plugin_name; + char* vendor_name; + char* support_email; + } TSPluginRegistrationInfo; + + /** + This set of enums are possible values returned by + TSHttpHdrParseReq() and TSHttpHdrParseResp(). + + */ + typedef enum + { + TS_PARSE_ERROR = -1, + TS_PARSE_DONE = 0, + TS_PARSE_OK = 1, + TS_PARSE_CONT = 2 + } TSParseResult; + + /** + This set of enums represents the possible HTTP types that + can be assigned to an HTTP header. When a header is created + with TSHttpHdrCreate(), it is automatically assigned a type of + TS_HTTP_TYPE_UNKNOWN. You can modify the HTTP type ONCE after it + the header is created, using TSHttpHdrTypeSet(). After setting the + HTTP type once, you cannot set it again. Use TSHttpHdrTypeGet() + to obtain the TSHttpType of an HTTP header. + + */ + typedef enum + { + TS_HTTP_TYPE_UNKNOWN, + TS_HTTP_TYPE_REQUEST, + TS_HTTP_TYPE_RESPONSE + } TSHttpType; + + /** + This set of enums represents possible return values from + TSHttpHdrStatusGet(), which retrieves the status code from an + HTTP response header (TSHttpHdrStatusGet() retrieves status codes + only from headers of type TS_HTTP_TYPE_RESPONSE). You can also set + the TSHttpStatus of a response header using TSHttpHdrStatusSet(). + + */ + typedef enum + { + TS_HTTP_STATUS_NONE = 0, + + TS_HTTP_STATUS_CONTINUE = 100, + TS_HTTP_STATUS_SWITCHING_PROTOCOL = 101, + + TS_HTTP_STATUS_OK = 200, + TS_HTTP_STATUS_CREATED = 201, + TS_HTTP_STATUS_ACCEPTED = 202, + TS_HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, + TS_HTTP_STATUS_NO_CONTENT = 204, + TS_HTTP_STATUS_RESET_CONTENT = 205, + TS_HTTP_STATUS_PARTIAL_CONTENT = 206, + + TS_HTTP_STATUS_MULTIPLE_CHOICES = 300, + TS_HTTP_STATUS_MOVED_PERMANENTLY = 301, + TS_HTTP_STATUS_MOVED_TEMPORARILY = 302, + TS_HTTP_STATUS_SEE_OTHER = 303, + TS_HTTP_STATUS_NOT_MODIFIED = 304, + TS_HTTP_STATUS_USE_PROXY = 305, + TS_HTTP_STATUS_TEMPORARY_REDIRECT = 307, + + TS_HTTP_STATUS_BAD_REQUEST = 400, + TS_HTTP_STATUS_UNAUTHORIZED = 401, + TS_HTTP_STATUS_PAYMENT_REQUIRED = 402, + TS_HTTP_STATUS_FORBIDDEN = 403, + TS_HTTP_STATUS_NOT_FOUND = 404, + TS_HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + TS_HTTP_STATUS_NOT_ACCEPTABLE = 406, + TS_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, + TS_HTTP_STATUS_REQUEST_TIMEOUT = 408, + TS_HTTP_STATUS_CONFLICT = 409, + TS_HTTP_STATUS_GONE = 410, + TS_HTTP_STATUS_LENGTH_REQUIRED = 411, + TS_HTTP_STATUS_PRECONDITION_FAILED = 412, + TS_HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE = 413, + TS_HTTP_STATUS_REQUEST_URI_TOO_LONG = 414, + TS_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, + + TS_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + TS_HTTP_STATUS_NOT_IMPLEMENTED = 501, + TS_HTTP_STATUS_BAD_GATEWAY = 502, + TS_HTTP_STATUS_SERVICE_UNAVAILABLE = 503, + TS_HTTP_STATUS_GATEWAY_TIMEOUT = 504, + TS_HTTP_STATUS_HTTPVER_NOT_SUPPORTED = 505 + } TSHttpStatus; + + /** + This set of enums represents the possible hooks where you can + set up continuation callbacks. The functions used to register a + continuation for a particular hook are: + + TSHttpHookAdd: adds a global hook. You can globally add + any hook except for TS_HTTP_REQUEST_TRANSFORM_HOOK and + TS_HTTP_RESPONSE_TRANSFORM_HOOK. + + The following hooks can ONLY be added globally: + - TS_HTTP_SELECT_ALT_HOOK + - TS_HTTP_SSN_START_HOOK + - TS_HTTP_SSN_CLOSE_HOOK + + TSHttpSsnHookAdd: adds a transaction hook to each transaction + within a session. You can only use transaction hooks with this call: + - TS_HTTP_READ_REQUEST_HDR_HOOK + - TS_HTTP_OS_DNS_HOOK + - TS_HTTP_SEND_REQUEST_HDR_HOOK + - TS_HTTP_READ_CACHE_HDR_HOOK + - TS_HTTP_READ_RESPONSE_HDR_HOOK + - TS_HTTP_SEND_RESPONSE_HDR_HOOK + - TS_HTTP_REQUEST_TRANSFORM_HOOK + - TS_HTTP_RESPONSE_TRANSFORM_HOOK + - TS_HTTP_TXN_START_HOOK + - TS_HTTP_TXN_CLOSE_HOOK + + TSHttpTxnHookAdd: adds a callback at a specific point within + an HTTP transaction. The following hooks can be used with this + function: + - TS_HTTP_READ_REQUEST_HDR_HOOK + - TS_HTTP_OS_DNS_HOOK + - TS_HTTP_SEND_REQUEST_HDR_HOOK + - TS_HTTP_READ_CACHE_HDR_HOOK + - TS_HTTP_READ_RESPONSE_HDR_HOOK + - TS_HTTP_SEND_RESPONSE_HDR_HOOK + - TS_HTTP_REQUEST_TRANSFORM_HOOK + - TS_HTTP_RESPONSE_TRANSFORM_HOOK + - TS_HTTP_TXN_CLOSE_HOOK + + The two transform hooks can ONLY be added as transaction hooks. + + TS_HTTP_LAST_HOOK _must_ be the last element. Only right place + to insert a new element is just before TS_HTTP_LAST_HOOK. + + */ + typedef enum + { + TS_HTTP_READ_REQUEST_HDR_HOOK, + TS_HTTP_OS_DNS_HOOK, + TS_HTTP_SEND_REQUEST_HDR_HOOK, + TS_HTTP_READ_CACHE_HDR_HOOK, + TS_HTTP_READ_RESPONSE_HDR_HOOK, + TS_HTTP_SEND_RESPONSE_HDR_HOOK, + TS_HTTP_REQUEST_TRANSFORM_HOOK, + TS_HTTP_RESPONSE_TRANSFORM_HOOK, + TS_HTTP_SELECT_ALT_HOOK, + TS_HTTP_TXN_START_HOOK, + TS_HTTP_TXN_CLOSE_HOOK, + TS_HTTP_SSN_START_HOOK, + TS_HTTP_SSN_CLOSE_HOOK, + TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, + TS_HTTP_PRE_REMAP_HOOK, + TS_HTTP_POST_REMAP_HOOK, + TS_HTTP_LAST_HOOK + } TSHttpHookID; + #define TS_HTTP_READ_REQUEST_PRE_REMAP_HOOK TS_HTTP_PRE_REMAP_HOOK //backwards compat + + typedef enum + { + TS_CACHE_PLUGIN_HOOK, + TS_CACHE_LOOKUP_HOOK, + TS_CACHE_READ_HOOK, + TS_CACHE_WRITE_HOOK, + TS_CACHE_DELETE_HOOK, + TS_CACHE_LAST_HOOK + } TSCacheHookID; + + /** + TSEvents are sent to continuations when they are called back. + The TSEvent provides the continuation's handler function with + information about the callback. Based on the event it receives, + the handler function can decide what to do. + + */ + typedef enum + { + TS_EVENT_NONE = 0, + TS_EVENT_IMMEDIATE = 1, + TS_EVENT_TIMEOUT = 2, + TS_EVENT_ERROR = 3, + TS_EVENT_CONTINUE = 4, + + TS_EVENT_VCONN_READ_READY = 100, + TS_EVENT_VCONN_WRITE_READY = 101, + TS_EVENT_VCONN_READ_COMPLETE = 102, + TS_EVENT_VCONN_WRITE_COMPLETE = 103, + TS_EVENT_VCONN_EOS = 104, + TS_EVENT_VCONN_INACTIVITY_TIMEOUT = 105, + + TS_EVENT_NET_CONNECT = 200, + TS_EVENT_NET_CONNECT_FAILED = 201, + TS_EVENT_NET_ACCEPT = 202, + TS_EVENT_NET_ACCEPT_FAILED = 204, + + /* EVENTS 206 - 212 for internal use */ + TS_EVENT_INTERNAL_206 = 206, + TS_EVENT_INTERNAL_207 = 207, + TS_EVENT_INTERNAL_208 = 208, + TS_EVENT_INTERNAL_209 = 209, + TS_EVENT_INTERNAL_210 = 210, + TS_EVENT_INTERNAL_211 = 211, + TS_EVENT_INTERNAL_212 = 212, + + TS_EVENT_HOST_LOOKUP = 500, + TS_EVENT_CACHE_OPEN_READ = 1102, + TS_EVENT_CACHE_OPEN_READ_FAILED = 1103, + TS_EVENT_CACHE_OPEN_WRITE = 1108, + TS_EVENT_CACHE_OPEN_WRITE_FAILED = 1109, + TS_EVENT_CACHE_REMOVE = 1112, + TS_EVENT_CACHE_REMOVE_FAILED = 1113, + TS_EVENT_CACHE_SCAN = 1120, + TS_EVENT_CACHE_SCAN_FAILED = 1121, + TS_EVENT_CACHE_SCAN_OBJECT = 1122, + TS_EVENT_CACHE_SCAN_OPERATION_BLOCKED = 1123, + TS_EVENT_CACHE_SCAN_OPERATION_FAILED = 1124, + TS_EVENT_CACHE_SCAN_DONE = 1125, + + TS_EVENT_CACHE_LOOKUP = 1126, + TS_EVENT_CACHE_READ = 1127, + TS_EVENT_CACHE_DELETE = 1128, + TS_EVENT_CACHE_WRITE = 1129, + TS_EVENT_CACHE_WRITE_HEADER = 1130, + TS_EVENT_CACHE_CLOSE = 1131, + TS_EVENT_CACHE_LOOKUP_READY = 1132, + TS_EVENT_CACHE_LOOKUP_COMPLETE = 1133, + TS_EVENT_CACHE_READ_READY = 1134, + TS_EVENT_CACHE_READ_COMPLETE = 1135, + + /* EVENT 1200 for internal use */ + TS_EVENT_INTERNAL_1200 = 1200, + + /* EVENT 3900 is corresponding to event AIO_EVENT_DONE defined in I_AIO.h */ + TS_AIO_EVENT_DONE = 3900, + + TS_EVENT_HTTP_CONTINUE = 60000, + TS_EVENT_HTTP_ERROR = 60001, + TS_EVENT_HTTP_READ_REQUEST_HDR = 60002, + TS_EVENT_HTTP_OS_DNS = 60003, + TS_EVENT_HTTP_SEND_REQUEST_HDR = 60004, + TS_EVENT_HTTP_READ_CACHE_HDR = 60005, + TS_EVENT_HTTP_READ_RESPONSE_HDR = 60006, + TS_EVENT_HTTP_SEND_RESPONSE_HDR = 60007, + TS_EVENT_HTTP_REQUEST_TRANSFORM = 60008, + TS_EVENT_HTTP_RESPONSE_TRANSFORM = 60009, + TS_EVENT_HTTP_SELECT_ALT = 60010, + TS_EVENT_HTTP_TXN_START = 60011, + TS_EVENT_HTTP_TXN_CLOSE = 60012, + TS_EVENT_HTTP_SSN_START = 60013, + TS_EVENT_HTTP_SSN_CLOSE = 60014, + TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE = 60015, + TS_EVENT_HTTP_PRE_REMAP = 60016, + TS_EVENT_HTTP_POST_REMAP = 60017, + TS_EVENT_MGMT_UPDATE = 60100, + + /* EVENTS 60200 - 60202 for internal use */ + TS_EVENT_INTERNAL_60200 = 60200, + TS_EVENT_INTERNAL_60201 = 60201, + TS_EVENT_INTERNAL_60202 = 60202 + } TSEvent; + #define TS_EVENT_HTTP_READ_REQUEST_PRE_REMAP TS_EVENT_HTTP_PRE_REMAP //backwards compat + + typedef enum + { TS_SRVSTATE_STATE_UNDEFINED = 0, + TS_SRVSTATE_ACTIVE_TIMEOUT, + TS_SRVSTATE_BAD_INCOMING_RESPONSE, + TS_SRVSTATE_CONNECTION_ALIVE, + TS_SRVSTATE_CONNECTION_CLOSED, + TS_SRVSTATE_CONNECTION_ERROR, + TS_SRVSTATE_INACTIVE_TIMEOUT, + TS_SRVSTATE_OPEN_RAW_ERROR, + TS_SRVSTATE_PARSE_ERROR, + TS_SRVSTATE_TRANSACTION_COMPLETE, + TS_SRVSTATE_CONGEST_CONTROL_CONGESTED_ON_F, + TS_SRVSTATE_CONGEST_CONTROL_CONGESTED_ON_M + } TSServerState; + + typedef enum + { + TS_LOOKUP_UNDEFINED_LOOKUP, + TS_LOOKUP_ICP_SUGGESTED_HOST, + TS_LOOKUP_PARENT_PROXY, + TS_LOOKUP_ORIGIN_SERVER, + TS_LOOKUP_INCOMING_ROUTER, + TS_LOOKUP_HOST_NONE + } TSLookingUpType; + + typedef enum + { + TS_CACHE_LOOKUP_MISS, + TS_CACHE_LOOKUP_HIT_STALE, + TS_CACHE_LOOKUP_HIT_FRESH, + TS_CACHE_LOOKUP_SKIPPED + } TSCacheLookupResult; + + typedef enum + { + TS_CACHE_DATA_TYPE_NONE, + TS_CACHE_DATA_TYPE_HTTP, + TS_CACHE_DATA_TYPE_OTHER + } TSCacheDataType; + + typedef enum + { + TS_CACHE_ERROR_NO_DOC = -20400, + TS_CACHE_ERROR_DOC_BUSY = -20401, + TS_CACHE_ERROR_NOT_READY = -20407 + } TSCacheError; + + typedef enum + { + TS_CACHE_SCAN_RESULT_DONE = 0, + TS_CACHE_SCAN_RESULT_CONTINUE = 1, + TS_CACHE_SCAN_RESULT_DELETE = 10, + TS_CACHE_SCAN_RESULT_DELETE_ALL_ALTERNATES, + TS_CACHE_SCAN_RESULT_UPDATE, + TS_CACHE_SCAN_RESULT_RETRY + } TSCacheScanResult; + + typedef enum + { + TS_DATA_ALLOCATE, + TS_DATA_MALLOCED, + TS_DATA_CONSTANT + } TSIOBufferDataFlags; + + typedef enum + { + TS_VC_CLOSE_ABORT = -1, + TS_VC_CLOSE_NORMAL = 1 + } TSVConnCloseFlags; + + typedef enum + { + TS_IOBUFFER_SIZE_INDEX_128 = 0, + TS_IOBUFFER_SIZE_INDEX_256 = 1, + TS_IOBUFFER_SIZE_INDEX_512 = 2, + TS_IOBUFFER_SIZE_INDEX_1K = 3, + TS_IOBUFFER_SIZE_INDEX_2K = 4, + TS_IOBUFFER_SIZE_INDEX_4K = 5, + TS_IOBUFFER_SIZE_INDEX_8K = 6, + TS_IOBUFFER_SIZE_INDEX_16K = 7, + TS_IOBUFFER_SIZE_INDEX_32K = 8 + } TSIOBufferSizeIndex; + + /** + Starting 2.0, SDK now follows same versioning as Traffic Server. + */ + typedef enum + { + TS_SDK_VERSION_2_0 = 0, + TS_SDK_VERSION_3_0 + } TSSDKVersion; + + typedef enum + { + TS_ERROR = -1, + TS_SUCCESS = 0 + } TSReturnCode; + + typedef enum + { + NO_CALLBACK = 0, + AFTER_HEADER , + AFTER_BODY + } TSFetchWakeUpOptions; + + /** + This type represents a context for data records. + */ + typedef enum + { + TS_RECORDTYPE_NULL = 0, + TS_RECORDTYPE_CONFIG, + TS_RECORDTYPE_PROCESS, + TS_RECORDTYPE_NODE, + TS_RECORDTYPE_CLUSTER, + TS_RECORDTYPE_LOCAL, + TS_RECORDTYPE_PLUGIN, + TS_RECORDTYPE_MAX + } TSRecordType; + + typedef enum + { + TS_RECORDDATATYPE_NULL = 0, + TS_RECORDDATATYPE_INT, + TS_RECORDDATATYPE_FLOAT, + TS_RECORDDATATYPE_STRING, + TS_RECORDDATATYPE_COUNTER, + TS_RECORDDATATYPE_MAX + } TSRecordDataType; + + typedef union + { + int64_t rec_int; + float rec_float; + char* rec_string; + int64_t rec_counter; + } TSRecordData; + + typedef enum + { + TS_CONFIG_NULL = -1, + // The order of these enum's must match the order of + // struct OverridableHttpConfigParams in HttpConfig.h. + TS_CONFIG_URL_REMAP_PRISTINE_HOST_HDR, + TS_CONFIG_HTTP_CHUNKING_ENABLED, + TS_CONFIG_HTTP_NEGATIVE_CACHING_ENABLED, + TS_CONFIG_HTTP_NEGATIVE_CACHING_LIFETIME, + TS_CONFIG_HTTP_CACHE_WHEN_TO_REVALIDATE, + TS_CONFIG_HTTP_KEEP_ALIVE_ENABLED_IN, + TS_CONFIG_HTTP_KEEP_ALIVE_ENABLED_OUT, + TS_CONFIG_HTTP_KEEP_ALIVE_POST_OUT, + TS_CONFIG_NET_SOCK_RECV_BUFFER_SIZE_OUT, + TS_CONFIG_NET_SOCK_SEND_BUFFER_SIZE_OUT, + TS_CONFIG_NET_SOCK_OPTION_FLAG_OUT, + TS_CONFIG_HTTP_FORWARD_PROXY_AUTH_TO_PARENT, + TS_CONFIG_HTTP_ANONYMIZE_REMOVE_FROM, + TS_CONFIG_HTTP_ANONYMIZE_REMOVE_REFERER, + TS_CONFIG_HTTP_ANONYMIZE_REMOVE_USER_AGENT, + TS_CONFIG_HTTP_ANONYMIZE_REMOVE_COOKIE, + TS_CONFIG_HTTP_ANONYMIZE_REMOVE_CLIENT_IP, + TS_CONFIG_HTTP_ANONYMIZE_INSERT_CLIENT_IP, + TS_CONFIG_HTTP_APPEND_XFORWARDS_HEADER, + TS_CONFIG_HTTP_RESPONSE_SERVER_ENABLED, + TS_CONFIG_HTTP_INSERT_SQUID_X_FORWARDED_FOR, + TS_CONFIG_HTTP_SEND_HTTP11_REQUESTS, + TS_CONFIG_HTTP_CACHE_HTTP, + TS_CONFIG_HTTP_CACHE_IGNORE_CLIENT_NO_CACHE, + TS_CONFIG_HTTP_CACHE_IGNORE_CLIENT_CC_MAX_AGE, + TS_CONFIG_HTTP_CACHE_IMS_ON_CLIENT_NO_CACHE, + TS_CONFIG_HTTP_CACHE_IGNORE_SERVER_NO_CACHE, + TS_CONFIG_HTTP_CACHE_CACHE_RESPONSES_TO_COOKIES, + TS_CONFIG_HTTP_CACHE_IGNORE_AUTHENTICATION, + TS_CONFIG_HTTP_CACHE_CACHE_URLS_THAT_LOOK_DYNAMIC, + TS_CONFIG_HTTP_CACHE_REQUIRED_HEADERS, + TS_CONFIG_HTTP_INSERT_REQUEST_VIA_STR, + TS_CONFIG_HTTP_INSERT_RESPONSE_VIA_STR, + TS_CONFIG_HTTP_CACHE_HEURISTIC_MIN_LIFETIME, + TS_CONFIG_HTTP_CACHE_HEURISTIC_MAX_LIFETIME, + TS_CONFIG_HTTP_CACHE_GUARANTEED_MIN_LIFETIME, + TS_CONFIG_HTTP_CACHE_GUARANTEED_MAX_LIFETIME, + TS_CONFIG_HTTP_CACHE_MAX_STALE_AGE, + TS_CONFIG_HTTP_KEEP_ALIVE_NO_ACTIVITY_TIMEOUT_IN, + TS_CONFIG_HTTP_TRANSACTION_NO_ACTIVITY_TIMEOUT_IN, + TS_CONFIG_HTTP_TRANSACTION_NO_ACTIVITY_TIMEOUT_OUT, + TS_CONFIG_HTTP_TRANSACTION_ACTIVE_TIMEOUT_OUT, + TS_CONFIG_HTTP_ORIGIN_MAX_CONNECTIONS, + TS_CONFIG_HTTP_CONNECT_ATTEMPTS_MAX_RETRIES, + TS_CONFIG_HTTP_CONNECT_ATTEMPTS_MAX_RETRIES_DEAD_SERVER, + TS_CONFIG_HTTP_CONNECT_ATTEMPTS_RR_RETRIES, + TS_CONFIG_HTTP_CONNECT_ATTEMPTS_TIMEOUT, + TS_CONFIG_HTTP_POST_CONNECT_ATTEMPTS_TIMEOUT, + TS_CONFIG_HTTP_DOWN_SERVER_CACHE_TIME, + TS_CONFIG_HTTP_DOWN_SERVER_ABORT_THRESHOLD, + TS_CONFIG_HTTP_CACHE_FUZZ_TIME, + TS_CONFIG_HTTP_CACHE_FUZZ_MIN_TIME, + TS_CONFIG_HTTP_DOC_IN_CACHE_SKIP_DNS, + + // Strings and floats must come after all the integer configs + TS_CONFIG_HTTP_RESPONSE_SERVER_STR, + TS_CONFIG_HTTP_CACHE_HEURISTIC_LM_FACTOR, + TS_CONFIG_HTTP_CACHE_FUZZ_PROBABILITY, + TS_CONFIG_LAST_ENTRY + } TSOverridableConfigKey; + + /* The TASK pool of threads is the primary method of off-loading continuations from the + net-threads. Configure this with proxy.config.task_threads in records.config. */ + typedef enum + { + TS_THREAD_POOL_DEFAULT = -1, + TS_THREAD_POOL_NET, + TS_THREAD_POOL_TASK, + /* unlikely you should use these */ + TS_THREAD_POOL_SSL, + TS_THREAD_POOL_DNS, + TS_THREAD_POOL_REMAP, + TS_THREAD_POOL_CLUSTER, + TS_THREAD_POOL_UDP + } TSThreadPool; + + typedef int64_t TSHRTime; + + /* These typedefs are used with the corresponding TSMgmt*Get functions + for storing the values retrieved by those functions. For example, + TSMgmtCounterGet() retrieves an TSMgmtCounter. */ + typedef int64_t TSMgmtInt; + typedef int64_t TSMgmtCounter; + typedef float TSMgmtFloat; + typedef char* TSMgmtString; + + typedef struct tsapi_file* TSFile; + + typedef struct tsapi_mloc* TSMLoc; + typedef struct tsapi_mbuffer* TSMBuffer; + typedef struct tsapi_httpssn* TSHttpSsn; + typedef struct tsapi_httptxn* TSHttpTxn; + typedef struct tsapi_httpaltinfo* TSHttpAltInfo; + typedef struct tsapi_mimeparser* TSMimeParser; + typedef struct tsapi_httpparser* TSHttpParser; + typedef struct tsapi_cachekey* TSCacheKey; + typedef struct tsapi_cachehttpinfo* TSCacheHttpInfo; + typedef struct tsapi_cachetxn* TSCacheTxn; + + typedef struct tsapi_vio* TSVIO; + typedef struct tsapi_thread* TSThread; + typedef struct tsapi_mutex* TSMutex; + typedef struct tsapi_config* TSConfig; + typedef struct tsapi_cont* TSCont; + typedef struct tsapi_cont* TSVConn; /* a VConn is really a specialized TSCont */ + typedef struct tsapi_action* TSAction; + typedef struct tsapi_iobuffer* TSIOBuffer; + typedef struct tsapi_iobufferdata* TSIOBufferData; + typedef struct tsapi_bufferblock* TSIOBufferBlock; + typedef struct tsapi_bufferreader* TSIOBufferReader; + typedef struct tsapi_hostlookupresult* TSHostLookupResult; + typedef struct tsapi_aiocallback* TSAIOCallback; + + typedef void *(*TSThreadFunc) (void* data); + typedef int (*TSEventFunc) (TSCont contp, TSEvent event, void* edata); + typedef void (*TSConfigDestroyFunc) (void* data); + + typedef struct + { + int success_event_id; + int failure_event_id; + int timeout_event_id; + } TSFetchEvent; + + typedef struct TSFetchUrlParams + { + const char* request; + int request_len; + struct sockaddr_storage ip; + int port; + TSCont contp; + TSFetchEvent events; + TSFetchWakeUpOptions options; + struct TSFetchUrlParams* next; + } TSFetchUrlParams_t; + + /* -------------------------------------------------------------------------- + Init */ + + /** + This function must be defined by all plugins. Traffic Server + calls this initialization routine when it loads the plugin (at + startup), and sets argc and argv appropriately based on the values + in plugin.config. + + @param argc the number of initial values specified in plugin.config, + plus one. If only the name of your plugin shared object is + specified in plugin.config, argc=1. + @param argv the vector of arguments. The length of argv is argc. + argv[0] is the name of the plugin shared library. Subsequent + values of argv are initialization values specified in + plugin.config. + + */ + extern tsapi void TSPluginInit(int argc, const char* argv[]); + + /* -------------------------------------------------------------------------- + License */ + /** + This function lets Traffic Server know that a license key is + required for the plugin. You implement this function to return the + necessary value. If a license is required, Traffic Server looks + at the plugin.db file for the license key. If this function is + not defined, a license is not required. Use the gen_key tool to + generate license keys. + + @return Zero if no license is required. Returns 1 if a license + is required. + */ + extern tsapi int TSPluginLicenseRequired(void); + + /* -------------------------------------------------------------------------- + URL schemes */ + extern tsapi const char* TS_URL_SCHEME_FILE; + extern tsapi const char* TS_URL_SCHEME_FTP; + extern tsapi const char* TS_URL_SCHEME_GOPHER; + extern tsapi const char* TS_URL_SCHEME_HTTP; + extern tsapi const char* TS_URL_SCHEME_HTTPS; + extern tsapi const char* TS_URL_SCHEME_MAILTO; + extern tsapi const char* TS_URL_SCHEME_NEWS; + extern tsapi const char* TS_URL_SCHEME_NNTP; + extern tsapi const char* TS_URL_SCHEME_PROSPERO; + extern tsapi const char* TS_URL_SCHEME_TELNET; + extern tsapi const char* TS_URL_SCHEME_TUNNEL; + extern tsapi const char* TS_URL_SCHEME_WAIS; + extern tsapi const char* TS_URL_SCHEME_PNM; + extern tsapi const char* TS_URL_SCHEME_RTSP; + extern tsapi const char* TS_URL_SCHEME_RTSPU; + extern tsapi const char* TS_URL_SCHEME_MMS; + extern tsapi const char* TS_URL_SCHEME_MMSU; + extern tsapi const char* TS_URL_SCHEME_MMST; + + /* -------------------------------------------------------------------------- + URL scheme string lengths */ + extern tsapi int TS_URL_LEN_FILE; + extern tsapi int TS_URL_LEN_FTP; + extern tsapi int TS_URL_LEN_GOPHER; + extern tsapi int TS_URL_LEN_HTTP; + extern tsapi int TS_URL_LEN_HTTPS; + extern tsapi int TS_URL_LEN_MAILTO; + extern tsapi int TS_URL_LEN_NEWS; + extern tsapi int TS_URL_LEN_NNTP; + extern tsapi int TS_URL_LEN_PROSPERO; + extern tsapi int TS_URL_LEN_TELNET; + extern tsapi int TS_URL_LEN_WAIS; + + /* -------------------------------------------------------------------------- + MIME fields */ + extern tsapi const char* TS_MIME_FIELD_ACCEPT; + extern tsapi const char* TS_MIME_FIELD_ACCEPT_CHARSET; + extern tsapi const char* TS_MIME_FIELD_ACCEPT_ENCODING; + extern tsapi const char* TS_MIME_FIELD_ACCEPT_LANGUAGE; + extern tsapi const char* TS_MIME_FIELD_ACCEPT_RANGES; + extern tsapi const char* TS_MIME_FIELD_AGE; + extern tsapi const char* TS_MIME_FIELD_ALLOW; + extern tsapi const char* TS_MIME_FIELD_APPROVED; + extern tsapi const char* TS_MIME_FIELD_AUTHORIZATION; + extern tsapi const char* TS_MIME_FIELD_BYTES; + extern tsapi const char* TS_MIME_FIELD_CACHE_CONTROL; + extern tsapi const char* TS_MIME_FIELD_CLIENT_IP; + extern tsapi const char* TS_MIME_FIELD_CONNECTION; + extern tsapi const char* TS_MIME_FIELD_CONTENT_BASE; + extern tsapi const char* TS_MIME_FIELD_CONTENT_ENCODING; + extern tsapi const char* TS_MIME_FIELD_CONTENT_LANGUAGE; + extern tsapi const char* TS_MIME_FIELD_CONTENT_LENGTH; + extern tsapi const char* TS_MIME_FIELD_CONTENT_LOCATION; + extern tsapi const char* TS_MIME_FIELD_CONTENT_MD5; + extern tsapi const char* TS_MIME_FIELD_CONTENT_RANGE; + extern tsapi const char* TS_MIME_FIELD_CONTENT_TYPE; + extern tsapi const char* TS_MIME_FIELD_CONTROL; + extern tsapi const char* TS_MIME_FIELD_COOKIE; + extern tsapi const char* TS_MIME_FIELD_DATE; + extern tsapi const char* TS_MIME_FIELD_DISTRIBUTION; + extern tsapi const char* TS_MIME_FIELD_ETAG; + extern tsapi const char* TS_MIME_FIELD_EXPECT; + extern tsapi const char* TS_MIME_FIELD_EXPIRES; + extern tsapi const char* TS_MIME_FIELD_FOLLOWUP_TO; + extern tsapi const char* TS_MIME_FIELD_FROM; + extern tsapi const char* TS_MIME_FIELD_HOST; + extern tsapi const char* TS_MIME_FIELD_IF_MATCH; + extern tsapi const char* TS_MIME_FIELD_IF_MODIFIED_SINCE; + extern tsapi const char* TS_MIME_FIELD_IF_NONE_MATCH; + extern tsapi const char* TS_MIME_FIELD_IF_RANGE; + extern tsapi const char* TS_MIME_FIELD_IF_UNMODIFIED_SINCE; + extern tsapi const char* TS_MIME_FIELD_KEEP_ALIVE; + extern tsapi const char* TS_MIME_FIELD_KEYWORDS; + extern tsapi const char* TS_MIME_FIELD_LAST_MODIFIED; + extern tsapi const char* TS_MIME_FIELD_LINES; + extern tsapi const char* TS_MIME_FIELD_LOCATION; + extern tsapi const char* TS_MIME_FIELD_MAX_FORWARDS; + extern tsapi const char* TS_MIME_FIELD_MESSAGE_ID; + extern tsapi const char* TS_MIME_FIELD_NEWSGROUPS; + extern tsapi const char* TS_MIME_FIELD_ORGANIZATION; + extern tsapi const char* TS_MIME_FIELD_PATH; + extern tsapi const char* TS_MIME_FIELD_PRAGMA; + extern tsapi const char* TS_MIME_FIELD_PROXY_AUTHENTICATE; + extern tsapi const char* TS_MIME_FIELD_PROXY_AUTHORIZATION; + extern tsapi const char* TS_MIME_FIELD_PROXY_CONNECTION; + extern tsapi const char* TS_MIME_FIELD_PUBLIC; + extern tsapi const char* TS_MIME_FIELD_RANGE; + extern tsapi const char* TS_MIME_FIELD_REFERENCES; + extern tsapi const char* TS_MIME_FIELD_REFERER; + extern tsapi const char* TS_MIME_FIELD_REPLY_TO; + extern tsapi const char* TS_MIME_FIELD_RETRY_AFTER; + extern tsapi const char* TS_MIME_FIELD_SENDER; + extern tsapi const char* TS_MIME_FIELD_SERVER; + extern tsapi const char* TS_MIME_FIELD_SET_COOKIE; + extern tsapi const char* TS_MIME_FIELD_SUBJECT; + extern tsapi const char* TS_MIME_FIELD_SUMMARY; + extern tsapi const char* TS_MIME_FIELD_TE; + extern tsapi const char* TS_MIME_FIELD_TRANSFER_ENCODING; + extern tsapi const char* TS_MIME_FIELD_UPGRADE; + extern tsapi const char* TS_MIME_FIELD_USER_AGENT; + extern tsapi const char* TS_MIME_FIELD_VARY; + extern tsapi const char* TS_MIME_FIELD_VIA; + extern tsapi const char* TS_MIME_FIELD_WARNING; + extern tsapi const char* TS_MIME_FIELD_WWW_AUTHENTICATE; + extern tsapi const char* TS_MIME_FIELD_XREF; + extern tsapi const char* TS_MIME_FIELD_X_FORWARDED_FOR; + + /* -------------------------------------------------------------------------- + MIME fields string lengths */ + extern tsapi int TS_MIME_LEN_ACCEPT; + extern tsapi int TS_MIME_LEN_ACCEPT_CHARSET; + extern tsapi int TS_MIME_LEN_ACCEPT_ENCODING; + extern tsapi int TS_MIME_LEN_ACCEPT_LANGUAGE; + extern tsapi int TS_MIME_LEN_ACCEPT_RANGES; + extern tsapi int TS_MIME_LEN_AGE; + extern tsapi int TS_MIME_LEN_ALLOW; + extern tsapi int TS_MIME_LEN_APPROVED; + extern tsapi int TS_MIME_LEN_AUTHORIZATION; + extern tsapi int TS_MIME_LEN_BYTES; + extern tsapi int TS_MIME_LEN_CACHE_CONTROL; + extern tsapi int TS_MIME_LEN_CLIENT_IP; + extern tsapi int TS_MIME_LEN_CONNECTION; + extern tsapi int TS_MIME_LEN_CONTENT_BASE; + extern tsapi int TS_MIME_LEN_CONTENT_ENCODING; + extern tsapi int TS_MIME_LEN_CONTENT_LANGUAGE; + extern tsapi int TS_MIME_LEN_CONTENT_LENGTH; + extern tsapi int TS_MIME_LEN_CONTENT_LOCATION; + extern tsapi int TS_MIME_LEN_CONTENT_MD5; + extern tsapi int TS_MIME_LEN_CONTENT_RANGE; + extern tsapi int TS_MIME_LEN_CONTENT_TYPE; + extern tsapi int TS_MIME_LEN_CONTROL; + extern tsapi int TS_MIME_LEN_COOKIE; + extern tsapi int TS_MIME_LEN_DATE; + extern tsapi int TS_MIME_LEN_DISTRIBUTION; + extern tsapi int TS_MIME_LEN_ETAG; + extern tsapi int TS_MIME_LEN_EXPECT; + extern tsapi int TS_MIME_LEN_EXPIRES; + extern tsapi int TS_MIME_LEN_FOLLOWUP_TO; + extern tsapi int TS_MIME_LEN_FROM; + extern tsapi int TS_MIME_LEN_HOST; + extern tsapi int TS_MIME_LEN_IF_MATCH; + extern tsapi int TS_MIME_LEN_IF_MODIFIED_SINCE; + extern tsapi int TS_MIME_LEN_IF_NONE_MATCH; + extern tsapi int TS_MIME_LEN_IF_RANGE; + extern tsapi int TS_MIME_LEN_IF_UNMODIFIED_SINCE; + extern tsapi int TS_MIME_LEN_KEEP_ALIVE; + extern tsapi int TS_MIME_LEN_KEYWORDS; + extern tsapi int TS_MIME_LEN_LAST_MODIFIED; + extern tsapi int TS_MIME_LEN_LINES; + extern tsapi int TS_MIME_LEN_LOCATION; + extern tsapi int TS_MIME_LEN_MAX_FORWARDS; + extern tsapi int TS_MIME_LEN_MESSAGE_ID; + extern tsapi int TS_MIME_LEN_NEWSGROUPS; + extern tsapi int TS_MIME_LEN_ORGANIZATION; + extern tsapi int TS_MIME_LEN_PATH; + extern tsapi int TS_MIME_LEN_PRAGMA; + extern tsapi int TS_MIME_LEN_PROXY_AUTHENTICATE; + extern tsapi int TS_MIME_LEN_PROXY_AUTHORIZATION; + extern tsapi int TS_MIME_LEN_PROXY_CONNECTION; + extern tsapi int TS_MIME_LEN_PUBLIC; + extern tsapi int TS_MIME_LEN_RANGE; + extern tsapi int TS_MIME_LEN_REFERENCES; + extern tsapi int TS_MIME_LEN_REFERER; + extern tsapi int TS_MIME_LEN_REPLY_TO; + extern tsapi int TS_MIME_LEN_RETRY_AFTER; + extern tsapi int TS_MIME_LEN_SENDER; + extern tsapi int TS_MIME_LEN_SERVER; + extern tsapi int TS_MIME_LEN_SET_COOKIE; + extern tsapi int TS_MIME_LEN_SUBJECT; + extern tsapi int TS_MIME_LEN_SUMMARY; + extern tsapi int TS_MIME_LEN_TE; + extern tsapi int TS_MIME_LEN_TRANSFER_ENCODING; + extern tsapi int TS_MIME_LEN_UPGRADE; + extern tsapi int TS_MIME_LEN_USER_AGENT; + extern tsapi int TS_MIME_LEN_VARY; + extern tsapi int TS_MIME_LEN_VIA; + extern tsapi int TS_MIME_LEN_WARNING; + extern tsapi int TS_MIME_LEN_WWW_AUTHENTICATE; + extern tsapi int TS_MIME_LEN_XREF; + extern tsapi int TS_MIME_LEN_X_FORWARDED_FOR; + + /* -------------------------------------------------------------------------- + HTTP values */ + extern tsapi const char* TS_HTTP_VALUE_BYTES; + extern tsapi const char* TS_HTTP_VALUE_CHUNKED; + extern tsapi const char* TS_HTTP_VALUE_CLOSE; + extern tsapi const char* TS_HTTP_VALUE_COMPRESS; + extern tsapi const char* TS_HTTP_VALUE_DEFLATE; + extern tsapi const char* TS_HTTP_VALUE_GZIP; + extern tsapi const char* TS_HTTP_VALUE_IDENTITY; + extern tsapi const char* TS_HTTP_VALUE_KEEP_ALIVE; + extern tsapi const char* TS_HTTP_VALUE_MAX_AGE; + extern tsapi const char* TS_HTTP_VALUE_MAX_STALE; + extern tsapi const char* TS_HTTP_VALUE_MIN_FRESH; + extern tsapi const char* TS_HTTP_VALUE_MUST_REVALIDATE; + extern tsapi const char* TS_HTTP_VALUE_NONE; + extern tsapi const char* TS_HTTP_VALUE_NO_CACHE; + extern tsapi const char* TS_HTTP_VALUE_NO_STORE; + extern tsapi const char* TS_HTTP_VALUE_NO_TRANSFORM; + extern tsapi const char* TS_HTTP_VALUE_ONLY_IF_CACHED; + extern tsapi const char* TS_HTTP_VALUE_PRIVATE; + extern tsapi const char* TS_HTTP_VALUE_PROXY_REVALIDATE; + extern tsapi const char* TS_HTTP_VALUE_PUBLIC; + + /* -------------------------------------------------------------------------- + HTTP values string lengths */ + extern tsapi int TS_HTTP_LEN_BYTES; + extern tsapi int TS_HTTP_LEN_CHUNKED; + extern tsapi int TS_HTTP_LEN_CLOSE; + extern tsapi int TS_HTTP_LEN_COMPRESS; + extern tsapi int TS_HTTP_LEN_DEFLATE; + extern tsapi int TS_HTTP_LEN_GZIP; + extern tsapi int TS_HTTP_LEN_IDENTITY; + extern tsapi int TS_HTTP_LEN_KEEP_ALIVE; + extern tsapi int TS_HTTP_LEN_MAX_AGE; + extern tsapi int TS_HTTP_LEN_MAX_STALE; + extern tsapi int TS_HTTP_LEN_MIN_FRESH; + extern tsapi int TS_HTTP_LEN_MUST_REVALIDATE; + extern tsapi int TS_HTTP_LEN_NONE; + extern tsapi int TS_HTTP_LEN_NO_CACHE; + extern tsapi int TS_HTTP_LEN_NO_STORE; + extern tsapi int TS_HTTP_LEN_NO_TRANSFORM; + extern tsapi int TS_HTTP_LEN_ONLY_IF_CACHED; + extern tsapi int TS_HTTP_LEN_PRIVATE; + extern tsapi int TS_HTTP_LEN_PROXY_REVALIDATE; + extern tsapi int TS_HTTP_LEN_PUBLIC; + + /* -------------------------------------------------------------------------- + HTTP methods */ + extern tsapi const char* TS_HTTP_METHOD_CONNECT; + extern tsapi const char* TS_HTTP_METHOD_DELETE; + extern tsapi const char* TS_HTTP_METHOD_GET; + extern tsapi const char* TS_HTTP_METHOD_HEAD; + extern tsapi const char* TS_HTTP_METHOD_ICP_QUERY; + extern tsapi const char* TS_HTTP_METHOD_OPTIONS; + extern tsapi const char* TS_HTTP_METHOD_POST; + extern tsapi const char* TS_HTTP_METHOD_PURGE; + extern tsapi const char* TS_HTTP_METHOD_PUT; + extern tsapi const char* TS_HTTP_METHOD_TRACE; + + /* -------------------------------------------------------------------------- + HTTP methods string lengths */ + extern tsapi int TS_HTTP_LEN_CONNECT; + extern tsapi int TS_HTTP_LEN_DELETE; + extern tsapi int TS_HTTP_LEN_GET; + extern tsapi int TS_HTTP_LEN_HEAD; + extern tsapi int TS_HTTP_LEN_ICP_QUERY; + extern tsapi int TS_HTTP_LEN_OPTIONS; + extern tsapi int TS_HTTP_LEN_POST; + extern tsapi int TS_HTTP_LEN_PURGE; + extern tsapi int TS_HTTP_LEN_PUT; + extern tsapi int TS_HTTP_LEN_TRACE; + + /* -------------------------------------------------------------------------- + MLoc Constants */ + /** + Use TS_NULL_MLOC as the parent in calls that require a parent + when an TSMLoc does not have a parent TSMLoc. For example if + the TSMLoc is obtained by a call to TSHttpTxnClientReqGet(), + + */ + extern tsapi const TSMLoc TS_NULL_MLOC; + + /* -------------------------------------------------------------------------- + Memory */ +#define TSmalloc(s) _TSmalloc ((s), TS_RES_MEM_PATH) +#define TSrealloc(p,s) _TSrealloc ((p), (s), TS_RES_MEM_PATH) +#define TSstrdup(p) _TSstrdup ((p), -1, TS_RES_MEM_PATH) +#define TSstrndup(p,n) _TSstrdup ((p), (n), TS_RES_MEM_PATH) +#define TSfree(p) _TSfree (p) + + tsapi void* _TSmalloc(size_t size, const char* path); + tsapi void* _TSrealloc(void* ptr, size_t size, const char* path); + tsapi char* _TSstrdup(const char* str, int64_t length, const char* path); + tsapi void _TSfree(void* ptr); + + /* -------------------------------------------------------------------------- + Component object handles */ + /** + Releases the TSMLoc mloc created from the TSMLoc parent. + If there is no parent TSMLoc, use TS_NULL_MLOC. + + @param bufp marshal buffer containing the TSMLoc handle to be + released. + @param parent location of the parent object from which the handle + was created. + @param mloc location of the handle to be released. + + */ + tsapi TSReturnCode TSHandleMLocRelease(TSMBuffer bufp, TSMLoc parent, TSMLoc mloc); + + /* -------------------------------------------------------------------------- + Install and plugin locations */ + /** + Gets the path of the directory in which Traffic Server is installed. + Use this function to specify the location of files that the + plugin uses. + + @return pointer to Traffic Server install directory. + + */ + tsapi const char* TSInstallDirGet(void); + + /** + Gets the path of the directory of Traffic Server configuration. + + @return pointer to Traffic Server configuration directory. + + */ + tsapi const char* TSConfigDirGet(void); + + /** + Gets the path of the plugin directory relative to the Traffic Server + install directory. For example, to open the file "config_ui.txt" in + the plugin directory: + + @code + TSfopen("TSPluginInstallDirGet()/TSPluginDirGet()/config_ui.txt"); + @endcode + + @return pointer to plugin directory relative to Traffic Server install + directory. + + */ + tsapi const char* TSPluginDirGet(void); + + /* -------------------------------------------------------------------------- + Traffic Server Version */ + /** + Gets the version of Traffic Server currently running. Use this + function to make sure that the plugin version and Traffic Server + version are compatible. See the SDK sample code for usage. + + @return pointer to version of Traffic Server running the plugin. + + */ + tsapi const char* TSTrafficServerVersionGet(void); + + /** Get the major version of Traffic Server currently running. + This is the same as the first element of the string + returned by @c TSTrafficServerVersionGet + + @return The major version as an integer. + */ + int TSTrafficServerVersionGetMajor(void); + + /** Get the minor version of Traffic Server currently running. + This is the same as the second element of the string + returned by @c TSTrafficServerVersionGet + + @return The minor version as an integer. + */ + int TSTrafficServerVersionGetMinor(void); + + /** Get the patch version of Traffic Server currently running. + This is the same as the third element of the string + returned by @c TSTrafficServerVersionGet + + @return The patch version as an integer. + */ + int TSTrafficServerVersionGetPatch(void); + + /* -------------------------------------------------------------------------- + Plugin registration */ + + /** + This function registers your plugin with a particular version + of Traffic Server SDK. Use this function to make sure that the + Traffic Server version currently running also supports your plugin. + See the SDK sample code for usage. + + @param sdk_version earliest version of the Traffic Server SDK that + supports your plugin. + @param plugin_info contains registration information about your + plugin. See TSPluginRegistrationInfo. + @return TS_ERROR if the plugin registration failed. + + */ + tsapi TSReturnCode TSPluginRegister(TSSDKVersion sdk_version, TSPluginRegistrationInfo* plugin_info); + + /* -------------------------------------------------------------------------- + Files */ + /** + Opens a file for reading or writing and returns a descriptor for + accessing the file. The current implementation cannot open a file + for both reading or writing. See the SDK Programmer's Guide for + sample code. + + @param filename file to be opened. + @param mode specifies whether to open the file for reading or + writing. If mode is "r" then the file is opened for reading. + If mode is "w" then the file is opened for writing. Currently + "r" and "w" are the only two valid modes for opening a file. + @return descriptor for the file that TSfopen opens. Descriptors of + type TSFile can be greater than 256. + + */ + tsapi TSFile TSfopen(const char* filename, const char* mode); + + /** + Closes the file to which filep points and frees the data structures + and buffers associated with it. If the file was opened for writing, + any pending data is flushed. + + @param filep file to be closed. + + */ + tsapi void TSfclose(TSFile filep); + + /** + Attempts to read length bytes of data from the file pointed to by + filep into the buffer buf. + + @param filep name of the file to read from. + @param buf buffer to read into. + @param length amount of data to read, in bytes. + @return number of bytes read. If end of the file, it returns 0. + If the file was not opened for reading or if an error occurs + while reading the file, it returns -1. + + */ + tsapi size_t TSfread(TSFile filep, void* buf, size_t length); + + /** + Attempts to write length bytes of data from the buffer buf + to the file filep. Make sure that filep is open for writing. + You might want to check the number of bytes written (TSfwrite() + returns this value) against the value of length. If it is less, + there might be insufficient space on disk, for example. + + @param filep file to write into. + @param buf buffer containing the data to be written. + @param length amount of data to write to filep, in bytes. + @return number of bytes written to filep. If the file was not + opened for writing, it returns -1. If an error occurs while + writing, it returns the number of bytes successfully written. + + */ + tsapi size_t TSfwrite(TSFile filep, const void* buf, size_t length); + + /** + Flushes pending data that has been buffered up in memory from + previous calls to TSfwrite(). + + @param filep file to flush. + + */ + tsapi void TSfflush(TSFile filep); + + /** + Reads a line from the file pointed to by filep into the buffer buf. + Lines are terminated by a line feed character, '\n'. The line + placed in the buffer includes the line feed character and is + terminated with a NULL. If the line is longer than length bytes + then only the first length-minus-1 bytes are placed in buf. + + @param filep file to read from. + @param buf buffer to read into. + @param length size of the buffer to read into. + @return pointer to the string read into the buffer buf. + + */ + tsapi char* TSfgets(TSFile filep, char* buf, size_t length); + + /* -------------------------------------------------------------------------- + Error logging */ + /** + Writes printf-style error messages to the Traffic Server error + log. One advantage of TSError over printf is that each call is + atomically placed into the error log and is not garbled with other + error entries. This is not an issue in single-threaded programs + but is a definite nuisance in multi-threaded programs. + + @param fmt printf format description. + @param ... argument for the printf format description. + + */ + tsapi void TSError(const char* fmt, ...); + + /* -------------------------------------------------------------------------- + Assertions */ + tsapi int _TSReleaseAssert(const char* txt, const char* f, int l); + tsapi int _TSAssert(const char* txt, const char* f, int l); + +#define TSReleaseAssert(EX) \ + (void)((EX) || (_TSReleaseAssert(#EX, __FILE__, __LINE__))) + +#define TSAssert(EX) \ + (void)((EX) || (_TSAssert(#EX, __FILE__, __LINE__))) + + /* -------------------------------------------------------------------------- + Marshal buffers */ + /** + Creates a new marshal buffer and initializes the reference count + to 1. + + */ + tsapi TSMBuffer TSMBufferCreate(void); + + /** + Ignores the reference count and destroys the marshal buffer bufp. + The internal data buffer associated with the marshal buffer is + also destroyed if the marshal buffer allocated it. + + @param bufp marshal buffer to be destroyed. + + */ + tsapi TSReturnCode TSMBufferDestroy(TSMBuffer bufp); + + /* -------------------------------------------------------------------------- + URLs */ + /** + Creates a new URL within the marshal buffer bufp. Returns a + location for the URL within the marshal buffer. + + @param bufp marshal buffer containing the new URL. + @param locp pointer to a TSMLoc to store the MLoc into. + + */ + tsapi TSReturnCode TSUrlCreate(TSMBuffer bufp, TSMLoc* locp); + + /** + Destroys the URL located at url_loc within the marshal buffer + bufp. Do not forget to release the TSMLoc url_loc with a call + to TSHandleMLocRelease(). + + @param bufp marshal buffer containing the URL to be destroyed. + @param offset location of the URL to be destroyed. + + */ + tsapi TSReturnCode TSUrlDestroy(TSMBuffer bufp, TSMLoc offset); + + /** + Copies the URL located at src_url within src_bufp to a URL + location within the marshal buffer dest_bufp, and returns the + TSMLoc location of the copied URL. Unlike TSUrlCopy(), you do + not have to create the destination URL before cloning. Release + the returned TSMLoc handle with a call to TSHandleMLocRelease(). + + @param dest_bufp marshal buffer containing the cloned URL. + @param src_bufp marshal buffer containing the URL to be cloned. + @param src_url location of the URL to be cloned, within the marshal + buffer src_bufp. + @param locp pointer to a TSMLoc to store the MLoc into. + + */ + tsapi TSReturnCode TSUrlClone(TSMBuffer dest_bufp, TSMBuffer src_bufp, TSMLoc src_url, TSMLoc* locp); + + /** + Copies the contents of the URL at lcoation src_loc within the + marshal buffer src_bufp to the location dest_loc within the marshal + buffer dest_bufp. TSUrlCopy() works correctly even if src_bufp + and dest_bufp point to different marshal buffers. Important: create + the destination URL before copying into it. Use TSUrlCreate(). + + @param dest_bufp marshal buffer to contain the copied URL. + @param dest_offset location of the URL to be copied. + @param src_bufp marshal buffer containing the source URL. + @param src_offset location of the source URL within src_bufp. + + */ + tsapi TSReturnCode TSUrlCopy(TSMBuffer dest_bufp, TSMLoc dest_offset, TSMBuffer src_bufp, TSMLoc src_offset); + + /** + Formats a URL stored in an TSMBuffer into an TSIOBuffer. + + @param bufp marshal buffer contain the URL to be printed. + @param offset location of the URL within bufp. + @param iobufp destination TSIOBuffer for the URL. + + */ + tsapi void TSUrlPrint(TSMBuffer bufp, TSMLoc offset, TSIOBuffer iobufp); + + /** + Parses a URL. The start pointer is both an input and an output + parameter and marks the start of the URL to be parsed. After + a successful parse, the start pointer equals the end pointer. + The end pointer must be one byte after the last character you + want to parse. The URL parsing routine assumes that everything + between start and end is part of the URL. It is up to higher level + parsing routines, such as TSHttpHdrParseReq(), to determine the + actual end of the URL. Returns TS_PARSE_ERROR if an error occurs, + otherwise TS_PARSE_DONE is returned to indicate success. + + @param bufp marshal buffer containing the URL to be parsed. + @param offset location of the URL to be parsed. + @param start points to the start of the URL to be parsed AND at + the end of a successful parse it will equal the end pointer. + @param end must be one byte after the last character. + @return TS_PARSE_ERROR or TS_PARSE_DONE. + + */ + tsapi TSParseResult TSUrlParse(TSMBuffer bufp, TSMLoc offset, const char** start, const char* end); + + /** + Calculates the length of the URL located at url_loc within the + marshal buffer bufp if it were returned as a string. This length + is the same as the length returned by TSUrlStringGet(). + + @param bufp marshal buffer containing the URL whose length you want. + @param offset location of the URL within the marshal buffer bufp. + @return string length of the URL. + + */ + tsapi int TSUrlLengthGet(TSMBuffer bufp, TSMLoc offset); + + /** + Constructs a string representation of the URL located at url_loc + within bufp. TSUrlStringGet() stores the length of the allocated + string in the parameter length. This is the same length that + TSUrlLengthGet() returns. The returned string is allocated by a + call to TSmalloc(). It should be freed by a call to TSfree(). + The length parameter must present, providing storage for the URL + string length value. + + @param bufp marshal buffer containing the URL you want to get. + @param offset location of the URL within bufp. + @param length string length of the URL. + @return The URL as a string. + + */ + tsapi char* TSUrlStringGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Retrieves the scheme portion of the URL located at url_loc within + the marshal buffer bufp. TSUrlSchemeGet() places the length of + the string in the length argument. If the length is NULL then no + attempt is made to dereference it. + + @param bufp marshal buffer storing the URL. + @param offset location of the URL within bufp. + @param length length of the returned string. + @return The scheme portion of the URL, as a string. + + */ + tsapi const char* TSUrlSchemeGet(TSMBuffer bufp, TSMLoc offset, int *length); + + /** + Sets the scheme portion of the URL located at url_loc within + the marshal buffer bufp to the string value. If length is -1 + then TSUrlSchemeSet() assumes that value is null-terminated. + Otherwise, the length of the string value is taken to be length. + TSUrlSchemeSet() copies the string to within bufp, so it is OK + to modify or delete value after calling TSUrlSchemeSet(). + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param value value to set the URL's scheme to. + @param length string stored in value. + + */ + tsapi TSReturnCode TSUrlSchemeSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /* -------------------------------------------------------------------------- + Internet specific URLs */ + /** + Retrieves the user portion of the URL located at url_loc + within bufp. Note: the returned string is not guaranteed to + be null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param length length of the returned string. + @return user portion of the URL. + + */ + tsapi const char* TSUrlUserGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the user portion of the URL located at url_loc within bufp + to the string value. If length is -1 then TSUrlUserSet() assumes + that value is null-terminated. Otherwise, the length of the string + value is taken to be length. TSUrlUserSet() copies the string to + within bufp, so it is OK to modify or delete value after calling + TSUrlUserSet(). + + @param bufp marshal buffer containing the URL. + @param offset location of the URL whose user is to be set. + @param value holds the new user name. + @param length string length of value. + + */ + tsapi TSReturnCode TSUrlUserSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /** + Retrieves the password portion of the URL located at url_loc + within bufp. TSUrlPasswordGet() places the length of the returned + string in the length argument. Note: the returned string is + not guaranteed to be null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset + @param length of the returned password string. + @return password portion of the URL. + + */ + tsapi const char* TSUrlPasswordGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the password portion of the URL located at url_loc within + bufp to the string value. If length is -1 then TSUrlPasswordSet() + assumes that value is null-terminated. Otherwise, the length + of value is taken to be length. TSUrlPasswordSet() copies the + string to within bufp, so it is okay to modify or delete value + after calling TSUrlPasswordSet(). + + @param bufp marshal buffer containing the URL. + @param offset + @param value new password. + @param length of the new password. + + */ + tsapi TSReturnCode TSUrlPasswordSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /** + Retrieves the host portion of the URL located at url_loc + within bufp. Note: the returned string is not guaranteed to be + null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param length of the returned string. + @return Host portion of the URL. + + */ + tsapi const char* TSUrlHostGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the host portion of the URL at url_loc to the string value. + If length is -1 then TSUrlHostSet() assumes that value is + null-terminated. Otherwise, the length of the string value is + taken to be length. The string is copied to within bufp, so you + can modify or delete value after calling TSUrlHostSet(). + + @param bufp marshal buffer containing the URL to modify. + @param offset location of the URL. + @param value new host name for the URL. + @param length string length of the new host name of the URL. + + */ + tsapi TSReturnCode TSUrlHostSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /** + Retrieves the port portion of the URL located at url_loc. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @return port portion of the URL. + + */ + tsapi int TSUrlPortGet(TSMBuffer bufp, TSMLoc offset); + + /** + Sets the port portion of the URL located at url_loc. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param port new port setting for the URL. + + */ + tsapi TSReturnCode TSUrlPortSet(TSMBuffer bufp, TSMLoc offset, int port); + + /* -------------------------------------------------------------------------- + HTTP specific URLs */ + /** + Retrieves the path portion of the URL located at url_loc within + bufp. TSUrlPathGet() places the length of the returned string in + the length argument. Note: the returned string is not guaranteed to + be null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param length of the returned string. + @return path portion of the URL. + + */ + tsapi const char* TSUrlPathGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the path portion of the URL located at url_loc within bufp + to the string value. If length is -1 then TSUrlPathSet() assumes + that value is null-terminated. Otherwise, the length of the value + is taken to be length. TSUrlPathSet() copies the string into bufp, + so you can modify or delete value after calling TSUrlPathSet(). + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param value new path string for the URL. + @param length of the new path string. + + */ + tsapi TSReturnCode TSUrlPathSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /* -------------------------------------------------------------------------- + FTP specific URLs */ + /** + Retrieves the FTP type of the URL located at url_loc within bufp. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @return FTP type of the URL. + + */ + tsapi int TSUrlFtpTypeGet(TSMBuffer bufp, TSMLoc offset); + + /** + Sets the FTP type portion of the URL located at url_loc within + bufp to the value type. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL to modify. + @param type new FTP type for the URL. + + */ + tsapi TSReturnCode TSUrlFtpTypeSet(TSMBuffer bufp, TSMLoc offset, int type); + + /* -------------------------------------------------------------------------- + HTTP specific URLs */ + /** + Retrieves the HTTP params portion of the URL located at url_loc + within bufp. The length of the returned string is in the length + argument. Note: the returned string is not guaranteed to be + null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param length of the returned string. + @return HTTP params portion of the URL. + + */ + tsapi const char* TSUrlHttpParamsGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the HTTP params portion of the URL located at url_loc within + bufp to the string value. If length is -1 that TSUrlHttpParamsSet() + assumes that value is null-terminated. Otherwise, the length of + the string value is taken to be length. TSUrlHttpParamsSet() + copies the string to within bufp, so you can modify or delete + value after calling TSUrlHttpParamsSet(). + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param value HTTP params string to set in the URL. + @param length string length of the new HTTP params value. + + */ + tsapi TSReturnCode TSUrlHttpParamsSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /** + Retrieves the HTTP query portion of the URL located at url_loc + within bufp. The length of the returned string is in the length + argument. Note: the returned string is not guaranteed to be + null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param length of the returned string. + @return HTTP query portion of the URL. + + */ + tsapi const char* TSUrlHttpQueryGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the HTTP query portion of the URL located at url_loc within + bufp to value. If length is -1, the string value is assumed to + be null-terminated; otherwise, the length of value is taken to be + length. TSUrlHttpQuerySet() copies the string to within bufp, so + you can modify or delete value after calling TSUrlHttpQuerySet(). + + @param bufp marshal buffer containing the URL. + @param offset location of the URL within bufp. + @param value new HTTP query string for the URL. + @param length of the new HTTP query string. + + */ + tsapi TSReturnCode TSUrlHttpQuerySet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /** + Retrieves the HTTP fragment portion of the URL located at url_loc + within bufp. The length of the returned string is in the length + argument. Note: the returned string is not guaranteed to be + null-terminated. + + @param bufp marshal buffer containing the URL. + @param offset location of the URL. + @param length of the returned string. + @return HTTP fragment portion of the URL. + + */ + tsapi const char* TSUrlHttpFragmentGet(TSMBuffer bufp, TSMLoc offset, int* length); + + /** + Sets the HTTP fragment portion of the URL located at url_loc + within bufp to value. If length is -1, the string value is + assumed to be null-terminated; otherwise, the length of value + is taken to be length. TSUrlHttpFragmentSet() copies the string + to within bufp, so you can modify or delete value after calling + TSUrlHttpFragmentSet(). + + @param bufp marshal buffer containing the URL. + @param offset location of the URL within bufp. + @param value new HTTP fragment string for the URL. + @param length of the new HTTP query string. + + */ + tsapi TSReturnCode TSUrlHttpFragmentSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + + /* -------------------------------------------------------------------------- + MIME headers */ + + /** + Creates a MIME parser. The parser's data structure contains + information about the header being parsed. A single MIME + parser can be used multiple times, though not simultaneously. + Before being used again, the parser must be cleared by calling + TSMimeParserClear(). + + */ + tsapi TSMimeParser TSMimeParserCreate(void); + + /** + Clears the specified MIME parser so that it can be used again. + + @param parser to be cleared. + + */ + tsapi void TSMimeParserClear(TSMimeParser parser); + + /** + Destroys the specified MIME parser and frees the associated memory. + + @param parser to destroy. + */ + tsapi void TSMimeParserDestroy(TSMimeParser parser); + + /** + Creates a new MIME header within bufp. Release with a call to + TSHandleMLocRelease(). + + @param bufp marshal buffer to contain the new MIME header. + @param locp buffer pointer to contain the MLoc + + */ + tsapi TSReturnCode TSMimeHdrCreate(TSMBuffer bufp, TSMLoc* locp); + + /** + Destroys the MIME header located at hdr_loc within bufp. + + @param bufp marshal buffer containing the MIME header to destroy. + @param offset location of the MIME header. + + */ + tsapi TSReturnCode TSMimeHdrDestroy(TSMBuffer bufp, TSMLoc offset); + + /** + Copies a specified MIME header to a specified marshal buffer, + and returns the location of the copied MIME header within the + destination marshal buffer. Unlike TSMimeHdrCopy(), you do not + have to create the destination MIME header before cloning. Release + the returned TSMLoc handle with a call to TSHandleMLocRelease(). + + @param dest_bufp destination marshal buffer. + @param src_bufp source marshal buffer. + @param src_hdr location of the source MIME header. + @param locp where to store the location of the copied MIME header. + + */ + tsapi TSReturnCode TSMimeHdrClone(TSMBuffer dest_bufp, TSMBuffer src_bufp, TSMLoc src_hdr, TSMLoc* locp); + + /** + Copies the contents of the MIME header located at src_loc + within src_bufp to the MIME header located at dest_loc within + dest_bufp. TSMimeHdrCopy() works correctly even if src_bufp and + dest_bufp point to different marshal buffers. Important: you must + create the destination MIME header before copying into it--use + TSMimeHdrCreate(). + + @param dest_bufp is the destination marshal buffer. + @param dest_offset + @param src_bufp is the source marshal buffer. + @param src_offset + + */ + tsapi TSReturnCode TSMimeHdrCopy(TSMBuffer dest_bufp, TSMLoc dest_offset, TSMBuffer src_bufp, + TSMLoc src_offset); + + /** + Formats the MIME header located at hdr_loc within bufp into the + TSIOBuffer iobufp. + + @param bufp marshal buffer containing the header to be copied to + an TSIOBuffer. + @param offset + @param iobufp target TSIOBuffer. + + */ + tsapi void TSMimeHdrPrint(TSMBuffer bufp, TSMLoc offset, TSIOBuffer iobufp); + + /** + Parses a MIME header. The MIME header must have already been + allocated and both bufp and hdr_loc must point within that header. + It is possible to parse a MIME header a single byte at a time + using repeated calls to TSMimeHdrParse(). As long as an error + does not occur, TSMimeHdrParse() consumes each single byte and + asks for more. + + @param parser parses the specified MIME header. + @param bufp marshal buffer containing the MIME header to be parsed. + @param offset + @param start both an input and output. On input, the start + argument points to the current position of the buffer being + parsed. On return, start is modified to point past the last + character parsed. + @param end points to one byte after the end of the buffer. + @return One of 3 possible int values: + - TS_PARSE_ERROR if there is a parsing error. + - TS_PARSE_DONE is returned when a "\r\n\r\n" pattern is + encountered, indicating the end of the header. + - TS_PARSE_CONT is returned if parsing of the header stopped + because the end of the buffer was reached. + + */ + tsapi TSParseResult TSMimeHdrParse(TSMimeParser parser, TSMBuffer bufp, TSMLoc offset, const char** start, + const char* end); + + /** + Calculates the length of the MIME header located at hdr_loc if it + were returned as a string. This the length of the MIME header in + its unparsed form. + + @param bufp marshal buffer containing the MIME header. + @param offset location of the MIME header. + @return string length of the MIME header located at hdr_loc. + + */ + tsapi int TSMimeHdrLengthGet(TSMBuffer bufp, TSMLoc offset); + + /** + Removes and destroys all the MIME fields within the MIME header + located at hdr_loc within the marshal buffer bufp. + + @param bufp marshal buffer containing the MIME header. + @param offset location of the MIME header. + + */ + tsapi TSReturnCode TSMimeHdrFieldsClear(TSMBuffer bufp, TSMLoc offset); + + /** + Returns a count of the number of MIME fields within the MIME header + located at hdr_loc within the marshal buffer bufp. + + @param bufp marshal buffer containing the MIME header. + @param offset location of the MIME header within bufp. + @return number of MIME fields within the MIME header located + at hdr_loc. + + */ + tsapi int TSMimeHdrFieldsCount(TSMBuffer bufp, TSMLoc offset); + + /** + Retrieves the location of a specified MIME field within the + MIME header located at hdr_loc within bufp. The idx parameter + specifies which field to retrieve. The fields are numbered from 0 + to TSMimeHdrFieldsCount(bufp, hdr_loc) - 1. If idx does not lie + within that range then TSMimeHdrFieldGet returns 0. Release the + returned handle with a call to TSHandleMLocRelease. + + @param bufp marshal buffer containing the MIME header. + @param hdr location of the MIME header. + @param idx index of the field to get with base at 0. + @return location of the specified MIME field. + + */ + tsapi TSMLoc TSMimeHdrFieldGet(TSMBuffer bufp, TSMLoc hdr, int idx); + + /** + Retrieves the TSMLoc location of a specfied MIME field from within + the MIME header located at hdr. The name and length parameters + specify which field to retrieve. For each MIME field in the MIME + header, a case insensitive string comparison is done between + the field name and name. If TSMimeHdrFieldFind() cannot find the + requested field, it returns TS_NULL_MLOC. Release the returned + TSMLoc handle with a call to TSHandleMLocRelease(). + + @param bufp marshal buffer containing the MIME header field to find. + @param hdr location of the MIME header containing the field. + @param name of the field to retrieve. + @param length string length of the string name. If length is -1, + then name is assumed to be null-terminated. + @return location of the requested MIME field. If the field could + not be found, returns TS_NULL_MLOC. + + */ + tsapi TSMLoc TSMimeHdrFieldFind(TSMBuffer bufp, TSMLoc hdr, const char* name, int length); + + /** + Returns the TSMLoc location of a specified MIME field from within + the MIME header located at hdr. The retrieved_str parameter + specifies which field to retrieve. For each MIME field in the + MIME header, a pointer comparison is done between the field name + and retrieved_str. This is a much quicker retrieval function + than TSMimeHdrFieldFind() since it obviates the need for a + string comparison. However, retrieved_str must be one of the + predefined field names of the form TS_MIME_FIELD_XXX for the + call to succeed. Release the returned TSMLoc handle with a call + to TSHandleMLocRelease(). + + @param bufp marshal buffer containing the MIME field. + @param hdr location of the MIME header containing the field. + @param retrieved_str specifies the field to retrieve. Must be + one of the predefined field names of the form TS_MIME_FIELD_XXX. + @return location of the requested MIME field. If the requested + field cannot be found, returns 0. + + */ + tsapi TSReturnCode TSMimeHdrFieldAppend(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + + /** + Removes the MIME field located at field within bufp from the + header located at hdr within bufp. If the specified field cannot + be found in the list of fields associated with the header then + nothing is done. + + Note: removing the field does not destroy the field, it only + detaches the field, hiding it from the printed output. The field + can be reattached with a call to TSMimeHdrFieldAppend(). If you + do not use the detached field you should destroy it with a call to + TSMimeHdrFieldDestroy() and release the handle field with a call + to TSHandleMLocRelease(). + + @param bufp contains the MIME field to remove. + @param hdr location of the header containing the MIME field to + be removed. This header could be an HTTP header or MIME header. + @param field is the location of the field to remove. + + */ + tsapi TSReturnCode TSMimeHdrFieldRemove(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + + tsapi TSReturnCode TSMimeHdrFieldCreate(TSMBuffer bufp, TSMLoc hdr, TSMLoc* locp); + + /**************************************************************************** + * Create a new field and assign it a name all in one call + ****************************************************************************/ + tsapi TSReturnCode TSMimeHdrFieldCreateNamed(TSMBuffer bufp, TSMLoc mh_mloc, const char* name, int name_len, TSMLoc* locp); + + /** + Destroys the MIME field located at field within bufp. You must + release the TSMLoc field with a call to TSHandleMLocRelease(). + + @param bufp contains the MIME field to be destroyed. + @param hdr location of the parent header containing the field + to be destroyed. This could be the location of a MIME header or + HTTP header. + @param field location of the field to be destroyed. + + */ + tsapi TSReturnCode TSMimeHdrFieldDestroy(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + + tsapi TSReturnCode TSMimeHdrFieldClone(TSMBuffer dest_bufp, TSMLoc dest_hdr, TSMBuffer src_bufp, TSMLoc src_hdr, + TSMLoc src_field, TSMLoc* locp); + tsapi TSReturnCode TSMimeHdrFieldCopy(TSMBuffer dest_bufp, TSMLoc dest_hdr, TSMLoc dest_field, + TSMBuffer src_bufp, TSMLoc src_hdr, TSMLoc src_field); + tsapi TSReturnCode TSMimeHdrFieldCopyValues(TSMBuffer dest_bufp, TSMLoc dest_hdr, TSMLoc dest_field, + TSMBuffer src_bufp, TSMLoc src_hdr, TSMLoc src_field); + tsapi TSMLoc TSMimeHdrFieldNext(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + tsapi TSMLoc TSMimeHdrFieldNextDup(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + tsapi int TSMimeHdrFieldLengthGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + tsapi const char* TSMimeHdrFieldNameGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int* length); + tsapi TSReturnCode TSMimeHdrFieldNameSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, const char* name, int length); + + tsapi TSReturnCode TSMimeHdrFieldValuesClear(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + tsapi int TSMimeHdrFieldValuesCount(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + + tsapi const char* TSMimeHdrFieldValueStringGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, int* value_len_ptr); + tsapi int TSMimeHdrFieldValueIntGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx); + tsapi unsigned int TSMimeHdrFieldValueUintGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx); + tsapi time_t TSMimeHdrFieldValueDateGet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field); + tsapi TSReturnCode TSMimeHdrFieldValueStringSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, + const char* value, int length); + tsapi TSReturnCode TSMimeHdrFieldValueIntSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, int value); + tsapi TSReturnCode TSMimeHdrFieldValueUintSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, + unsigned int value); + tsapi TSReturnCode TSMimeHdrFieldValueDateSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, time_t value); + + tsapi TSReturnCode TSMimeHdrFieldValueAppend(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, + const char* value, int length); + tsapi TSReturnCode TSMimeHdrFieldValueStringInsert(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, + const char* value, int length); + tsapi TSReturnCode TSMimeHdrFieldValueIntInsert(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, int value); + tsapi TSReturnCode TSMimeHdrFieldValueUintInsert(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, + unsigned int value); + tsapi TSReturnCode TSMimeHdrFieldValueDateInsert(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, time_t value); + + tsapi TSReturnCode TSMimeHdrFieldValueDelete(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx); + + /* -------------------------------------------------------------------------- + HTTP headers */ + tsapi TSHttpParser TSHttpParserCreate(void); + tsapi void TSHttpParserClear(TSHttpParser parser); + tsapi void TSHttpParserDestroy(TSHttpParser parser); + + tsapi TSMLoc TSHttpHdrCreate(TSMBuffer bufp); + + /** + Destroys the HTTP header located at hdr_loc within the marshal + buffer bufp. Do not forget to release the handle hdr_loc with a + call to TSHandleMLocRelease(). + + */ + tsapi void TSHttpHdrDestroy(TSMBuffer bufp, TSMLoc offset); + + tsapi TSReturnCode TSHttpHdrClone(TSMBuffer dest_bufp, TSMBuffer src_bufp, TSMLoc src_hdr, TSMLoc* locp); + + /** + Copies the contents of the HTTP header located at src_loc within + src_bufp to the HTTP header located at dest_loc within dest_bufp. + TSHttpHdrCopy() works correctly even if src_bufp and dest_bufp + point to different marshal buffers. Make sure that you create the + destination HTTP header before copying into it. + + Note: TSHttpHdrCopy() appends the port number to the domain + of the URL portion of the header. For example, a copy of + http://www.example.com appears as http://www.example.com:80 in + the destination buffer. + + @param dest_bufp marshal buffer to contain the copied header. + @param dest_offset location of the copied header. + @param src_bufp marshal buffer containing the source header. + @param src_offset location of the source header. + + */ + tsapi TSReturnCode TSHttpHdrCopy(TSMBuffer dest_bufp, TSMLoc dest_offset, TSMBuffer src_bufp, + TSMLoc src_offset); + + tsapi void TSHttpHdrPrint(TSMBuffer bufp, TSMLoc offset, TSIOBuffer iobufp); + + /** + Parses an HTTP request header. The HTTP header must have already + been created, and must reside inside the marshal buffer bufp. + The start argument points to the current position of the string + buffer being parsed. The end argument points to one byte after the + end of the buffer to be parsed. On return, TSHttpHdrParseReq() + modifies start to point past the last character parsed. + + It is possible to parse an HTTP request header a single byte at + a time using repeated calls to TSHttpHdrParseReq(). As long as + an error does not occur, the TSHttpHdrParseReq() function will + consume that single byte and ask for more. + + @param parser parses the HTTP header. + @param bufp marshal buffer containing the HTTP header to be parsed. + @param offset location of the HTTP header within bufp. + @param start both an input and output. On input, it points to the + current position of the string buffer being parsed. On return, + start is modified to point past the last character parsed. + @param end points to one byte after the end of the buffer to be parsed. + @return status of the parse: + - TS_PARSE_ERROR means there was a parsing error. + - TS_PARSE_DONE means that the end of the header was reached + (the parser encountered a "\r\n\r\n" pattern). + - TS_PARSE_CONT means that parsing of the header stopped because + the parser reached the end of the buffer (large headers can + span multiple buffers). + + */ + tsapi TSParseResult TSHttpHdrParseReq(TSHttpParser parser, TSMBuffer bufp, TSMLoc offset, const char** start, + const char* end); + + tsapi TSParseResult TSHttpHdrParseResp(TSHttpParser parser, TSMBuffer bufp, TSMLoc offset, const char** start, + const char* end); + + tsapi int TSHttpHdrLengthGet(TSMBuffer bufp, TSMLoc offset); + + tsapi TSHttpType TSHttpHdrTypeGet(TSMBuffer bufp, TSMLoc offset); + tsapi TSReturnCode TSHttpHdrTypeSet(TSMBuffer bufp, TSMLoc offset, TSHttpType type); + + tsapi int TSHttpHdrVersionGet(TSMBuffer bufp, TSMLoc offset); + tsapi TSReturnCode TSHttpHdrVersionSet(TSMBuffer bufp, TSMLoc offset, int ver); + + tsapi const char* TSHttpHdrMethodGet(TSMBuffer bufp, TSMLoc offset, int* length); + tsapi TSReturnCode TSHttpHdrMethodSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + tsapi TSReturnCode TSHttpHdrUrlGet(TSMBuffer bufp, TSMLoc offset, TSMLoc* locp); + tsapi TSReturnCode TSHttpHdrUrlSet(TSMBuffer bufp, TSMLoc offset, TSMLoc url); + + tsapi TSHttpStatus TSHttpHdrStatusGet(TSMBuffer bufp, TSMLoc offset); + tsapi TSReturnCode TSHttpHdrStatusSet(TSMBuffer bufp, TSMLoc offset, TSHttpStatus status); + tsapi const char* TSHttpHdrReasonGet(TSMBuffer bufp, TSMLoc offset, int* length); + tsapi TSReturnCode TSHttpHdrReasonSet(TSMBuffer bufp, TSMLoc offset, const char* value, int length); + tsapi const char* TSHttpHdrReasonLookup(TSHttpStatus status); + + /* -------------------------------------------------------------------------- + Threads */ + tsapi TSThread TSThreadCreate(TSThreadFunc func, void* data); + tsapi TSThread TSThreadInit(void); + tsapi void TSThreadDestroy(TSThread thread); + tsapi TSThread TSThreadSelf(void); + + /* -------------------------------------------------------------------------- + Mutexes */ + tsapi TSMutex TSMutexCreate(void); + tsapi void TSMutexLock(TSMutex mutexp); + tsapi TSReturnCode TSMutexLockTry(TSMutex mutexp); + + tsapi void TSMutexUnlock(TSMutex mutexp); + + /* -------------------------------------------------------------------------- + cachekey */ + /** + Creates (allocates memory for) a new cache key. + */ + tsapi TSCacheKey TSCacheKeyCreate(void); + + /** + Generates a key for an object to be cached (written to the cache). + + @param key to be associated with the cached object. Before + calling TSCacheKeySetDigest() you must create the key with + TSCacheKeyCreate(). + @param input string that uniquely identifies the object. In most + cases, it is the URL of the object. + @param length of the string input. + + */ + tsapi TSReturnCode TSCacheKeyDigestSet(TSCacheKey key, const char* input, int length); + + tsapi TSReturnCode TSCacheKeyDigestFromUrlSet(TSCacheKey key, TSMLoc url); + + /** + Associates a host name to the cache key. Use this function if the + cache has been partitioned by hostname. The hostname tells the + cache which volume to use for the object. + + @param key of the cached object. + @param hostname to associate with the cache key. + @param host_len length of the string hostname. + + */ + tsapi TSReturnCode TSCacheKeyHostNameSet(TSCacheKey key, const char* hostname, int host_len); + + tsapi TSReturnCode TSCacheKeyPinnedSet(TSCacheKey key, time_t pin_in_cache); + + /** + Destroys a cache key. You must destroy cache keys when you are + finished with them, i.e. after all reads and writes are completed. + + @param key to be destroyed. + + */ + tsapi TSReturnCode TSCacheKeyDestroy(TSCacheKey key); + + /* -------------------------------------------------------------------------- + cache url */ + tsapi TSReturnCode TSCacheUrlSet(TSHttpTxn txnp, const char* url, int length); + + /* -------------------------------------------------------------------------- + Configuration */ + tsapi unsigned int TSConfigSet(unsigned int id, void* data, TSConfigDestroyFunc funcp); + tsapi TSConfig TSConfigGet(unsigned int id); + tsapi void TSConfigRelease(unsigned int id, TSConfig configp); + tsapi void* TSConfigDataGet(TSConfig configp); + + /* -------------------------------------------------------------------------- + Management */ + tsapi void TSMgmtUpdateRegister(TSCont contp, const char *plugin_name); + tsapi TSReturnCode TSMgmtIntGet(const char* var_name, TSMgmtInt* result); + tsapi TSReturnCode TSMgmtCounterGet(const char* var_name, TSMgmtCounter* result); + tsapi TSReturnCode TSMgmtFloatGet(const char* var_name, TSMgmtFloat* result); + tsapi TSReturnCode TSMgmtStringGet(const char* var_name, TSMgmtString* result); + + /* -------------------------------------------------------------------------- + Continuations */ + tsapi TSCont TSContCreate(TSEventFunc funcp, TSMutex mutexp); + tsapi void TSContDestroy(TSCont contp); + tsapi void TSContDataSet(TSCont contp, void* data); + tsapi void* TSContDataGet(TSCont contp); + tsapi TSAction TSContSchedule(TSCont contp, TSHRTime timeout, TSThreadPool tp); + tsapi TSAction TSContScheduleEvery(TSCont contp, TSHRTime every, TSThreadPool tp); + tsapi TSAction TSHttpSchedule(TSCont contp, TSHttpTxn txnp, TSHRTime timeout); + tsapi int TSContCall(TSCont contp, TSEvent event, void* edata); + tsapi TSMutex TSContMutexGet(TSCont contp); + + /* -------------------------------------------------------------------------- + HTTP hooks */ + tsapi void TSHttpHookAdd(TSHttpHookID id, TSCont contp); + + /* -------------------------------------------------------------------------- + Cache hook */ + tsapi TSReturnCode TSCacheHookAdd(TSCacheHookID id, TSCont contp); + + /* -------------------------------------------------------------------------- + HTTP sessions */ + tsapi void TSHttpSsnHookAdd(TSHttpSsn ssnp, TSHttpHookID id, TSCont contp); + tsapi void TSHttpSsnReenable(TSHttpSsn ssnp, TSEvent event); + tsapi int TSHttpSsnTransactionCount(TSHttpSsn ssnp); + + /* -------------------------------------------------------------------------- + HTTP transactions */ + tsapi void TSHttpTxnHookAdd(TSHttpTxn txnp, TSHttpHookID id, TSCont contp); + tsapi TSHttpSsn TSHttpTxnSsnGet(TSHttpTxn txnp); + tsapi TSReturnCode TSHttpTxnClientReqGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpTxnPristineUrlGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* url_loc); + /** Get the effective URL for the transaction. + The effective URL is the URL taking in to account both the explicit + URL in the request and the HOST field. + + A possibly non-null terminated string is returned. + + @note The returned string is allocated and must be freed by the caller + after use with @c TSfree. + */ + tsapi char* TSHttpTxnEffectiveUrlStringGet( + TSHttpTxn txnp, ///< Transaction. + int* length ///< String length return, may be @c NULL. + ); + tsapi TSReturnCode TSHttpTxnClientRespGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpTxnServerReqGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpTxnServerRespGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpTxnCachedReqGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpTxnCachedRespGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi void TSHttpTxnRespCacheableSet(TSHttpTxn txnp, int flag); + tsapi void TSHttpTxnReqCacheableSet(TSHttpTxn txnp, int flag); + tsapi TSReturnCode TSFetchPageRespGet (TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + tsapi char* TSFetchRespGet(TSHttpTxn txnp, int* length); + tsapi TSReturnCode TSHttpTxnCacheLookupStatusGet(TSHttpTxn txnp, int* lookup_status); + + tsapi TSReturnCode TSHttpTxnTransformRespGet(TSHttpTxn txnp, TSMBuffer* bufp, TSMLoc* offset); + + /** Get client address for transaction @a txnp. + Retrieves the socket address of the remote client that has + connected to Traffic Server for transaction @a txnp. The + return structure is the generic socket address storage in + order to be address-family agnostic. The user of this function + can then go on to do the approriate thing with the type + specified in the ss_family field of the structure whether + that be for IPv4, IPv6, or any other address family. + + @return Client address for connection to client in transaction @a txnp. + + */ + tsapi struct sockaddr const* TSHttpTxnClientAddrGet( + TSHttpTxn txnp ///< Transaction. + ); + /** Get the incoming address. + + @note The pointer is valid only for the current callback. Clients + that need to keep the value across callbacks must maintain their + own storage. + + @return Local address of the client connection for transaction @a txnp. + */ + tsapi struct sockaddr const* TSHttpTxnIncomingAddrGet( + TSHttpTxn txnp ///< Transaction. + ); + /** Get the origin server address. + * + @note The pointer is valid only for the current callback. Clients + that need to keep the value across callbacks must maintain their + own storage. + + @return The address of the origin server for transaction @a txnp. + */ + tsapi struct sockaddr const* TSHttpTxnServerAddrGet( + TSHttpTxn txnp ///< Transaction. + ); + /** Set the origin server address. + + This must be invoked before the origin server address is looked up. + If called no lookup is done, the address @a addr is used instead. + + @return @c TS_SUCCESS if the origin server address is set, @c TS_ERROR otherwise. + */ + tsapi TSReturnCode TSHttpTxnServerAddrSet( + TSHttpTxn txnp, ///< Transaction + struct sockaddr const* addr ///< Address for origin server. + ); + + /** Get the next hop address. + * + @note The pointer is valid only for the current callback. Clients + that need to keep the value across callbacks must maintain their + own storage. + + @return The address of the next hop for transaction @a txnp. + */ + tsapi struct sockaddr const* TSHttpTxnNextHopAddrGet( + TSHttpTxn txnp ///< Transaction. + ); + + tsapi TSReturnCode TSHttpTxnClientFdGet(TSHttpTxn txnp, int* fdp); + tsapi TSReturnCode TSHttpTxnOutgoingAddrSet(TSHttpTxn txnp, struct sockaddr const* addr); + + /// @deprecated Use TSHttpTxnClientAddrGet + tsapi TS_DEPRECATED unsigned int TSHttpTxnClientIPGet(TSHttpTxn txnp); + /// @deprecated Use TSHttpTxnClientAddrGet + tsapi TS_DEPRECATED TSReturnCode TSHttpTxnClientRemotePortGet(TSHttpTxn txnp, int* portp); + /// @deprecated Use TSHttpTxnIncomingAddrGet + tsapi TS_DEPRECATED int TSHttpTxnClientIncomingPortGet(TSHttpTxn txnp); + /// @deprecated Use TSHttpTxnServerAddrGet + tsapi TS_DEPRECATED unsigned int TSHttpTxnServerIPGet(TSHttpTxn txnp); + /// @deprecated Use TSHttpTxnNextHopAddrGet + tsapi TS_DEPRECATED unsigned int TSHttpTxnNextHopIPGet(TSHttpTxn txnp); + /// @deprecated Use TSHttpTxnNextHopAddrGet + tsapi TS_DEPRECATED int TSHttpTxnNextHopPortGet(TSHttpTxn txnp); + + tsapi void TSHttpTxnErrorBodySet(TSHttpTxn txnp, char* buf, int buflength, char* mimetype); + + /** + Retrieves the parent proxy hostname and port, if parent + proxying is enabled. If parent proxying is not enabled, + TSHttpTxnParentProxyGet() sets hostname to NULL and port to -1. + + @param txnp HTTP transaction whose parent proxy to get. + @param hostname of the parent proxy. + @param port parent proxy's port. + + */ + tsapi TSReturnCode TSHttpTxnParentProxyGet(TSHttpTxn txnp, char** hostname, int* port); + + /** + Sets the parent proxy name and port. The string hostname is copied + into the TSHttpTxn; you can modify or delete the string after + calling TSHttpTxnParentProxySet(). + + @param txnp HTTP transaction whose parent proxy to set. + @param hostname parent proxy host name string. + @param port parent proxy port to set. + + */ + tsapi void TSHttpTxnParentProxySet(TSHttpTxn txnp, char* hostname, int port); + + tsapi void TSHttpTxnUntransformedRespCache(TSHttpTxn txnp, int on); + tsapi void TSHttpTxnTransformedRespCache(TSHttpTxn txnp, int on); + + /** + Notifies the HTTP transaction txnp that the plugin is + finished processing the current hook. The plugin tells the + transaction to either continue (TS_EVENT_HTTP_CONTINUE) or stop + (TS_EVENT_HTTP_ERROR). + + You must always reenable the HTTP transaction after the processing + of each transaction event. However, never reenable twice. + Reenabling twice is a serious error. + + @param txnp transaction to be reenabled. + @param event tells the transaction how to continue: + - TS_EVENT_HTTP_CONTINUE, which means that the transaction + should continue. + - TS_EVENT_HTTP_ERROR which terminates the transaction + and sends an error to the client if no response has already + been sent. + + */ + tsapi void TSHttpTxnReenable(TSHttpTxn txnp, TSEvent event); + tsapi TSReturnCode TSHttpCacheReenable(TSCacheTxn txnp, const TSEvent event, const void* data, const uint64_t size); + tsapi TSReturnCode TSHttpTxnFollowRedirect(TSHttpTxn txnp, int on); + + tsapi void TSHttpTxnArgSet(TSHttpTxn txnp, int arg_idx, void* arg); + tsapi void* TSHttpTxnArgGet(TSHttpTxn txnp, int arg_idx); + tsapi void TSHttpSsnArgSet(TSHttpSsn ssnp, int arg_idx, void* arg); + tsapi void* TSHttpSsnArgGet(TSHttpSsn ssnp, int arg_idx); + + /* The reserve API should only be use in TSAPI plugins, during plugin initialization! */ + /* The lookup methods can be used anytime, but are best used during initialization as well, + or at least "cache" the results for best performance. */ + tsapi TSReturnCode TSHttpArgIndexReserve(const char* name, const char* description, int* arg_idx); + tsapi TSReturnCode TSHttpArgIndexNameLookup(const char* name, int* arg_idx, const char** description); + tsapi TSReturnCode TSHttpArgIndexLookup(int arg_idx, const char** name, const char** description); + + /** @deprecated */ + tsapi TS_DEPRECATED int TSHttpTxnMaxArgCntGet(void); + + tsapi int TSHttpTxnGetMaxHttpRetBodySize(void); + tsapi void TSHttpTxnSetHttpRetBody(TSHttpTxn txnp, const char* body_msg, int plain_msg); + tsapi void TSHttpTxnSetHttpRetStatus(TSHttpTxn txnp, TSHttpStatus http_retstatus); + + tsapi void TSHttpTxnActiveTimeoutSet(TSHttpTxn txnp, int timeout); + tsapi void TSHttpTxnConnectTimeoutSet(TSHttpTxn txnp, int timeout); + tsapi void TSHttpTxnDNSTimeoutSet(TSHttpTxn txnp, int timeout); + tsapi void TSHttpTxnNoActivityTimeoutSet(TSHttpTxn txnp, int timeout); + + tsapi TSServerState TSHttpTxnServerStateGet(TSHttpTxn txnp); + + /* -------------------------------------------------------------------------- + Intercepting Http Transactions */ + + /** + Allows a plugin take over the servicing of the request as though + it was the origin server. contp will be sent TS_EVENT_NET_ACCEPT. + The edata passed with TS_NET_EVENT_ACCEPT is an TSVConn just as + it would be for a normal accept. The plugin must act as if it is + an http server and read the http request and body off the TSVConn + and send an http response header and body. + + TSHttpTxnIntercept() must be called be called from only + TS_HTTP_READ_REQUEST_HOOK. Using TSHttpTxnIntercept will + bypass the Traffic Server cache. If response sent by the plugin + should be cached, use TSHttpTxnServerIntercept() instead. + TSHttpTxnIntercept() primary use is allow plugins to serve data + about their functioning directly. + + TSHttpTxnIntercept() must only be called once per transaction. + + @param contp continuation called to handle the interception. + @param txnp transaction to be intercepted. + + */ + tsapi void TSHttpTxnIntercept(TSCont contp, TSHttpTxn txnp); + + /** + Allows a plugin take over the servicing of the request as though + it was the origin server. In the event a request needs to be + made to the server for transaction txnp, contp will be sent + TS_EVENT_NET_ACCEPT. The edata passed with TS_NET_EVENT_ACCEPT + is an TSVConn just as it would be for a normal accept. The plugin + must act as if it is an http server and read the http request and + body off the TSVConn and send an http response header and body. + + TSHttpTxnInterceptServer() must be not be called after + the connection to the server has taken place. The last hook + last hook in that TSHttpTxnIntercept() can be called from is + TS_HTTP_READ_CACHE_HDR_HOOK. If a connection to the server is + not necessary, contp is not called. + + The reponse from the plugin is cached subject to standard + and configured http caching rules. Should the plugin wish the + response not be cached, the plugin must use appropriate http + response headers to prevent caching. The primary purpose of + TSHttpTxnInterceptServer() is allow plugins to provide gateways + to other protocols or to allow to plugin to it's own transport for + the next hop to the server. TSHttpTxnInterceptServer() overrides + parent cache configuration. + + TSHttpTxnInterceptServer() must only be called once per + transaction. + + @param contp continuation called to handle the interception + @param txnp transaction to be intercepted. + + */ + tsapi void TSHttpTxnServerIntercept(TSCont contp, TSHttpTxn txnp); + + /* -------------------------------------------------------------------------- + Initiate Http Connection */ + /** + Allows the plugin to initiate an http connection. The TSVConn the + plugin receives as the result of successful operates identically to + one created through TSNetConnect. Aside from allowing the plugin + to set the client ip and port for logging, the functionality of + TSHttpConnect() is identical to connecting to localhost on the + proxy port with TSNetConnect(). TSHttpConnect() is more efficient + than TSNetConnect() to localhost since it avoids the overhead of + passing the data through the operating system. + + @param log_ip ip address (in network byte order) that connection + will be logged as coming from. + @param log_port port (in network byte order) that connection will + be logged as coming from. + @param vc will be set to point to the new TSVConn on success. + + */ + tsapi TSVConn TSHttpConnect(struct sockaddr const* addr); + tsapi void TSFetchUrl(const char* headers, int request_len, unsigned int ip, int port , TSCont contp, TSFetchWakeUpOptions callback_options,TSFetchEvent events); + tsapi void TSFetchPages(TSFetchUrlParams_t* params); + + /* Check if HTTP State machine is internal or not */ + tsapi TSReturnCode TSHttpIsInternalRequest(TSHttpTxn txnp); + + /* -------------------------------------------------------------------------- + HTTP alternate selection */ + tsapi TSReturnCode TSHttpAltInfoClientReqGet(TSHttpAltInfo infop, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpAltInfoCachedReqGet(TSHttpAltInfo infop, TSMBuffer* bufp, TSMLoc* offset); + tsapi TSReturnCode TSHttpAltInfoCachedRespGet(TSHttpAltInfo infop, TSMBuffer* bufp, TSMLoc* offset); + tsapi void TSHttpAltInfoQualitySet(TSHttpAltInfo infop, float quality); + + /* -------------------------------------------------------------------------- + Actions */ + tsapi void TSActionCancel(TSAction actionp); + tsapi int TSActionDone(TSAction actionp); + + /* -------------------------------------------------------------------------- + VConnections */ + tsapi TSVIO TSVConnReadVIOGet(TSVConn connp); + tsapi TSVIO TSVConnWriteVIOGet(TSVConn connp); + tsapi int TSVConnClosedGet(TSVConn connp); + + tsapi TSVIO TSVConnRead(TSVConn connp, TSCont contp, TSIOBuffer bufp, int64_t nbytes); + tsapi TSVIO TSVConnWrite(TSVConn connp, TSCont contp, TSIOBufferReader readerp, int64_t nbytes); + tsapi void TSVConnClose(TSVConn connp); + tsapi void TSVConnAbort(TSVConn connp, int error); + tsapi void TSVConnShutdown(TSVConn connp, int read, int write); + + /* -------------------------------------------------------------------------- + Cache VConnections */ + tsapi int64_t TSVConnCacheObjectSizeGet(TSVConn connp); + + /* -------------------------------------------------------------------------- + Transformations */ + tsapi TSVConn TSTransformCreate(TSEventFunc event_funcp, TSHttpTxn txnp); + tsapi TSVConn TSTransformOutputVConnGet(TSVConn connp); + + /* -------------------------------------------------------------------------- + Net VConnections */ + /** + Returns the IP address of the remote host with which Traffic Server + is connected through the vconnection vc. + + @deprecated Use TSNetVConnRemoteAddrGet + + @param vc representing a connection that your plugin has opened + between Traffic Server and a (remote) host. + @param ip will be set to the IP address of the remote host in + network byte order. Note: this value is 32-bit, for IPv4. + + */ + tsapi TS_DEPRECATED unsigned int TSNetVConnRemoteIPGet(TSVConn vc); + + tsapi struct sockaddr const* TSNetVConnRemoteAddrGet(TSVConn vc); + + /// @deprecated Use TSNetVConnRemoteAddrGet + tsapi TS_DEPRECATED int TSNetVConnRemotePortGet(TSVConn vc); + + /** + Opens a network connection to the host specified by ip on the port + specified by port. If the connection is successfully opened, contp + is called back with the event TS_EVENT_NET_CONNECT and the new + network vconnection will be passed in the event data parameter. + If the connection is not successful, contp is called back with + the event TS_EVENT_NET_CONNECT_FAILED. + + Note: on Solaris, it is possible to receive TS_EVENT_NET_CONNECT + even if the connection failed, because of the implementation of + network sockets in the underlying operating system. There is an + exception: if a plugin tries to open a connection to a port on + its own host machine, then TS_EVENT_NET_CONNECT is sent only + if the connection is successfully opened. In general, however, + your plugin needs to look for an TS_EVENT_VCONN_WRITE_READY to + be sure that the connection is successfully opened. + + @return something allows you to check if the connection is complete, + or cancel the attempt to connect. + + */ + tsapi TSAction TSNetConnect( + TSCont contp, ///< continuation that is called back when the attempted net connection either succeeds or fails. + struct sockaddr const* to ///< Address to which to connect. + ); + + tsapi TSAction TSNetAccept(TSCont contp, int port, int domain, int accept_threads); + + /* -------------------------------------------------------------------------- + DNS Lookups */ + tsapi TSAction TSHostLookup(TSCont contp, char* hostname, int namelen); + /// @deprecated Use TSHostLookupResultAddrGet + tsapi TS_DEPRECATED unsigned int TSHostLookupResultIPGet(TSHostLookupResult lookup_result); + tsapi struct sockaddr const* TSHostLookupResultAddrGet(TSHostLookupResult lookup_result); + /// @deprecated Use TSHttpTxnServerAddrSet + tsapi TS_DEPRECATED void TSOSIpSet(TSHttpTxn txnp, unsigned int ip); + // TODO: Eventually, we might want something like this as well, but it requires + // support for building the HostDBInfo struct: + // tsapi void TSHostLookupResultSet(TSHttpTxn txnp, TSHostLookupResult result); + + /* -------------------------------------------------------------------------- + Cache VConnections */ + /** + Asks the Traffic Server cache if the object corresponding to key + exists in the cache and can be read. If the object can be read, + the Traffic Server cache calls the continuation contp back with + the event TS_EVENT_CACHE_OPEN_READ. In this case, the cache also + passes contp a cache vconnection and contp can then initiate a + read operation on that vconnection using TSVConnRead. + + If the object cannot be read, the cache calls contp back with + the event TS_EVENT_CACHE_OPEN_READ_FAILED. The user (contp) + has the option to cancel the action returned by TSCacheRead. + Note that reentrant calls are possible, i.e. the cache can call + back the user (contp) in the same call. + + @param contp continuation to be called back if a read operation + is permissible. + @param key cache key corresponding to the object to be read. + @return something allowing the user to cancel or schedule the + cache read. + + */ + tsapi TSAction TSCacheRead(TSCont contp, TSCacheKey key); + + /** + Asks the Traffic Server cache if contp can start writing the + object (corresponding to key) to the cache. If the object + can be written, the cache calls contp back with the event + TS_EVENT_CACHE_OPEN_WRITE. In this case, the cache also passes + contp a cache vconnection and contp can then initiate a write + operation on that vconnection using TSVConnWrite. The object + is not committed to the cache until the vconnection is closed. + When all data has been transferred, the user (contp) must do + an TSVConnClose. In case of any errors, the user MUST do an + TSVConnAbort(contp, 0). + + If the object cannot be written, the cache calls contp back with + the event TS_EVENT_CACHE_OPEN_WRITE_FAILED. This can happen, + for example, if there is another object with the same key being + written to the cache. The user (contp) has the option to cancel + the action returned by TSCacheWrite. + + Note that reentrant calls are possible, i.e. the cache can call + back the user (contp) in the same call. + + @param contp continuation that the cache calls back (telling it + whether the write operation can proceed or not). + @param key cache key corresponding to the object to be cached. + @return something allowing the user to cancel or schedule the + cache write. + + */ + tsapi TSAction TSCacheWrite(TSCont contp, TSCacheKey key); + + /** + Removes the object corresponding to key from the cache. If the + object was removed successfully, the cache calls contp back + with the event TS_EVENT_CACHE_REMOVE. If the object was not + found in the cache, the cache calls contp back with the event + TS_EVENT_CACHE_REMOVE_FAILED. + + In both of these callbacks, the user (contp) does not have to do + anything. The user does not get any vconnection from the cache, + since no data needs to be transferred. When the cache calls + contp back with TS_EVENT_CACHE_REMOVE, the remove has already + been commited. + + @param contp continuation that the cache calls back reporting the + success or failure of the remove. + @param key cache key corresponding to the object to be removed. + @return something allowing the user to cancel or schedule the + remove. + + */ + tsapi TSAction TSCacheRemove(TSCont contp, TSCacheKey key); + tsapi TSReturnCode TSCacheReady(int* is_ready); + tsapi TSAction TSCacheScan(TSCont contp, TSCacheKey key, int KB_per_second); + + /* -------------------------------------------------------------------------- + VIOs */ + tsapi void TSVIOReenable(TSVIO viop); + tsapi TSIOBuffer TSVIOBufferGet(TSVIO viop); + tsapi TSIOBufferReader TSVIOReaderGet(TSVIO viop); + tsapi int64_t TSVIONBytesGet(TSVIO viop); + tsapi void TSVIONBytesSet(TSVIO viop, int64_t nbytes); + tsapi int64_t TSVIONDoneGet(TSVIO viop); + tsapi void TSVIONDoneSet(TSVIO viop, int64_t ndone); + tsapi int64_t TSVIONTodoGet(TSVIO viop); + tsapi TSMutex TSVIOMutexGet(TSVIO viop); + tsapi TSCont TSVIOContGet(TSVIO viop); + tsapi TSVConn TSVIOVConnGet(TSVIO viop); + + /* -------------------------------------------------------------------------- + Buffers */ + tsapi TSIOBuffer TSIOBufferCreate(void); + + /** + Creates a new TSIOBuffer of the specified size. With this function, + you can create smaller buffers than the 32K buffer created by + TSIOBufferCreate(). In some situations using smaller buffers can + improve performance. + + @param index size of the new TSIOBuffer to be created. + @param new TSIOBuffer of the specified size. + + */ + tsapi TSIOBuffer TSIOBufferSizedCreate(TSIOBufferSizeIndex index); + + /** + The watermark of an TSIOBuffer is the minimum number of bytes + of data that have to be in the buffer before calling back any + continuation that has initiated a read operation on this buffer. + TSIOBufferWaterMarkGet() will provide the size of the watermark, + in bytes, for a specified TSIOBuffer. + + @param bufp buffer whose watermark the function gets. + + */ + tsapi int64_t TSIOBufferWaterMarkGet(TSIOBuffer bufp); + + /** + The watermark of an TSIOBuffer is the minimum number of bytes + of data that have to be in the buffer before calling back any + continuation that has initiated a read operation on this buffer. + As a writer feeds data into the TSIOBuffer, no readers are called + back until the amount of data reaches the watermark. Setting + a watermark can improve performance because it avoids frequent + callbacks to read small amounts of data. TSIOBufferWaterMarkSet() + assigns a watermark to a particular TSIOBuffer. + + @param bufp buffer whose water mark the function sets. + @param water_mark watermark setting, as a number of bytes. + + */ + tsapi void TSIOBufferWaterMarkSet(TSIOBuffer bufp, int64_t water_mark); + + tsapi void TSIOBufferDestroy(TSIOBuffer bufp); + tsapi TSIOBufferBlock TSIOBufferStart(TSIOBuffer bufp); + tsapi int64_t TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length, int64_t offset); + + /** + Writes length bytes of data contained in the string buf to the + TSIOBuffer bufp. Returns the number of bytes of data successfully + written to the TSIOBuffer. + + @param bufp is the TSIOBuffer to write into. + @param buf string to write into the TSIOBuffer. + @param length of the string buf. + @return length of data successfully copied into the buffer, + in bytes. + + */ + tsapi int64_t TSIOBufferWrite(TSIOBuffer bufp, const void* buf, int64_t length); + tsapi void TSIOBufferProduce(TSIOBuffer bufp, int64_t nbytes); + + tsapi TSIOBufferBlock TSIOBufferBlockNext(TSIOBufferBlock blockp); + tsapi const char* TSIOBufferBlockReadStart(TSIOBufferBlock blockp, TSIOBufferReader readerp, int64_t* avail); + tsapi int64_t TSIOBufferBlockReadAvail(TSIOBufferBlock blockp, TSIOBufferReader readerp); + tsapi char* TSIOBufferBlockWriteStart(TSIOBufferBlock blockp, int64_t* avail); + tsapi int64_t TSIOBufferBlockWriteAvail(TSIOBufferBlock blockp); + + tsapi TSIOBufferReader TSIOBufferReaderAlloc(TSIOBuffer bufp); + tsapi TSIOBufferReader TSIOBufferReaderClone(TSIOBufferReader readerp); + tsapi void TSIOBufferReaderFree(TSIOBufferReader readerp); + tsapi TSIOBufferBlock TSIOBufferReaderStart(TSIOBufferReader readerp); + tsapi void TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes); + tsapi int64_t TSIOBufferReaderAvail(TSIOBufferReader readerp); + + + /* -------------------------------------------------------------------------- + Stats based on librecords raw stats (this is prefered API until we rewrite + stats). This system has a limitation of up to 1,500 stats max, controlled via + proxy.config.stat_api.max_stats_allowed (default is 512). + + This is available as of Apache TS v2.2.*/ + typedef enum + { + TS_STAT_PERSISTENT = 1, + TS_STAT_NON_PERSISTENT + } TSStatPersistence; + + typedef enum + { + TS_STAT_SYNC_SUM = 0, + TS_STAT_SYNC_COUNT, + TS_STAT_SYNC_AVG, + TS_STAT_SYNC_TIMEAVG + } TSStatSync; + + /* Note that only TS_RECORDDATATYPE_INT is supported at this point. */ + tsapi int TSStatCreate(const char* the_name, TSRecordDataType the_type, TSStatPersistence persist, TSStatSync sync); + + tsapi void TSStatIntIncrement(int the_stat, TSMgmtInt amount); + tsapi void TSStatIntDecrement(int the_stat, TSMgmtInt amount); + /* Currently not supported. */ + /* tsapi void TSStatFloatIncrement(int the_stat, float amount); */ + /* tsapi void TSStatFloatDecrement(int the_stat, float amount); */ + + tsapi TSMgmtInt TSStatIntGet(int the_stat); + tsapi void TSStatIntSet(int the_stat, TSMgmtInt value); + /* Currently not supported. */ + /* tsapi TSeturnCode TSStatFloatGet(int the_stat, float* value); */ + /* tsapi TSReturnCode TSStatFloatSet(int the_stat, float value); */ + + tsapi TSReturnCode TSStatFindName(const char* name, int* idp); + + /* -------------------------------------------------------------------------- + This is the old stats system, it's deprecated, and should preferably not + be used. It has serious limitations both in scalability and performance. */ + typedef enum + { + INKSTAT_TYPE_INT64, + INKSTAT_TYPE_FLOAT + } INKStatTypes; + + typedef void* INKStat; + typedef void* INKCoupledStat; + + /* -------------------------------------------------------------------------- + uncoupled stats */ + /** @deprecated */ + tsapi INKStat INKStatCreate(const char* the_name, INKStatTypes the_type); + /** @deprecated */ + tsapi void INKStatIntAddTo(INKStat the_stat, int64_t amount); + /** @deprecated */ + tsapi void INKStatFloatAddTo(INKStat the_stat, float amount); + /** @deprecated */ + tsapi void INKStatDecrement(INKStat the_stat); + /** @deprecated */ + tsapi void INKStatIncrement(INKStat the_stat); + /** @deprecated */ + tsapi int64_t INKStatIntGet(INKStat the_stat); + /** @deprecated */ + tsapi float INKStatFloatGet(INKStat the_stat); + /** @deprecated */ + tsapi void INKStatIntSet(INKStat the_stat, int64_t value); + /** @deprecated */ + tsapi void INKStatFloatSet(INKStat the_stat, float value); + + /* -------------------------------------------------------------------------- + coupled stats */ + /** @deprecated */ + tsapi INKCoupledStat INKStatCoupledGlobalCategoryCreate(const char* the_name); + /** @deprecated */ + tsapi INKCoupledStat INKStatCoupledLocalCopyCreate(const char* the_name, INKCoupledStat global_copy); + /** @deprecated */ + tsapi void INKStatCoupledLocalCopyDestroy(INKCoupledStat local_copy); + /** @deprecated */ + tsapi INKStat INKStatCoupledGlobalAdd(INKCoupledStat global_copy, const char* the_name, INKStatTypes the_type); + /** @deprecated */ + tsapi INKStat INKStatCoupledLocalAdd(INKCoupledStat local_copy, const char* the_name, INKStatTypes the_type); + /** @deprecated */ + tsapi void INKStatsCoupledUpdate(INKCoupledStat local_copy); + + /* -------------------------------------------------------------------------- + tracing api */ + + tsapi int TSIsDebugTagSet(const char* t); + tsapi void TSDebug(const char* tag, const char* format_str, ...); + extern int diags_on_for_plugins; +#define TSDEBUG if (diags_on_for_plugins) TSDebug + + /* -------------------------------------------------------------------------- + logging api */ + + /** + The following enum values are flags, so they should be powers + of two. With the exception of TS_LOG_MODE_INVALID_FLAG, they + are all used to configure the creation of an TSTextLogObject + through the mode argument to TSTextLogObjectCreate(). + TS_LOG_MODE_INVALID_FLAG is used internally to check the validity + of this argument. Insert new flags before TS_LOG_MODE_INVALID_FLAG, + and set TS_LOG_MODE_INVALID_FLAG to the largest power of two of + the enum. + + */ + enum + { + TS_LOG_MODE_ADD_TIMESTAMP = 1, + TS_LOG_MODE_DO_NOT_RENAME = 2, + TS_LOG_MODE_INVALID_FLAG = 4 + }; + + /** + This type represents a custom log file that you create with + TSTextLogObjectCreate(). Your plugin writes entries into this + log file using TSTextLogObjectWrite(). + + */ + typedef struct tsapi_textlogobject* TSTextLogObject; + + typedef void (*TSRecordDumpCb) (TSRecordType rec_type, void* edata, int registered, const char* name, TSRecordDataType data_type, TSRecordData* datum); + + tsapi void TSRecordDump(TSRecordType rec_type, TSRecordDumpCb callback, void* edata); + + /** + + Creates a new custom log file that your plugin can write to. You + can design the fields and inputs to the log file using the + TSTextLogObjectWrite() function. The logs you create are treated + like ordinary logs; they are rolled if log rolling is enabled. (Log + collation is not supported though). + + @param filename new log file being created. The new log file + is created in the logs directory. You can specify a path to a + subdirectory within the log directory, e.g. subdir/filename, + but make sure you create the subdirectory first. If you do + not specify a file name extension, the extension ".log" is + automatically added. + @param mode is one (or both) of the following: + - TS_LOG_MODE_ADD_TIMESTAMP Whenever the plugin makes a log + entry using TSTextLogObjectWrite (see below), it prepends + the entry with a timestamp. + - TS_LOG_MODE_DO_NOT_RENAME This means that if there is a + filename conflict, Traffic Server should not attempt to rename + the custom log. The consequence of a name conflict is that the + custom log will simply not be created, e.g. suppose you call: + @code + log = TSTextLogObjectCreate("squid" , mode, NULL, &error); + @endcode + If mode is TS_LOG_MODE_DO_NOT_RENAME, you will NOT get a new + log (you'll get a null pointer) if squid.log already exists. + If mode is not TS_LOG_MODE_DO_NOT_RENAME, Traffic Server + tries to rename the log to a new name (it will try squid_1.log). + @param new_log_obj new custom log file. + @return error code: + - TS_LOG_ERROR_NO_ERROR No error; the log object has been + created successfully. + - TS_LOG_ERROR_OBJECT_CREATION Log object not created. This + error is rare and would most likely be caused by the system + running out of memory. + - TS_LOG_ERROR_FILENAME_CONFLICTS You get this error if mode = + TS_LOG_MODE_DO_NOT_RENAME, and if there is a naming conflict. + The log object is not created. + - TS_LOG_ERROR_FILE_ACCESS Log object not created because of + a file access problem (for example, no write permission to the + logging directory, or a specified subdirectory for the log file + does not exist). + + */ + tsapi TSReturnCode TSTextLogObjectCreate(const char* filename, int mode, TSTextLogObject* new_log_obj); + + /** + Writes a printf-style formatted statement to an TSTextLogObject + (a plugin custom log). + + @param the_object log object to write to. You must first create + this object with TSTextLogObjectCreate(). + @param format printf-style formatted statement to be printed. + @param ... parameters in the formatted statement. A newline is + automatically added to the end. + @return one of the following errors: + - TS_LOG_ERROR_NO_ERROR Means that the write was successful. + - TS_LOG_ERROR_LOG_SPACE_EXHAUSTED Means that Traffic Server + ran out of disk space for logs. If you see this error you might + want to roll logs more often. + - TS_LOG_ERROR_INTERNAL_ERROR Indicates some internal problem + with a log entry (such as an entry larger than the size of the + log write buffer). This error is very unusual. + + */ + tsapi TSReturnCode TSTextLogObjectWrite(TSTextLogObject the_object, char* format, ...); + + /** + This immediately flushes the contents of the log write buffer for + the_object to disk. Use this call only if you want to make sure that + log entries are flushed immediately. This call has a performance + cost. Traffic Server flushes the log buffer automatically about + every 1 second. + + @param the_object custom log file whose write buffer is to be + flushed. + + */ + tsapi void TSTextLogObjectFlush(TSTextLogObject the_object); + + /** + Destroys a log object and releases the memory allocated to it. + Use this call if you are done with the log. + + @param the_object custom log to be destroyed. + + */ + tsapi TSReturnCode TSTextLogObjectDestroy(TSTextLogObject the_object); + + /** + Set log header. + + */ + tsapi void TSTextLogObjectHeaderSet(TSTextLogObject the_object, const char* header); + + /** + Enable/disable rolling. + + */ + tsapi void TSTextLogObjectRollingEnabledSet(TSTextLogObject the_object, int rolling_enabled); + + /** + Set the rolling interval. + + */ + tsapi void TSTextLogObjectRollingIntervalSecSet(TSTextLogObject the_object, int rolling_interval_sec); + + /** + Set the rolling offset. + + */ + tsapi void TSTextLogObjectRollingOffsetHrSet(TSTextLogObject the_object, int rolling_offset_hr); + + /** + Async disk IO read + + @return TS_SUCCESS or TS_ERROR. + */ + tsapi TSReturnCode TSAIORead(int fd, off_t offset, char* buf, size_t buffSize, TSCont contp); + + /** + Async disk IO buffer get + + @return char* to the buffer + */ + tsapi char* TSAIOBufGet(TSAIOCallback data); + + /** + Async disk IO get number of bytes + + @return the number of bytes + */ + tsapi int TSAIONBytesGet(TSAIOCallback data); + + /** + Async disk IO write + + @return TS_SUCCESS or TS_ERROR. + */ + tsapi TSReturnCode TSAIOWrite(int fd, off_t offset, char* buf, size_t bufSize, TSCont contp); + + /** + Async disk IO set number of threads + + @return TS_SUCCESS or TS_ERROR. + */ + tsapi TSReturnCode TSAIOThreadNumSet(int thread_num); + + /** + Check if transaction was aborted (due client/server errors etc.) + + @return 1 if transaction was aborted + */ + tsapi TSReturnCode TSHttpTxnAborted(TSHttpTxn txnp); + + /* + The reason is even if VConn is created using this API, it is + still useless. For example, if we do TSVConnRead(), the read + operation returns read_vio. If we do TSVIOReenable(read_vio), + it actually calls: + + @code + void VIO::reenable() { + if (vc_server) vc_server->reenable(this); + } + @endcode + + vc_server->reenable calls: + + @code + VConnection::reenable(VIO); + @endcode + + This function is virtual in VConnection.h. It is defined separately for + UnixNet, NTNet and CacheVConnection. + + Thus, unless VConn is either NetVConnection or CacheVConnection, it can't + be instantiated for functions like reenable. + + In addition, this function has never been used. + + */ + tsapi TSVConn TSVConnCreate(TSEventFunc event_funcp, TSMutex mutexp); + + tsapi TS_DEPRECATED void TSIOBufferAppend(TSIOBuffer bufp, TSIOBufferBlock blockp); + tsapi TS_DEPRECATED TSIOBufferData TSIOBufferDataCreate(void* data, int size, TSIOBufferDataFlags flags); + tsapi TS_DEPRECATED TSIOBufferBlock TSIOBufferBlockCreate(TSIOBufferData datap, int size, int offset); + + + /* api functions to access stats */ + /* ClientResp APIs exist as well and are exposed in PrivateFrozen */ + tsapi int TSHttpTxnClientReqHdrBytesGet(TSHttpTxn txnp); + tsapi int64_t TSHttpTxnClientReqBodyBytesGet(TSHttpTxn txnp); + tsapi int TSHttpTxnServerReqHdrBytesGet(TSHttpTxn txnp); + tsapi int64_t TSHttpTxnServerReqBodyBytesGet(TSHttpTxn txnp); + tsapi int TSHttpTxnPushedRespHdrBytesGet(TSHttpTxn txnp); + tsapi int64_t TSHttpTxnPushedRespBodyBytesGet(TSHttpTxn txnp); + tsapi int TSHttpTxnServerRespHdrBytesGet(TSHttpTxn txnp); + tsapi int64_t TSHttpTxnServerRespBodyBytesGet(TSHttpTxn txnp); + tsapi int TSHttpTxnClientRespHdrBytesGet(TSHttpTxn txnp); + tsapi int64_t TSHttpTxnClientRespBodyBytesGet(TSHttpTxn txnp); + + /* NetVC timeout APIs. */ + tsapi void TSVConnInactivityTimeoutSet(TSVConn connp, TSHRTime timeout); + tsapi void TSVConnInactivityTimeoutCancel(TSVConn connp); + tsapi void TSVConnActiveTimeoutSet(TSVConn connp, TSHRTime timeout); + tsapi void TSVConnActiveTimeoutCancel(TSVConn connp); + + /* + ability to skip the remap phase of the State Machine + this only really makes sense in TS_HTTP_READ_REQUEST_HDR_HOOK + */ + tsapi void TSSkipRemappingSet(TSHttpTxn txnp, int flag); + + + /* + Set or get various overridable configurations, for a transaction. This should + probably be done as early as possible, e.g. TS_HTTP_READ_REQUEST_HDR_HOOK. + */ + tsapi TSReturnCode TSHttpTxnConfigIntSet(TSHttpTxn txnp, TSOverridableConfigKey conf, TSMgmtInt value); + tsapi TSReturnCode TSHttpTxnConfigIntGet(TSHttpTxn txnp, TSOverridableConfigKey conf, TSMgmtInt* value); + tsapi TSReturnCode TSHttpTxnConfigFloatSet(TSHttpTxn txnp, TSOverridableConfigKey conf, TSMgmtFloat value); + tsapi TSReturnCode TSHttpTxnConfigFloatGet(TSHttpTxn txnp, TSOverridableConfigKey conf, TSMgmtFloat* value); + tsapi TSReturnCode TSHttpTxnConfigStringSet(TSHttpTxn txnp, TSOverridableConfigKey conf, const char* value, int length); + tsapi TSReturnCode TSHttpTxnConfigStringGet(TSHttpTxn txnp, TSOverridableConfigKey conf, const char** value, int* length); + + tsapi TSReturnCode TSHttpTxnConfigFind(const char* name, int length, TSOverridableConfigKey* conf, TSRecordDataType* type); + + /* + It's unclear if these actually function properly still. + */ + tsapi void TSRedirectUrlSet(TSHttpTxn txnp, const char* url, const int url_len); + tsapi const char* TSRedirectUrlGet(TSHttpTxn txnp, int* url_len_ptr); + + /* Get current HTTP connection stats */ + tsapi int TSHttpCurrentClientConnectionsGet(void); + tsapi int TSHttpCurrentActiveClientConnectionsGet(void); + tsapi int TSHttpCurrentIdleClientConnectionsGet(void); + tsapi int TSHttpCurrentCacheConnectionsGet(void); + tsapi int TSHttpCurrentServerConnectionsGet(void); + + /* ===== Http Transactions ===== */ + tsapi TSReturnCode TSHttpTxnCachedRespModifiableGet(TSHttpTxn txnp, TSMBuffer *bufp, TSMLoc *offset); + tsapi TSReturnCode TSHttpTxnCacheLookupStatusSet(TSHttpTxn txnp, int cachelookup); + tsapi TSReturnCode TSHttpTxnCacheLookupUrlGet(TSHttpTxn txnp, TSMBuffer bufp, TSMLoc obj); + tsapi TSReturnCode TSHttpTxnCachedUrlSet(TSHttpTxn txnp, TSMBuffer bufp, TSMLoc obj); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TS_API_H__ */ + diff --git a/proxy/config/Makefile.am b/proxy/config/Makefile.am new file mode 100644 index 00000000..3e8e525c --- /dev/null +++ b/proxy/config/Makefile.am @@ -0,0 +1,57 @@ +# Makefile.am for config +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = body_factory +EXTRA_DIST = \ + records.config.default.in \ + storage.config.default.in + +sysconfdir = $(pkgsysconfdir) +nodist_sysconf_DATA = \ + records.config.default \ + storage.config.default + +dist_sysconf_DATA = \ + ae_ua.config.default \ + cache.config.default \ + cluster.config.default \ + congestion.config.default \ + hosting.config.default \ + icp.config.default \ + ip_allow.config.default \ + log_hosts.config.default \ + logs_xml.config.default \ + mgr.cnf.default \ + parent.config.default \ + volume.config.default \ + plugin.config.default \ + plugin.db.default \ + remap.config.default \ + socks.config.default \ + splitdns.config.default \ + ssl_multicert.config.default \ + stats.config.xml.default \ + update.config.default \ + vaddrs.config.default + +install-exec-hook: + for dfltcfgfile in $(dist_sysconf_DATA) $(nodist_sysconf_DATA) ; \ + do \ + cfgfile=`echo $$dfltcfgfile | sed 's/\.default$$//'` ; \ + test -f $(DESTDIR)/$(sysconfdir)/$$cfgfile || mv $(DESTDIR)/$(sysconfdir)/$$dfltcfgfile $(DESTDIR)/$(sysconfdir)/$$cfgfile ; \ + done diff --git a/proxy/config/Makefile.in b/proxy/config/Makefile.in new file mode 100644 index 00000000..3bbcda85 --- /dev/null +++ b/proxy/config/Makefile.in @@ -0,0 +1,885 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for config +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = proxy/config +DIST_COMMON = $(dist_sysconf_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/records.config.default.in \ + $(srcdir)/storage.config.default.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = records.config.default storage.config.default +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(sysconfdir)" +DATA = $(dist_sysconf_DATA) $(nodist_sysconf_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = $(pkgsysconfdir) +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +SUBDIRS = body_factory +EXTRA_DIST = \ + records.config.default.in \ + storage.config.default.in + +nodist_sysconf_DATA = \ + records.config.default \ + storage.config.default + +dist_sysconf_DATA = \ + ae_ua.config.default \ + cache.config.default \ + cluster.config.default \ + congestion.config.default \ + hosting.config.default \ + icp.config.default \ + ip_allow.config.default \ + log_hosts.config.default \ + logs_xml.config.default \ + mgr.cnf.default \ + parent.config.default \ + volume.config.default \ + plugin.config.default \ + plugin.db.default \ + remap.config.default \ + socks.config.default \ + splitdns.config.default \ + ssl_multicert.config.default \ + stats.config.xml.default \ + update.config.default \ + vaddrs.config.default + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign proxy/config/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign proxy/config/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +records.config.default: $(top_builddir)/config.status $(srcdir)/records.config.default.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +storage.config.default: $(top_builddir)/config.status $(srcdir)/storage.config.default.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_sysconfDATA: $(dist_sysconf_DATA) + @$(NORMAL_INSTALL) + test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" + @list='$(dist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ + done + +uninstall-dist_sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sysconfdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sysconfdir)" && rm -f $$files +install-nodist_sysconfDATA: $(nodist_sysconf_DATA) + @$(NORMAL_INSTALL) + test -z "$(sysconfdir)" || $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" + @list='$(nodist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \ + done + +uninstall-nodist_sysconfDATA: + @$(NORMAL_UNINSTALL) + @list='$(nodist_sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sysconfdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sysconfdir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(sysconfdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-dist_sysconfDATA install-nodist_sysconfDATA + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-dist_sysconfDATA uninstall-nodist_sysconfDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-exec-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dist_sysconfDATA install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-info install-info-am \ + install-man install-nodist_sysconfDATA install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am \ + uninstall-dist_sysconfDATA uninstall-nodist_sysconfDATA + + +install-exec-hook: + for dfltcfgfile in $(dist_sysconf_DATA) $(nodist_sysconf_DATA) ; \ + do \ + cfgfile=`echo $$dfltcfgfile | sed 's/\.default$$//'` ; \ + test -f $(DESTDIR)/$(sysconfdir)/$$cfgfile || mv $(DESTDIR)/$(sysconfdir)/$$dfltcfgfile $(DESTDIR)/$(sysconfdir)/$$cfgfile ; \ + done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/proxy/config/ae_ua.config.default b/proxy/config/ae_ua.config.default new file mode 100644 index 00000000..6280f9f3 --- /dev/null +++ b/proxy/config/ae_ua.config.default @@ -0,0 +1,23 @@ +# --------------------------------------------------------------------------------------- +# Accept-Encoding/User-Agent filtering Configuration file. +# This file can include an unlimited number of regular expressions or simple strings for +# User-Agents headers filtering. +# If the request User-Agent header matches the regular expression, Accep-Encoding header +# will be verified/changed/removed in order to disable the acceptance of any compressed data. +# Please keep in mind that Traffic Server has some predefined regular expressions +# for well-known "bad" clients. +# Traffic Server supports the following format for this file: +# +# where can be: +# .substring - check only lead substring in User-Agent header (case sensitive) +# .string - the same as .substring +# .substring_ncase - check only lead substring in User-Agent header (case insensitive) +# .string_ncase - the same as .substring_ncase +# .regexp - POSIX regular expression +# +# - valid POSIX regular expression if ".regexp" string type was specified +# or arbitrary ascii string for other string types +# --------------------------------------------------------------------------------------- +# For example: +# .regexp Mozilla/4.[0-9].* +# .string Mozilla/4.0 diff --git a/proxy/config/body_factory/Makefile.am b/proxy/config/body_factory/Makefile.am new file mode 100644 index 00000000..4101fb6c --- /dev/null +++ b/proxy/config/body_factory/Makefile.am @@ -0,0 +1,20 @@ +# +# Makefile.am for config/body_factory. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SUBDIRS = default diff --git a/proxy/config/body_factory/Makefile.in b/proxy/config/body_factory/Makefile.in new file mode 100644 index 00000000..09bb4468 --- /dev/null +++ b/proxy/config/body_factory/Makefile.in @@ -0,0 +1,772 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Makefile.am for config/body_factory. +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = proxy/config/body_factory +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +SUBDIRS = default +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign proxy/config/body_factory/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign proxy/config/body_factory/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/proxy/config/body_factory/default/.body_factory_info b/proxy/config/body_factory/default/.body_factory_info new file mode 100644 index 00000000..a8a651e0 --- /dev/null +++ b/proxy/config/body_factory/default/.body_factory_info @@ -0,0 +1,16 @@ +# .body_factory_info +# +# The .body_factory_info file contains descriptive information +# about the error pages in this directory. +# +# Currently, .body_factory_info contains information which +# indicates the character set and natural language of the error +# pages in this directory. For example, to describe Korean +# web pages encoded in the iso-2022-kr character set, you might +# add these lines to .body_factory_info file: +# +# Content-Language: kr +# Content-Charset: iso-2022-kr +# +# If this file is empty, or only contains comments, the default is +# assumed: English text in the standard iso-8859-1 character set. diff --git a/proxy/config/body_factory/default/Makefile.am b/proxy/config/body_factory/default/Makefile.am new file mode 100644 index 00000000..0e9e6f35 --- /dev/null +++ b/proxy/config/body_factory/default/Makefile.am @@ -0,0 +1,48 @@ +# Makefile.am for config/body_factory/default +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +bodyfactorydir = $(pkgsysconfdir)/body_factory/default + +dist_bodyfactory_DATA = \ + access\#denied \ + access\#proxy_auth_required \ + access\#redirect_url \ + access\#ssl_forbidden \ + .body_factory_info \ + cache\#not_in_cache \ + cache\#read_error \ + congestion\#retryAfter \ + connect\#dns_failed \ + connect\#failed_connect \ + connect\#hangup \ + default \ + interception\#no_host \ + README \ + redirect\#moved_temporarily \ + request\#cycle_detected \ + request\#no_content_length \ + request\#no_host \ + request\#scheme_unsupported \ + request\#syntax_error \ + response\#bad_response \ + response\#bad_version \ + timeout\#activity \ + timeout\#inactivity \ + transcoding\#unsupported \ + urlrouting\#no_mapping + diff --git a/proxy/config/body_factory/default/Makefile.in b/proxy/config/body_factory/default/Makefile.in new file mode 100644 index 00000000..f753c414 --- /dev/null +++ b/proxy/config/body_factory/default/Makefile.in @@ -0,0 +1,646 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am for config/body_factory/default +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +VPATH = @srcdir@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = proxy/config/body_factory/default +DIST_COMMON = README $(dist_bodyfactory_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/common.m4 \ + $(top_srcdir)/build/crypto.m4 $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/build/lzma.m4 \ + $(top_srcdir)/build/network.m4 $(top_srcdir)/build/pcre.m4 \ + $(top_srcdir)/build/tcl.m4 $(top_srcdir)/build/xml.m4 \ + $(top_srcdir)/build/zlib.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/lib/ts/ink_autoconf.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(bodyfactorydir)" +DATA = $(dist_bodyfactory_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkgdatadir = @pkgdatadir@ +pkglibdir = @pkglibdir@ +pkglibexecdir = @pkglibexecdir@ +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +API_DEFS = @API_DEFS@ +AR = @AR@ +ASCPP = @ASCPP@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCACHE = @CCACHE@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPAT_LDFLAGS = @EXPAT_LDFLAGS@ +EXTRA_CC_LDFLAGS = @EXTRA_CC_LDFLAGS@ +EXTRA_CXX_LDFLAGS = @EXTRA_CXX_LDFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +HOST_GUESS = @HOST_GUESS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IOCORE_MODULARIZED_DEFS = @IOCORE_MODULARIZED_DEFS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBDEMANGLE = @LIBDEMANGLE@ +LIBDL = @LIBDL@ +LIBEV = @LIBEV@ +LIBEXC = @LIBEXC@ +LIBEXECINFO = @LIBEXECINFO@ +LIBEXPAT = @LIBEXPAT@ +LIBICONV = @LIBICONV@ +LIBMLD = @LIBMLD@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPCRE = @LIBPCRE@ +LIBPROFILER = @LIBPROFILER@ +LIBRESOLV = @LIBRESOLV@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSSL = @LIBSSL@ +LIBTCL = @LIBTCL@ +LIBTHREAD = @LIBTHREAD@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LINK_FLAGS = @LIBTOOL_LINK_FLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MGMT_DEFS = @MGMT_DEFS@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHARED_CFLAGS = @SHARED_CFLAGS@ +SHARED_CXXFLAGS = @SHARED_CXXFLAGS@ +SHARED_CXXLINKFLAGS = @SHARED_CXXLINKFLAGS@ +SHARED_LDFLAGS = @SHARED_LDFLAGS@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TCL_BIN_DIR = @TCL_BIN_DIR@ +TCL_LIB_FILE = @TCL_LIB_FILE@ +TCL_LIB_FLAG = @TCL_LIB_FLAG@ +TCL_LIB_SPEC = @TCL_LIB_SPEC@ +TCL_PATCH_LEVEL = @TCL_PATCH_LEVEL@ +TCL_SRC_DIR = @TCL_SRC_DIR@ +TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@ +TCL_STUB_LIB_FLAG = @TCL_STUB_LIB_FLAG@ +TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@ +TCL_VERSION = @TCL_VERSION@ +TFW_PACKAGE_SUFFIX = @TFW_PACKAGE_SUFFIX@ +TS_LIBTOOL_VERSION = @TS_LIBTOOL_VERSION@ +TS_VERSION_MAJOR = @TS_VERSION_MAJOR@ +TS_VERSION_MICRO = @TS_VERSION_MICRO@ +TS_VERSION_MINOR = @TS_VERSION_MINOR@ +TS_VERSION_NUMBER = @TS_VERSION_NUMBER@ +TS_VERSION_STRING = @TS_VERSION_STRING@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_cv_sizeof_voidp = @ac_cv_sizeof_voidp@ +allocah = @allocah@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +arpa_ineth = @arpa_ineth@ +arpa_nameser_compath = @arpa_nameser_compath@ +arpa_nameserh = @arpa_nameserh@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_group = @build_group@ +build_machine = @build_machine@ +build_os = @build_os@ +build_person = @build_person@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cachedir = @cachedir@ +cpioh = @cpioh@ +ctypeh = @ctypeh@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_loopback_iface = @default_loopback_iface@ +defer_accept = @defer_accept@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_remote_cov_commit = @enable_remote_cov_commit@ +endianh = @endianh@ +exec_prefix = @exec_prefix@ +execinfoh = @execinfoh@ +exp_bindir = @exp_bindir@ +exp_cachedir = @exp_cachedir@ +exp_datadir = @exp_datadir@ +exp_exec_prefix = @exp_exec_prefix@ +exp_includedir = @exp_includedir@ +exp_infodir = @exp_infodir@ +exp_installbuilddir = @exp_installbuilddir@ +exp_libdir = @exp_libdir@ +exp_libexecdir = @exp_libexecdir@ +exp_localstatedir = @exp_localstatedir@ +exp_logdir = @exp_logdir@ +exp_mandir = @exp_mandir@ +exp_prefix = @exp_prefix@ +exp_runtimedir = @exp_runtimedir@ +exp_sbindir = @exp_sbindir@ +exp_sysconfdir = @exp_sysconfdir@ +expath = @expath@ +floath = @floath@ +gethostbyname_r_glibc2 = @gethostbyname_r_glibc2@ +gethostbyname_r_hostent_data = @gethostbyname_r_hostent_data@ +has_backtrace = @has_backtrace@ +has_clock_gettime = @has_clock_gettime@ +has_demangle = @has_demangle@ +has_eventfd = @has_eventfd@ +has_inkapi = @has_inkapi@ +has_lrand48_r = @has_lrand48_r@ +has_posix_fadvise = @has_posix_fadvise@ +has_posix_memalign = @has_posix_memalign@ +has_profiler = @has_profiler@ +has_purify = @has_purify@ +has_srand48_r = @has_srand48_r@ +has_standalone_iocore = @has_standalone_iocore@ +has_strlcat = @has_strlcat@ +has_strlcpy = @has_strlcpy@ +has_strndup = @has_strndup@ +has_tests = @has_tests@ +has_wccp = @has_wccp@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +ink_with_modules_def = @ink_with_modules_def@ +ink_with_modules_local = @ink_with_modules_local@ +ink_with_modules_process = @ink_with_modules_process@ +install_sh = @install_sh@ +installbuilddir = @installbuilddir@ +iocore_include_dirs = @iocore_include_dirs@ +ip_transparent = @ip_transparent@ +is_micro_build = @is_micro_build@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libgenh = @libgenh@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +lzmah = @lzmah@ +machine_endianh = @machine_endianh@ +malloch = @malloch@ +mandir = @mandir@ +mathh = @mathh@ +max_api_stats = @max_api_stats@ +mkdir_p = @mkdir_p@ +need_union_semun = @need_union_semun@ +net_ppp_defsh = @net_ppp_defsh@ +netdbh = @netdbh@ +netinet_in_systmh = @netinet_in_systmh@ +netinet_inh = @netinet_inh@ +netinet_ip_icmph = @netinet_ip_icmph@ +netinet_iph = @netinet_iph@ +netinet_tcph = @netinet_tcph@ +oldincludedir = @oldincludedir@ +pcre_pcreh = @pcre_pcreh@ +pcreh = @pcreh@ +pdfdir = @pdfdir@ +pkgbindir = @pkgbindir@ +pkgcachedir = @pkgcachedir@ +pkglocalstatedir = @pkglocalstatedir@ +pkglogdir = @pkglogdir@ +pkgruntimedir = @pkgruntimedir@ +pkgsbindir = @pkgsbindir@ +pkgsysconfdir = @pkgsysconfdir@ +pkgsysgroup = @pkgsysgroup@ +pkgsysuser = @pkgsysuser@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rel_bindir = @rel_bindir@ +rel_cachedir = @rel_cachedir@ +rel_datadir = @rel_datadir@ +rel_exec_prefix = @rel_exec_prefix@ +rel_includedir = @rel_includedir@ +rel_infodir = @rel_infodir@ +rel_installbuilddir = @rel_installbuilddir@ +rel_libdir = @rel_libdir@ +rel_libexecdir = @rel_libexecdir@ +rel_localstatedir = @rel_localstatedir@ +rel_logdir = @rel_logdir@ +rel_mandir = @rel_mandir@ +rel_prefix = @rel_prefix@ +rel_runtimedir = @rel_runtimedir@ +rel_sbindir = @rel_sbindir@ +rel_sysconfdir = @rel_sysconfdir@ +runtimedir = @runtimedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +siginfoh = @siginfoh@ +srcdir = @srcdir@ +stroptsh = @stroptsh@ +sys_byteorderh = @sys_byteorderh@ +sys_epollh = @sys_epollh@ +sys_eventh = @sys_eventh@ +sys_ioctlh = @sys_ioctlh@ +sys_mounth = @sys_mounth@ +sys_paramh = @sys_paramh@ +sys_sockioh = @sys_sockioh@ +sys_sysctlh = @sys_sysctlh@ +sys_sysinfoh = @sys_sysinfoh@ +sys_sysmacrosh = @sys_sysmacrosh@ +sys_systeminfoh = @sys_systeminfoh@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +use_diags = @use_diags@ +use_epoll = @use_epoll@ +use_fast_sdk = @use_fast_sdk@ +use_kqueue = @use_kqueue@ +use_libev = @use_libev@ +use_port = @use_port@ +use_posix_cap = @use_posix_cap@ +use_tproxy = @use_tproxy@ +valuesh = @valuesh@ +waith = @waith@ +zlibh = @zlibh@ +bodyfactorydir = $(pkgsysconfdir)/body_factory/default +dist_bodyfactory_DATA = \ + access\#denied \ + access\#proxy_auth_required \ + access\#redirect_url \ + access\#ssl_forbidden \ + .body_factory_info \ + cache\#not_in_cache \ + cache\#read_error \ + congestion\#retryAfter \ + connect\#dns_failed \ + connect\#failed_connect \ + connect\#hangup \ + default \ + interception\#no_host \ + README \ + redirect\#moved_temporarily \ + request\#cycle_detected \ + request\#no_content_length \ + request\#no_host \ + request\#scheme_unsupported \ + request\#syntax_error \ + response\#bad_response \ + response\#bad_version \ + timeout\#activity \ + timeout\#inactivity \ + transcoding\#unsupported \ + urlrouting\#no_mapping + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign proxy/config/body_factory/default/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign proxy/config/body_factory/default/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dist_bodyfactoryDATA: $(dist_bodyfactory_DATA) + @$(NORMAL_INSTALL) + test -z "$(bodyfactorydir)" || $(MKDIR_P) "$(DESTDIR)$(bodyfactorydir)" + @list='$(dist_bodyfactory_DATA)'; test -n "$(bodyfactorydir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(bodyfactorydir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(bodyfactorydir)" || exit $$?; \ + done + +uninstall-dist_bodyfactoryDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_bodyfactory_DATA)'; test -n "$(bodyfactorydir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bodyfactorydir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bodyfactorydir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bodyfactorydir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dist_bodyfactoryDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_bodyfactoryDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dist_bodyfactoryDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am uninstall uninstall-am uninstall-dist_bodyfactoryDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/proxy/config/body_factory/default/README b/proxy/config/body_factory/default/README new file mode 100644 index 00000000..3c6e1e29 --- /dev/null +++ b/proxy/config/body_factory/default/README @@ -0,0 +1,17 @@ +This directory contains customizable error page templates for the +Apache Traffic Server. + +You can edit the files in this directory to customized HTML error +response pages. The HTML bodies can include ATS logging format +fields, which will be replaced by the current values before the pages +are served to the user. + +You can also include sets of directories, each in a different language, +for serving multi-lingual error pages. + +Each directory of error pages include a .body_factory_info file, which +contains optional information about the language and character set of +the error page contents. + +See the Traffic Server Administrator's Guide and Release Notes for more +information. diff --git a/proxy/config/body_factory/default/access#denied b/proxy/config/body_factory/default/access#denied new file mode 100644 index 00000000..1207ea98 --- /dev/null +++ b/proxy/config/body_factory/default/access#denied @@ -0,0 +1,14 @@ + + +Access Denied + + + +

    Access Denied

    +
    + + +Description: You are not allowed to access the document you requested. + +
    + diff --git a/proxy/config/body_factory/default/access#proxy_auth_required b/proxy/config/body_factory/default/access#proxy_auth_required new file mode 100644 index 00000000..c365d4ff --- /dev/null +++ b/proxy/config/body_factory/default/access#proxy_auth_required @@ -0,0 +1,14 @@ + + +Proxy Authentication Required + + + +

    Proxy Authentication Required

    +
    + + +Description: Please login with username and password. + +
    + diff --git a/proxy/config/body_factory/default/access#redirect_url b/proxy/config/body_factory/default/access#redirect_url new file mode 100644 index 00000000..429fe935 --- /dev/null +++ b/proxy/config/body_factory/default/access#redirect_url @@ -0,0 +1,15 @@ + + + Authentication Failed + + + + +

    Authentication Failed.

    +
    + + Please wait while u r redirected to another page. + If your browser fails to redirect, click on this
    link. + + + diff --git a/proxy/config/body_factory/default/access#ssl_forbidden b/proxy/config/body_factory/default/access#ssl_forbidden new file mode 100644 index 00000000..44bda2ec --- /dev/null +++ b/proxy/config/body_factory/default/access#ssl_forbidden @@ -0,0 +1,15 @@ + + +SSL Port Forbidden + + + +

    SSL Port Forbidden

    +
    + + +Description: You have made a request for a secure SSL connection to a +forbidden port number. + +
    + diff --git a/proxy/config/body_factory/default/cache#not_in_cache b/proxy/config/body_factory/default/cache#not_in_cache new file mode 100644 index 00000000..000f346c --- /dev/null +++ b/proxy/config/body_factory/default/cache#not_in_cache @@ -0,0 +1,16 @@ + + +Not In Cache + + + +

    Not In Cache

    +
    + + +Description: Your request mandated that the document come from cache, but +the document is not present in cache. As requested, the transaction +is being terminated. + +
    + diff --git a/proxy/config/body_factory/default/cache#read_error b/proxy/config/body_factory/default/cache#read_error new file mode 100644 index 00000000..cc2ae19b --- /dev/null +++ b/proxy/config/body_factory/default/cache#read_error @@ -0,0 +1,14 @@ + + +Temporary Error + + + +

    Temporary Error

    +
    + + +Description: Temporary error. Please try again later. + +
    + diff --git a/proxy/config/body_factory/default/congestion#retryAfter b/proxy/config/body_factory/default/congestion#retryAfter new file mode 100644 index 00000000..fd74a410 --- /dev/null +++ b/proxy/config/body_factory/default/congestion#retryAfter @@ -0,0 +1,15 @@ + + +Service Unavailable + + + +

    Service Unavailable

    +
    + + +Description: Service Unavailable
    +Retry After: % seconds +
    +
    + diff --git a/proxy/config/body_factory/default/connect#dns_failed b/proxy/config/body_factory/default/connect#dns_failed new file mode 100644 index 00000000..c2f32569 --- /dev/null +++ b/proxy/config/body_factory/default/connect#dns_failed @@ -0,0 +1,17 @@ + + +Unknown Host + + + +

    Unknown Host

    +
    + + +Description: Unable to locate the server named "%" --- +the server does not have a DNS entry. Perhaps there is a misspelling +in the server name, or the server no longer exists. Double-check the +name and try again. + +
    + diff --git a/proxy/config/body_factory/default/connect#failed_connect b/proxy/config/body_factory/default/connect#failed_connect new file mode 100644 index 00000000..e7cd3a9f --- /dev/null +++ b/proxy/config/body_factory/default/connect#failed_connect @@ -0,0 +1,14 @@ + + +Could Not Connect + + + +

    Could Not Connect

    +
    + + +Description: Could not connect to the server "%". + +
    + diff --git a/proxy/config/body_factory/default/connect#hangup b/proxy/config/body_factory/default/connect#hangup new file mode 100644 index 00000000..06dde2a6 --- /dev/null +++ b/proxy/config/body_factory/default/connect#hangup @@ -0,0 +1,15 @@ + + +Server Connection Closed + + + +

    Server Connection Closed

    +
    + + +Description: The server "%" closed the connection before +the transaction was completed. + +
    + diff --git a/proxy/config/body_factory/default/default b/proxy/config/body_factory/default/default new file mode 100644 index 00000000..0b5cd01c --- /dev/null +++ b/proxy/config/body_factory/default/default @@ -0,0 +1,14 @@ + + +Error + + + +

    Error

    +
    + + +Description: Could not process this "%" request. + +
    + diff --git a/proxy/config/body_factory/default/interception#no_host b/proxy/config/body_factory/default/interception#no_host new file mode 100644 index 00000000..18d29dc4 --- /dev/null +++ b/proxy/config/body_factory/default/interception#no_host @@ -0,0 +1,17 @@ + + +Host Header Required + + + +

    Host Header Required

    +
    + + +Description: An attempt was made to transparently proxy your request, +but this attempt failed because your browser did not send an HTTP "Host" +header. To access this web site correctly, you will need to upgrade to +a browser that supports the HTTP "Host" header field. + +
    + diff --git a/proxy/config/body_factory/default/redirect#moved_temporarily b/proxy/config/body_factory/default/redirect#moved_temporarily new file mode 100644 index 00000000..a5c50369 --- /dev/null +++ b/proxy/config/body_factory/default/redirect#moved_temporarily @@ -0,0 +1,14 @@ + + +Document Has Moved + + + +

    Document Has Moved

    +
    + + +Description: The document you requested has moved to a new location. The new location is "%<{Location}psh>". + +
    + diff --git a/proxy/config/body_factory/default/request#cycle_detected b/proxy/config/body_factory/default/request#cycle_detected new file mode 100644 index 00000000..0cc7c59c --- /dev/null +++ b/proxy/config/body_factory/default/request#cycle_detected @@ -0,0 +1,16 @@ + + +Cycle Prohibited + + + +

    Cycle Prohibited

    +
    + + +Description: Could not process your request for the document +because it would cause an HTTP proxy cycle. Please check the URL and your +browser's proxy settings. + +
    + diff --git a/proxy/config/body_factory/default/request#no_content_length b/proxy/config/body_factory/default/request#no_content_length new file mode 100644 index 00000000..b4ae0af1 --- /dev/null +++ b/proxy/config/body_factory/default/request#no_content_length @@ -0,0 +1,15 @@ + + +No Content Length + + + +

    No Content Length

    +
    + + +Description: Could not process this "%" request because +there was no Content-Length specified. + +
    + diff --git a/proxy/config/body_factory/default/request#no_host b/proxy/config/body_factory/default/request#no_host new file mode 100644 index 00000000..c827a1f1 --- /dev/null +++ b/proxy/config/body_factory/default/request#no_host @@ -0,0 +1,17 @@ + + +Host Header Required + + + +

    Host Header Required

    +
    + + +Description: Your browser did not send a "Host" HTTP header field +and therefore the virtual host being requested could not be determined. +To access this web site correctly, you will need to upgrade to a browser +that supports the HTTP "Host" header field. + +
    + diff --git a/proxy/config/body_factory/default/request#scheme_unsupported b/proxy/config/body_factory/default/request#scheme_unsupported new file mode 100644 index 00000000..d66f2276 --- /dev/null +++ b/proxy/config/body_factory/default/request#scheme_unsupported @@ -0,0 +1,15 @@ + + +Unsupported Protocol + + + +

    Unsupported Protocol

    +
    + + +Description: Can't perform your request for the document because +the protocol scheme is unknown. + +
    + diff --git a/proxy/config/body_factory/default/request#syntax_error b/proxy/config/body_factory/default/request#syntax_error new file mode 100644 index 00000000..4297fa90 --- /dev/null +++ b/proxy/config/body_factory/default/request#syntax_error @@ -0,0 +1,14 @@ + + +Bad Request + + + +

    Bad Request

    +
    + + +Description: Could not process this "%" request. + +
    + diff --git a/proxy/config/body_factory/default/response#bad_response b/proxy/config/body_factory/default/response#bad_response new file mode 100644 index 00000000..de8dbeef --- /dev/null +++ b/proxy/config/body_factory/default/response#bad_response @@ -0,0 +1,14 @@ + + +Web Server Error + + + +

    Web Server Error

    +
    + + +Description: The host "%" did not return the document correctly. + +
    + diff --git a/proxy/config/body_factory/default/response#bad_version b/proxy/config/body_factory/default/response#bad_version new file mode 100644 index 00000000..64c7e68d --- /dev/null +++ b/proxy/config/body_factory/default/response#bad_version @@ -0,0 +1,15 @@ + + +HTTP Version Not Supported + + + +

    HTTP Version Not Supported

    +
    + + +Description: The web server "%" is using an unsupported +version of the HTTP protocol. + +
    + diff --git a/proxy/config/body_factory/default/timeout#activity b/proxy/config/body_factory/default/timeout#activity new file mode 100644 index 00000000..0d3eabea --- /dev/null +++ b/proxy/config/body_factory/default/timeout#activity @@ -0,0 +1,14 @@ + + +Activity Timeout + + + +

    Activity Timeout

    +
    + + +Description: Too much time has passed transmitting document. + +
    + diff --git a/proxy/config/body_factory/default/timeout#inactivity b/proxy/config/body_factory/default/timeout#inactivity new file mode 100644 index 00000000..0ac28da7 --- /dev/null +++ b/proxy/config/body_factory/default/timeout#inactivity @@ -0,0 +1,14 @@ + + +Inactivity Timeout + + + +

    Inactivity Timeout

    +
    + + +Description: Too much time has passed without sending any data for document. + +
    + diff --git a/proxy/config/body_factory/default/transcoding#unsupported b/proxy/config/body_factory/default/transcoding#unsupported new file mode 100644 index 00000000..941c819f --- /dev/null +++ b/proxy/config/body_factory/default/transcoding#unsupported @@ -0,0 +1,16 @@ + + +Transcoding Not Available + + + +

    Transcoding Not Available

    +
    + + + + Description: Unable to provide the document in the +format requested by your browser. + +
    + diff --git a/proxy/config/body_factory/default/urlrouting#no_mapping b/proxy/config/body_factory/default/urlrouting#no_mapping new file mode 100644 index 00000000..1405fe71 --- /dev/null +++ b/proxy/config/body_factory/default/urlrouting#no_mapping @@ -0,0 +1,15 @@ + + +Not Found on Accelerator + + + +

    Not Found on Accelerator

    +
    + + +Description: Your request on host "%" was not found. +Check the location and try again. + +
    + diff --git a/proxy/config/cache.config.default b/proxy/config/cache.config.default new file mode 100644 index 00000000..52c0684d --- /dev/null +++ b/proxy/config/cache.config.default @@ -0,0 +1,45 @@ +# +# cache.config +# +# The purpose of this file is to alter caching parameters of +# specific objects or sets of objects +# +# Each line consists of a set of tag value pairs. The pairs +# are in the format = +# +# Each line must include exactly one primary specifier +# +# Primary destination specifiers are +# dest_domain= +# dest_host= +# dest_ip= +# url_regex= +# +# +# Lines may include any number of the secondary specifiers but +# secondary specifiers may not be duplicated on the same line +# +# Secondary specifiers are +# port= +# scheme= +# prefix= +# suffix= +# method= +# time= +# src_ip= +# +# Each line must include exactly one cache directive +# Cache directives are +# action=never-cache +# action=ignore-no-cache (client & server no cache) +# action=ignore-client-no-cache (only client no cache) +# action=ignore-server-no-cache (only server no cache) +# pin-in-cache=